Python」タグアーカイブ

PyGObject SendMessage and PostMessage

GTK+ で PostMessage をやりたい。
ようするに関数を抜けてからシグナルの処理をしたい。
g_signal_emit では関数がそこで止まってしまう。

g_idle_add を使って似たようなことはできるんだけど。
Gedit for Windows part3 | PaePoi
やはり正攻法でやりたいジャン。

gdk_event_put という関数を見つけた。
この引数に GdkEvent を渡せばイケるかも。

Gjs で書いていたけど GdkEvent がどうやっても作れない。
手段を知らないだけか実装されていないのかは不明。
ということで久々に PyGObject でやってみる。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0') 
from gi.repository import Gtk, Gdk

class EmitTest (Gtk.Window):
    """
        SendMessage, PostMessage
    """
    def __init__(self):
        Gtk.Window.__init__(self)
        b1 = Gtk.Button(label="g_signal_emit")
        b2 = Gtk.Button(label="gdk_event_put")
        b1.connect("clicked", self.on_emit_clicked)
        b2.connect("clicked", self.on_put_clicked)
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        vbox.pack_start(b1, False, False, 0)
        vbox.pack_start(b2, False, False, 0)
        self.add(vbox)
        self.show_all()

    def on_emit_clicked(self, button):
        ''' # output
            delete-event
            [g_signal_emit] Clicked
        '''
        self.emit("delete-event", None)
        print("[g_signal_emit] Clicked")

    def on_put_clicked(self, button):
        ''' # output
            [gdk_event_put] Clicked
            delete-event
        '''
        event = Gdk.Event.new(Gdk.EventType.DELETE)
        event.any.window = self.props.window
        event.put()
        print("[gdk_event_put] Clicked")

    def do_delete_event(self, event):
        print("delete-event")
        Gtk.main_quit()
        return True

EmitTest()
Gtk.main()

gdk_event_put ならハンドラを抜けた後に delete-event が発行される。
これなら PostMessage と同じように使えそうだ。
ただ本当は Gjs でやりたいんですけど。

Fedora 24 に入る Gjs なら同様に使えるのかな?
と楽しみにしていたら又一週間リリースが延びたようだ。
ま、いつものことか。

Gtk TreeView (Gjs, PyGObject)

Gjs で ListView(TreeView) にてハマったので覚書。
作り方自体は以下のページ手順で問題ないです。

TreeView with ListStore (JavaScript)

問題は PyGObject のコードから移植する場合。
PyGObject は実は PyGtk プロジェクトの記法を沢山取り入れている。
そのため記述が簡単だけど C の手段から掛け離れている場合が多々ある。

gtk_liststore_append はこんなに別物

/*@ PyGtk and PyGObject
liststore.append([data1, data2])

@ C
GtkTreeIter* it;
gtk_list_store_append(liststore, it);
gtk_list_store_set(liststore, it, 0, data1, 1, data2, -1);
*/

// Gjs
let it = liststore.append();
liststore.set(it, [0, 1], [data1, data2]);

PyGObject, PyGtk ってこんなに省略さていたのか!
C で複数セットの説明は省略、Gjs はナルホドと思うバインド。
PyGtk 様は必ずセットで行うのだから、とまさかのココまで省略したっぽい。
そのまんま PyGObject に採用されてしまったということですね。

gtk_tree_selection_get_selected なんかも。

/* PyGObject
model, it = selection.get_selected()
*/
let [isSelected, model, it] = selection.get_selected();

Python という言語は結果が同じ手段を一つしか提供しないことで有名。
上記は it が None かどうかを調べればいいので isSelected なんて不要。
憶測だけどそういうことなのだろうか。
しかも Gjs は上記で戻り値を二つにしてもエラーにならないから困る。

let [model, it] = selection.get_selected();
print(model);

みたく printf debug を駆使してやっとエラーの原因が解るの繰り返し。
Python コードから移植するより devhelp を見たほうが速い気がする。
複雑なツリービューだともっと面倒臭いかも。

そんなこんながありまして。
Y901x は本サイトでベータ公開となりました。

Linux アプリケーション – L’Isola di Niente

だって早く作らないと作った本人が拡大表示すらできない環境だもん。
SKYLAKE Fedora 環境は頗る安定しています。

PyGObject and Gjs API Reference

PyGObject の API Reference を見つけた。
GLib, Gtk だけでなく GObject introspection 全部。

Python GI API Reference

正直かなり見難いけど。
使い道がイマイチ解からなかったライブラリもコレでバッチリ。

