GTK4: activate-link

先日書いた GtkLabel のマークアップで a href ですけど。
GTK4 ではクリックすると activate-link シグナルが発生するようだ。
確認ダイアログを出して振り分けなんかができますね。
ということで書いてみたんですけど。

#!/usr/bin/env python3

import gi, sys
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GLib, Gio

class TestWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        try:
            Gtk.ApplicationWindow.__init__(self,
                application=app,
                default_width=300,
                default_height=300)
            label = Gtk.Label(
                label = '<a href="trash:///">Open the Trash</a>',
                use_markup = True)
            label.connect('activate-link', self.on_label_activate_link)
            self.set_child(label)
        except Exception as e:
            print(e, file=sys.stderr)
            app.quit()

    def on_label_activate_link(self, label, uri):
        msg = Gtk.MessageDialog(
            buttons = Gtk.ButtonsType.YES_NO,
            modal = True,
            transient_for = self,
            text = 'Do you want to open the trash can?')
        msg.connect('response', self.on_label_message_response, uri)
        msg.show()
        # Stop the Open Link
        return True

    def on_label_message_response(self, dialog, response_id, uri):
        if response_id == Gtk.ResponseType.YES:
            GLib.spawn_command_line_async(f'gio open {uri}')
        dialog.destroy()

class TestApplication(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self, application_id='org.omsystem.pen')

    def do_activate(self):
        w = TestWindow(self)
        w.present()

app = TestApplication()
app.run(sys.argv)

ちと面倒。

activate_link のハンドラは True を戻さないと普通に実行してしまう。
msg.show() は非同期なのでとにかく True を戻す。
uri の処理は別シグナルなので user_data に入れて渡す。
実行は gio コマンドで、という流れになりました。

複数のリンクを作ったら全部コレ書かなきゃいけないのか、みたいな。
いやプログラミングってそういうものですけど。

Sakura

昨日てか土日の岩倉市、五条川はずーと曇りか雨でした。
それでもゲッソリするくらい来る花見客が写真を撮りまくっていた。
太陽光が乏しい白い雲が背景だとソメイヨシノの微妙な桃色が。。。。。

筆者も練習と割り切って土日もガシガシ撮影したよ。
案の定ブログに貼り付けられそうな写真は一つも撮影できなかった。
そして月曜の本日は雲一つない晴天、って観光客殺しかよ。

前置きはこれくらいにして。
今日の五条川(久しぶり)

gojyo river

やはり青空が背景だと全然違います。
背景は大事だよ、人間が実際に見た風景と写真はイコールではない。

gojyo river

川に入っているんじゃないよ、川底とカーブを利用した一枚。
こういうのが撮れるのが岩倉の五条川のいいところ。

gojyo river

アップしてみる、バリッとした花びら見たいじゃん。
F16 まで絞っても綺麗なままですね。

gojyo river

昨年上げた場所から今年も一枚。
流石にあの頃よりはチョッピリ腕が上がったかなって。

gojyo river

気が付くと 12mm 17mm 25mm しか使っていない。
いやいや、17mm のパンケーキ単焦点を買って良かったよ。
この三つな焦点距離さえあれば何でも撮れる、ということか。
マイクロフォーサーズの焦点距離なので他な人は計算してね。

しかし今日もデジイチな人が多いな、それも主に女性が。
本当に SONY な人が多いね、以前は CANON ばかりだったのに。
世間ではデジカメはスマホに駆逐されたみたいな風潮なんだが。

筆者は以前から思っていたんだよ。
スマホの写真に不満がある人が一斉に高級デジカメに移る日が来るって。
それが 2022 年な今なんだって思うのは気のせいなんだろうか。

GTK4: GtkMessageDialog

GTK4 は GtkMessageDialog が面倒になっていた。

#!/usr/bin/env python3

import gi, sys
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GLib

def on_message_response(dialog, response_id):
    dialog.destroy()
    loop.quit()

msg = Gtk.MessageDialog(
    buttons = Gtk.ButtonsType.OK,
    text = 'GTK4 MessageDialog Sample Code')
msg.connect('response', on_message_response)

#res = msg.run() # GTK3
msg.show()

loop = GLib.MainLoop.new(None, False)
loop.run()

GtkMessageDialog

run が廃止、戻り値はシグナルで受け取りする必要がある。
シグナルってことはメインループが必要ということで。
GTK3 までのように単独で使えるほうが変だったのを見直したようで。

おまけに親ウインドウが無いと警告まで出るように。
いやまあ、通常の利用ではそれで問題ないんだけどさ。

シグナルのハンドラは Gjs ならいいけど PyGObject だと面倒だな。
表示させるだけならラムダ式にすればいいかと。

ついでに、GtkLabel のマークアップって a href とかもイケるんだね。
GTK3 の時からイケたみたい、use-markup プロパティがある場所は全部使える。
上記をウインドウから使うサンプルと合わせてこんな感じ。

#!/usr/bin/env python3

import gi, sys
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GLib

class TestWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app)
        try:
            button = Gtk.Button(label = 'Show Message Dialog')
            button.connect('clicked', self.on_button_clicked)
            self.set_child(button)
        except Exception as e:
            print(e, file=sys.stderr)
            app.quit()
        self.present()

    def on_button_clicked(self, button):
        msg = Gtk.MessageDialog(
            buttons = Gtk.ButtonsType.OK,
            modal = True,
            text = '<a href="trash:///">Open the Trash</a>',
            transient_for = self,
            use_markup = True)
        msg.connect('response', lambda dlg, i: dlg.destroy())
        msg.show()

class TestApplication(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self, application_id='org.olympus.e-m5mark3')

    def do_activate(self):
        w = TestWindow(self)
        w.present()

app = TestApplication()
app.run()

GtkLabel

show は非同期なので show の後は何も処理を書いたら駄目なので注意。

ところで。

GNOME 開発センター(旧)

以前からあったのかどうかは知らないけど旧ページを見つけた。
developer-old としているので多分更新はしないんだろうけど。
API を個別サイトで参照するの面倒なんだよね。

Notify Signal

すっかり写真ブログ化しているこのブログですが。
今月末には新しい Fedora が出るはずなのでそろそろ本筋でも。
GTK4 のサンプルコードもそろそろ出そろってきたかなって。

GitHub – johnfactotum/quick-lookup: Simple GTK dictionary application powered by Wiktionary

このあたりが解りやすいかな。
省略表記多すぎ、てか文末セミコロンすら絶対に書かない派なのね。
まあ Gjs で GTK4 はこんなふうに書けばいいのかって参考にはなる。

気になったのは notify::is-active シグナル。
アクティブ化の真偽値をこのシグナルで捕まえられるのかな。

#!/usr/bin/gjs

imports.gi.versions.Gtk = '4.0'
const {GObject, Gtk} = imports.gi;

var TestWindow = GObject.registerClass({
    GTypeName: 'TestWindow'
}, class TestWindow extends Gtk.ApplicationWindow {
    _init(app) {
        super._init({
            application: app,
            title: '1'
        });
        try {
            this.connect('notify::is-active', () => {
                if (this.is_active) this.title += '1';
            });
        } catch(e) {
            printerr(`@@@Error@@@@:\n${e.message}`);
            app.quit();
        }
    }
});

var TestApplication = GObject.registerClass({
    GTypeName: 'TestApplication'
}, class TestApplication extends Gtk.Application {
    _init() {
        super._init({
            application_id: 'org.lumix.gh6'
        });
    }
    vfunc_activate() {
        let w = new TestWindow(this);
        w.present();
    }
});

let app = new TestApplication();
app.run(null);

おぉコレは使いどころがあるぞ。
昔筆者がやってた初回起動時間のセコい短縮なんかにも使えるね。
ウインド表示直後に処理 | Paepoi Blog

ところでこの Notify というシグナルって何だろう?

GObject.Object::notify

どうやら GObject のシグナルらしい。
そして is-active は GtkWindow のプロパティ。

Gtk.Window

つまりこのシグナルは何かプロパティをセットした時に吐きだすようだ。
別のプロパティで試してみよう、PyGObject でもイケるかな?

#!/usr/bin/env python3

import gi, sys
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk

class TestWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app)
        try:
            self.connect('notify::default-width', self.on_width_change)
        except Exception as e:
            print(e, file=sys.stderr)
            app.quit()

    def on_width_change(self, this, pspec):
        self.set_title(f'width: {self.props.default_width}')

class TestApplication(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self, application_id='org.olympus.pen')

    def do_activate(self):
        w = TestWindow(self)
        w.present()

app = TestApplication()
app.run()

width

イケた、ウインドウの横サイズを変更すると即座にタイトルが変更される。
Notify::** シグナルでプロパティを監視することが可能なんですね。
引数の GParamSpec から値を得ることもできると思うけど手段がワカラン。
プロパティを見ればいいだけなので別にいいか。

Nabana

今日の五条川、戻ってまいりました。
さて昨年は撮れなかったサクラカワセミーを今年こそ。

kawasemi

いや桜の木に止まってくださいよ、お願いします。
今日は他に二度見つけたけど撮影できず、来週こそ。

さて肝心の桜の花は岩倉市内で五分咲き程度。
桜がイマイチなら菜の花を撮影すればいいじゃん!

nabana

岩倉駅のすぐ近くにこんな場所があるのよ。

nabana

桜はイマイチだけど菜の花はガッツリ咲いているよ。

nabana

ぶっちゃけこんな景色はココら一帯だけなんだけどね。

sakura

桜の花も場所を選べば結構咲いています。
twitter で五条川を検索すると、やはり大量ですね。

ところで桜祭りは中止だけどライトアップの準備はされていた。
もう少し咲いたら夜桜でも、夜勤だから平日は無理だけど。

しかし今日は 17mm パンケーキ単焦点 f/6.3 のみで撮影したけど。
十分じゃね?プロレンズいらねーや。
それと EVF をまったく使わないので自動切替を off にしたら超快適。
仕上がり確認でアイセンサーが反応するのがうっとおしかったんだよね。
スーパーコンパネは OK ボタンで代用できる。

sakuramejiro

サクラメジローのほうが先に撮れてしまいました。
四千本もあるのによくぞ筆者の近くに来てくれた。