yendo weblog


LibGlade から GtkBuilder への移行 (PyGTK 編)

GNOME 3 では、LibGlade から GtkBuilder への移行が必須になる。 この移行でなにがどうメリットなのかよく分からない割りに、 細かいところで面倒だったので、ちょっとまとめておく。 以下 PyGTK を事例としているが、他の言語でもまぁ似たようなものだろう。

Glade ファイル UI ファイルへの変換

Glade で変換する。LibGlade 形式のファイルを読み込んで、GtkBuider 形式で保存するだけ。バージョン 3.6.7 で問題なく変換できた。

コードの修正

ほぼ機械的に変更できるが、シグナルの接続など場合によってはちょっとした手作業も必要になる。

インポートとオブジェクトの取得

プロジェクトファイルの読み込み

これも基本的には機械的に置き換えできる。

旧:

gui = gtk.glade.XML(GLADE_FILE)

新:

gui = gtk.Builder()
gui.add_from_file(UI_FILE)

しかし、単一の Glade ファイルに複数のトップレベルが含まれ、それぞれでシグナ ルが設定されている場合は、シグナルの接続に問題が起こる。(すべてのシグナルに ついて接続されていないとか警告をしてくれる。) それを回避するためには、以下 のようにあるトップレベル以下のみを読み込むことも可能である。

gui.add_objects_from_file(UI_FILE, ["window1"])

ただ、この場合別のツリー以下にあるオブジェクトの呼び出しに問題が起こる。 例えば adjustment のようなウィジェットツリーとは別のオブジェクトツリー以下 にあるオブジェクトの場合である。

いろいろ面倒なことを考えるよりも、シグナルを扱うウィジェットは、別の ui ファイルにまとめた方がいい。

シグナルの接続

基本的には signal_autoconnect → connect_signals である。

ただ、LibGlade で は複数回にわたって多重にシグナル接続を重ねることができたが、GtkBuider では、最初に接続したシグナル以外は無視される。 クラスの継承などでシグナルを多段設定している場合などは注意が必要。

よく質問されているようだが、 とにかくシグナルの接続は一回で済ますように変更するしかないようだ。 例えば以下のようにする。

旧:

dic = { "on_checkbutton_changed" : self._changed_checkbutton_cb }
gui.connect_signals(dic)

dic = { "on_combobox_changed" : self._changed_combobox_cb }
gui.connect_signals(dic)

新:

dic = { "on_checkbutton_changed" : self._changed_checkbutton_cb }

dic2 = { "on_combobox_changed" : self._changed_combobox_cb }
dic.update(dic2)
gui.connect_signals(dic)

i18n関連

プログラムを国際化している場合は、さらに変更が必要である。

POTFILE.in

メッセージを含むファイルを羅列すればよいのだが、 現在の intltool バージョン 0.41.0 だと GtkBuider ファイルに対応していない。 ui ファイルが bonobo の ui ファイルと見なされ、処理されない。 そのため glade ファイル同様に扱われるように、ファイル名の先頭に [type: gettext/glade] を付与しておく。 main.ui と sub.ui のようなファイル名の場合は以下のようになる。

[type: gettext/glade]main.ui
[type: gettext/glade]sub.ui

bindtextdomain

gtk.glade の代わりに locale モジュールを使う。

import gettext
import locale

for module in (gettext, locale):
    module.bindtextdomain(APP_NAME, LOCALE_DIR)
    module.textdomain(APP_NAME)

参照サイト

2010/04/06 (Tue) 20:48 | タグ: computer | 固定リンク


GNOME 写真フレーム

デスクトップ上に写真を表示するガジェット (フォトフレーム) は、 Windows なんかだとずいぶんさまざま公開されているけど、 GNOME デスクトップ向けだとちょっと高機能なものなど見あたらなかったので、 PyGTK で作ってみた。

特徴

インストール

GNOME 写真フレームは以下のパッケージに依存している。

また以下のパッケージが推奨されている。

ダウンロードして、展開後に ./setup.py install でインストールする。 あるいは一部機能が制限されるが、インストールせずに直接 gphotoframe を実行することも可能。

2009/05/16 (Sat) 23:21 | タグ: computer | 固定リンク


PyGTK でのバックグラウンド動作

GUI アプリ動作時にウェブにアクセスすると、その間 GUI が固まってしまう。 これを回避するにはウェブへのアクセスをバッググラウンドで行なう必要がある。 Gtk2-Perl の場合については以前書いたけど、 PyGTK なら Twisted を使えばとっても簡単。 これくらいなら、フォークとかスレッドとか細かな面倒を見なくて済む。

まずは必要なモジュールをインポート。 他のモジュールに先行してインポートした方がいいらしい。