実は Gjs も同じライブラリなのでそのまんま適用できます。
とりあえず Xkl で試してみましょう。

#!/usr/bin/env python3

from gi.repository import Xkl

s = Xkl.get_country_name("DE")
print(s)
#=> Germany

s = Xkl.get_language_name("jpn")
print(s)
#=> Japanese

Gjs

#!/usr/bin/gjs

const Xkl = imports.gi.Xkl;

let s = Xkl.get_country_name("DE");
print(s);
//=> ドイツ

s = Xkl.get_language_name("jpn");
print(s);
//=> 日本語

コメントに解答してますが、動かしてみます。

python_setlocale

忘れていた、3.18 から require_version 必須だった!
Gjs は不要なのに、今後は解らないけど。
それより Gjs だと日本語になるんだが何が違うのだ?

#!/usr/bin/env python3

import locale
locale.setlocale(locale.LC_ALL, '')

import gi
gi.require_version('Xkl', '1.0')

from gi.repository import Xkl

s = Xkl.get_country_name("DE")
print(s)
#=> ドイツ

s = Xkl.get_language_name("jpn")
print(s)
#=> 日本語

これで Gjs と同じ結果になった。
Gjs は locale 設定を自動的にやっているってことなのね。
PyGObject しかやっていなかったら英語でしか取得できないと勘違いしていたかも。
やっててよかった JavaScript!

それより、Gjs のほうが簡単になる場合なんてあったのか。
そろそろ本格的に移行かな、Y901x を作り替えするだけだが。

g_file_set_display_name

GFile で g_file_set_display_name すると普通にリネームするんだね。

#!/usr/bin/env python3

import sys
from gi.repository import Gio

f = Gio.File.new_for_path(sys.argv[1])
f.set_display_name("nae_yuki.jpg")

rename

存在しないファイルでこの関数を使うと「存在しないよ!」とエラー。

rename_error

こうなってしまったので気が付いただけですが。
なるほど、メモリ上のデータではなくファイルポインタなのね。

ちなみに、これを利用してリネームツールをとか考えたけど。

mvにサヨナラ!renameコマンドのイケメンぶりが半端ない | techiela

rename コマンドってこんなに便利だったのか…
mv しか使ったことがなかったYO!

GtkPlacesSidebar

あれ、今まで Widget ギャラリーページなんてあったかな?
Widget Gallery: GTK+ 3 Reference Manual

Widget 画像をクリックするとそのページにジャンプできる。
これは微妙に便利。

てか GtkPlacesSidebar というものが 3.10 時からあったのか。
このページのおかげで今頃知ったぞ!

しかしどう見ても Nautilus の左ペインそのまんまだが何だこれ。
試してみるのが一番速いな、ということで。

#!/usr/bin/env python3

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio, GLib

class SidebarTest(Gtk.Window):
    """
        Nautilus Sidebar
    """
    def __init__(self):
        Gtk.Window.__init__(self)
        # GtkPlacesSidebar
        sidebar = Gtk.PlacesSidebar.new()
        # Select Documents Directory
        doc = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS)
        f = Gio.File.new_for_path(doc)
        sidebar.set_location(f)
        # Add Shortcut
        f = Gio.File.new_for_path("/home/sasakima-nao/doc/html")
        if f.query_exists():
            sidebar.add_shortcut(f)
        # Signal
        sidebar.connect("open-location", self.on_sidebar_open_location)
        # etc...
        #sidebar.set_show_recent(False)
        #sidebar.set_show_other_locations(True)
        #sidebar.set_show_enter_location(True)
        self.add(sidebar)
        self.show_all()

    def do_delete_event(self, event):
        Gtk.main_quit()

    def on_sidebar_open_location(self, sidebar, location, open_flags):
        """
            location @ GFile
        """
        uri = location.get_uri()
        self.set_title(uri)

SidebarTest()
Gtk.main()

sidebar

外付け USB HDD を繋いだら普通に認識までしてくれたぞ。
ブックマークも同じ、本当に Nautilus の左ペインそのまんまじゃないか。
でも何故か 3.18 で「他の場所」部に移動した root が表示される。

ショートカットの追加も可能、ただし実在している必要があるようだ。
一部は非表示にもできるけど基本 Nautilus と同じってことみたい。

うーん、これってどういう場面で使うのだろう?
外部機器の接続監視やサーバーログインを自前でやる必要が無いのはいいが。
オリジナルな「開くダイアログ」以外の使い道が考え付かない DESU。