月別アーカイブ: 2022年4月

GTK4: Transparent Window

GTK4 で背景透過ウインドウを作る。

#!/usr/bin/env python3
 
import gi, sys
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GdkPixbuf, Gdk

# 背景透過な PNG 画像を用意して指定してください
PNGFILE = 'test.png'

APP_CSS = 'window { background-color: rgba(255, 255, 255, 0); }'.encode('utf-8')

class Win(Gtk.ApplicationWindow):
    '''
        decorated プロパティだけでは透過できなくなりました
        CSS にて透明にする必要がある
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, decorated=False, application=app)
        # CSS にて透過させる
        provider = Gtk.CssProvider()
        provider.load_from_data(APP_CSS)
        context = self.get_style_context()
        context.add_provider_for_display(
            self.get_display(),
            provider,
            Gtk.STYLE_PROVIDER_PRIORITY_USER)
        # 画像のロード
        self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(PNGFILE)
        # button-press-event 等は無くなりました
        ges = Gtk.GestureClick()
        ges.connect('released', self.on_gesture_click_released)
        self.add_controller(ges)
        # Draw
        da = Gtk.DrawingArea()
        da.set_draw_func(self.da_draw_func)
        self.set_child(da)
        # 画像サイズにリサイズ
        self.set_default_size(self.pixbuf.get_width(), self.pixbuf.get_height())

    def da_draw_func(self, da, cr, width, height):
        Gdk.cairo_set_source_pixbuf(cr, self.pixbuf, 0, 0)
        cr.paint()

    def on_gesture_click_released(self, ges, n_press, x, y):
        '''
            ダブルクリックで終了
        '''
        if n_press == 2:
            self.props.application.quit()

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

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

transpalent

面倒になった。

GTK3 は decorated を False にしてウインドウの draw シグナルを処理。
だけで良かったけれど GTK4 は CSS を使わないと透過できなくなっていた。

それに draw シグナルが廃止されたので GtkDrawingArea を使う必要がある。
CSS で透過させれば上に乗せた GtkDrawingArea も背景透過になるのは助かる。

ついでに、Gtk.StyleContext.add_provider_for_screen が廃止されていた。
GDK4 は GdkScreen が廃止されていたのか、気が付かなかった。
add_provider_for_display に変更、引数は同じ感じでイケた。

そんなこんなでやっとココまでできた。
後はドラッグで移動させる処理をなんとかせねば。

日本語情報が無いのはいつもの事だけど英語情報も全然無くて厳しい。
GTK3 は GTK2 のままから徐々に変更だったから楽だったんだよなって。

Yozakura

時期外れになる前に、日曜夜の五条川。

yozakura

せっかくの満開が曇りや雨で残念なら夜桜を撮影すればいいじゃない!

yozakura

と、月曜日に貼ろうと思っていたけど月曜は晴天だったので。

yozakura

ちなみに照明はもう撤去されています。

yozakura

さて五条川も葉桜になってきました。
梅から続く写真好きな人へのボーナスタイムも終わり。
次はゴールデンウイークの野鳥ボーナスタイムが待っている。
あ、サクラカワセミー今年も撮っていない。

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 を個別サイトで参照するの面倒なんだよね。