from twisted.internet import gtk2reactor
gtk2reactor.install()
from twisted.internet import defer, reactor
from twisted.web import client
ウェブへのアクセスには getPage を使う。addCallback でアクセス終了後に呼び出す関数を指定する。 downloadPage では、ファイルへのダウンロードを行う。
d = client.getPage(url)
d.addCallback(func_cb)

def func_cb(data):
    print data

メイン・ループについては、gtk.main() の代わりに reactor.run() で開始、 また終了についても、gtk.main_quit() の代わりに、reactor.stop() を使う。

reactor.run()

なお、プロキシーを利用する場合はちょっと面倒みたい。 簡単な方法はないのかな。

追記: 結局プロキシーを利用する適当なモジュールを自分で用意した。(2009/05/19)

2009/04/18 (Sat) 15:14 | タグ: computer | 固定リンク


gnome-terminal の文字幅問題

gnome-terminal のというか libvte の East Asian Ambiguous 問題は、最新の libvte 0.17.4 では解決されている。 libvte 0.16.x ではうまく効かなかった環境変数 VTE_CJK_WIDTH だが、 libvte 0.17.4 では wide なり auto (locale で自動判定) なりを指定すればちゃんと効く。

一方、この libvte 0.17.4 では文字の間隔 (フォントの幅?) が妙に広くなってしまうという問題がある。 ただ、理由はよく分からないが、これは環境変数 VTE_BACKEND に pango を指定すれば、従来通りの幅で表示してくれる。

環境変数をどこで設定したらよいか分からなかったので、 ランチャに以下のように指定した。

env VTE_CJK_WIDTH=auto VTE_BACKEND=pango gnome-terminal --disable-factory

gnome-terminal もこれで快適。

2009/02/03 (Tue) 03:35 | タグ: computer | 固定リンク


F-Spot の日本語メッセージカタログ

F-Spot の日本語メッセージカタログを更新した。本家リポジトリの翻訳と、 Launchpad および Novell の翻訳をまとめ、未翻訳のところを訳した。 また、po ファイルではひとまずコメントアウトしてあるが、オリジナルの POT ファイルに含まれていない「設定」画面のメッセージも翻訳した。

その際、訳語や表記は基本的に相花さんの翻訳 (F-Spot や他の GNOME アプリ) に合わせ、その上で画像処理関係は GIMP の翻訳に、EXIF 関連や (写真用語) は EXIF の仕様書に合わた。

なお、ちょっと悩んだ翻訳に "Reparented" があった。 あまり使われる機能ではないが(コンパイルオプションの指定が必要)、 F-Spot のバージョン管理で使われるバージョンの一つで、 オリジナルの写真だったものを他の写真のバージョンの一つに変更させたものだ。 こちらはちょっと苦しく「再関連付け版」と訳した。

f-spot.mo を /usr/share/locale/ja/LC_MESSAGES/ なんかにコピーすれば、この翻訳が利用できる。

追記 1: 相花さんにエラーを修正の上コミットしていただいた。(2009/3/16 23:40)

追記 2: 0.6.x リリースにあわせて翻訳を更新した。 (2009/10/20 22:05)

2009/01/24 (Sat) 18:49 | タグ: computer | 固定リンク


デジタル一眼レフカメラを買った

ダカフェ日記を見てしまい デジタル一眼カメラが欲しくなってしまった、というスイーツ(笑)ぶり。 なので、なるべく安く単焦点の明るいレンズを使うという観点でカメラを選ぶ。

一眼レフだとレンズキットで 4、5 万円くらいからあるのか、 安くなったものだなぁと調べてみるが、レンズってやっぱり高いのね。 いわゆる標準レンズに相当する単焦点レンズが欲しかったけど、 レンズ単体に 3 万円とか払えないですよ。 安い単焦点レンズというと Canon で EF50mm F1.8 II (約 9,000 円)、Nikon で Ai AF Nikkor 50mm F1.8D (約17,000円) ぐらい。 ただ、この Nikon のレンズなんかは普及機では AF が使えない。 ということで、メーカーは Canon に決定。

Canon で入門機というと Kiss シリーズ。旧機種の Digital X、現行機種の FX2 がある。 レンズキットがお得なので、 レンズ込みで考えると手ぶれ補正機構は欲しいかなということで Digita X は止めた。デジタルカメラは新しいものが基本的に良いだろうし、 物持ちが良い方なのでメーカーの補修用性能部品の保管期間が ちょっとでも長い方がいいかもしれないぐらいを考えた。 あと、SD カードの方が少し安いかな。

