Wnck

Libwnck Reference Manual
を試していて面白いことをみつけた。

#!/usr/bin/env python3

from gi.repository import Wnck

screen = Wnck.Screen.get_default()
''' output
(process:5006): Gdk-CRITICAL **: ...
'''

となる、おいおいどういうことだよ。

Part?II.?Getting Started with libwnck
に書いてある Python コードをそのまんま書いたのに。
下のほうにある C のコードを見ると

gdk_init (&argc, &argv);

とあるので Gdk.init(sys.argv) が必要なのかな?
なんて思って試してみると

#!/usr/bin/env python3

from gi.repository import Wnck, Gdk

screen = Wnck.Screen.get_default()

# Screen Size
x = screen.get_width()
y = screen.get_height()
print("Screen @ {0}x{1} pixel".format(x, y))

''' output
Screen @ 1920x1080 pixel
'''

なんだよ Gdk の import だけで普通に動く、使っていないのに。
そういえば Gtk を使う場合も init を呼ばずに使えている。
PyGI では Gdk の import だけで初期化は完了するということなのね。
Gtk の import でも同様になるみたい。

更に

#!/usr/bin/env python3

from gi.repository import Wnck, Gdk

screen = Wnck.Screen.get_default()

win = screen.get_active_window()
print(win.get_name())

''' output
AttributeError: 'NoneType' object has no attribute 'get_name'
'''

None って、やはりこれも C のコード同様に

#!/usr/bin/env python3

from gi.repository import Wnck, Gdk

screen = Wnck.Screen.get_default()

# Important
screen.force_update()

win = screen.get_active_window()
print(win.get_name())

WnckScreen を作成しただけでは動的な状況を把握できないようです。
しかし下のサンプルコードではこんな関数を呼んでいない。
mainloop を回すなら update は不要ということみたい。

しかし面白いことに

#!/usr/bin/env python3

from gi.repository import Gdk

screen = Gdk.Screen.get_default()

win = screen.get_active_window()
w = win.get_width()
h = win.get_height()
print("Active Window @ {0}x{1} pixel".format(w, h))

こっちだと active_window が得られる、よくわかんねぇ!
WnckScreen と GdkScreen は用途がまったく違うから実際の混乱は無いだろうけど。
Wnck はスクリーンの監視等が主な役目。
ということでサンプルコードの下側を GUIに改造してみた。

#!/usr/bin/env python3

# https://developer.gnome.org/libwnck/stable/getting-started.html
# to PyGI Window

from gi.repository import Wnck, Gtk

class ScreenMonitoring(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        # Wnck
        screen = Wnck.Screen.get_default()
        screen.connect("window-opened", self.on_window_opened)
        screen.connect("active-window-changed", self.on_active_window_changed)
        # View
        view = Gtk.TextView()
        self.buf = view.get_buffer()
        sw = Gtk.ScrolledWindow()
        sw.add(view)
        # Label
        self.label = Gtk.Label("active:")
        # Pack
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        vbox.pack_start(sw, True, True, 0)
        vbox.pack_start(self.label, False, False, 0)
        self.add(vbox)
        self.resize(500, 200)
        self.show_all()

    def on_window_opened(self, screen, window, data=None):
        appname = window.get_application().get_name()
        title   = window.get_name()
        it = self.buf.get_end_iter()
        self.buf.insert(it, "{0}: {1}\n".format(appname, title))

    def on_active_window_changed(self, screen, previously_active_window, data=None):
        active_win = screen.get_active_window()
        if (active_win):
            self.label.set_text("active: {0}".format(active_win.get_name()))
        else:
            self.label.set_text("no active window")

ScreenMonitoring()
Gtk.main()

wncktest

機動後にアプリを立ち上げたりアクティブ状態を替えたりすると即座に反応する。
実はこのとき通知領域に clipoli を置いていたのだが認識しなかった。
Google Chrome は最小化していたけど認識、なるほど。

デスクトップはデスクトップというウインドウとして認識するのね
あと画像を見れば判るだろうけど筆者はデスクトップは desktop に変名している。
でも[デスクトップ]になる、Nautilus のサイドバーも変わらないしなんだろう?
Nautilus は[ファイル]にならないのに Eye of GNOME は[画像ビューアー]って何だよ。
Python アプリは get_application で python とはならないのか。

wnck_lubuntu

Lubuntu でも動くけど何故か Wnck が Warnimg を出しまくる。
desktop はキチンと変名、いやこのとき PCManFM で desktop を開いていた。
pcmanfm: pcmanfm がデスクトップのようだ、なんだこれ…
しかも何故か lxpanel を認識、GNOME と全然違うじゃないの。

なんかディストリビューションどころか環境ごとにバラバラになりそう。
上手く利用しないと Wnck はドハマリしそうな予感。