で、F と X2 で悩んだ。調べてみると結構細々違うようになっているが、 そのほとんどが私のような素人にはどっちでもいい感じ。 ただ、気になるのが連写撮影速度。JPG なら 3 枚/秒か、3.5 枚/秒の違いでどうでも良いのだけど、RAW の場合 F だと 1.5 枚/秒になってしまう。せっかくのデジタル一眼レフなので RAW で連写したいかなということで、これで X2 に決めた。 1 万円程度しか違わないし……、 とかなると他の相違も結構大きいかなとか思えるという不思議。

Kiss X2 でちょっと残念なのはボディの安っぽさぐらい。 これに関しては、F の方がボディ塗装がマットな感じで私には好ましい。 見た目については Nikon の D60 なんかは、値段の割によくできてると思う。

ということで Kiss X2 レンズキットと EF 50mm F1.8 II を購入した。 総計 66,000 円ぐらい。X2 には延長保証もつけたので、安く買えたと思う。 ほんの少しだけど撮った写真を Flickr にアップロードしたりする。 自分としては、思ったよりはまともに撮れて安心した。 一眼レフ楽しい。

2008/11/27 (Thu) 22:20 | タグ: misc | 固定リンク


Gtk2-Perl でのバックグラウンド動作

Gtk2-Perl で Twitter クライアント Twitim を作った折りのメモ。 アプリ動作時にウェブにアクセスすると、その間 GUI が固まってしまう。 これを回避するにはウェブへのアクセスをバッググラウンドで行なう必要がある。 ちなみに、ちょっと哀しいけど結論だけなら 最後の「もっと簡単な方法」だけ読めば十分みたい。

分岐 fork

バックグラウンド動作のための分岐には、 スレッドやフォークがある。このような目的で スレッドを簡単に使うには POE があるようだがちょっとおおげさすぎる。 スレッドは UNIX 環境以外でも使えるのだろうが面倒だし、 Gtk2-Perl の FAQ でもお勧めしないとある。 なお、ruby なら間違いなくスレッドなのだろう。 Gtk2-Perl のアプリではバックグラウンド動作の例があまり 見つからなかったが、gnview はスレッドを使っている。

今回は AnyEvent を使っていることもあり、なるべく単純にと伝統的なフォークを使う。 AnyEvent は Gtk のイベントとなら協調して動作するが、 スレッドとか POE とかとはどうなのか不安だったこともある。 ただフォークでも注意が必要。 子プロセスの終了には use POSIX; の上、POSIX::_exit(1) する必要あり。 そうしないと X のエラーが起こる。 FAQ に情報 あり。 またその返り値は必ず指定する。 指定しないと X のエラーが起こる。はまった。返り値はまぁ 1 でしょう。

通信 pipe

子プロセスから親プロセスに、通信結果を渡すプロセス間通信だと、 パイプや共有メモリが一般的。 変数で渡すなら共有メモリもいいが、基本スカラー変数しか渡せない。 (共有メモリについてもサンプルがある。 IPC-ShareLite は簡単。)

今回はパイプを使う。 サンプル あり。pipe() をつかって、親と子を繋ぐ pipe ハンドラを指定する。 use IO::Handle; の上バッファに貯めないよう autoflush させた方がいい。 (なお、Net::XMPP2::Client; は IO::Handle;に依存)

また、同時に複数のパイプが開かれる場合があるので、 ファイルハンドルには未定義の変数をあて、Perl (5.6.0 以降) に自動的に生成してもらう。 ファイルハンドルに変数を使うことはできない。

コールバック Helper->add_watch

子プロセスから読込んだデータを親プロセスで使うには、 子プロセスの終了を検知しなければならない。

AnyEvent で子プロセスの終了を検知したり、 ファイルハンドラの読み込みからコールバックしたりすることもできるが、 今回は Gtk の Helper->add_watch で ファイルハンドラの読み込みからのコールバックを使った。 サンプルあり。

親プロセスで、Helper->add_watch のセットをしておけば、 子プロセスの終了を待たず (たぶん)、データがある程度流れて来次第、 親プロセスでそのデータを随時処理できるようだ。 子プロセスでパイプを close されると、そこでデータの読み込みを終了する。

もっと簡単な方法

……と言うように実装してしばらくしてから、 Re: forking an external process: msg#00022 というそのものの記事を見つけた。 LWP::UserAgent でサブルーチンのリファレンスを引数として渡し、 その中で Gtk->main_iteration while Gtk->events_pending; を呼ぶという方法だ。 とても賢い。ちゃんと試してないが大抵のところこれで十分だろう。 気づくのが遅かった。

追記: いろいろ書いたけど、結局のところモジュール依存を気にしなければ、 AnyEvent-HTTP を使えば超簡単。お勧め。 (2009/4/18)

2008/05/21 (Wed) 01:28 | タグ: computer | 固定リンク