Ruby インタラクティブ・グラフィック TODO

Rubyインタラクティブなグラフィック処理をしたい。ゲームを作るわけではない。ただ、line() と書いたらそこで線が描かれてほしいのである。つまり、fork とかでグラフィック用のサーバを作りたい。手持ちには GTK+ 用に自分で作った Gem 'oekaki' があるので、それの発展形として GTK+ を使いたいわけだが、簡単に Thread.new ではプロセス間通信がうまくいかないようである。つまり、Thread クラスと Gem 'gtk2' は相性がよくないらしい。

では Kernel#fork ならどうか。これはまだ試していない。TODO である。



Gem 'gtk2' を使うなら、いずれにせよ Gtk.timeout_add を利用するしかないだろうな。それ以外に方法があるかだが、Ruby/GTKリファレンスを見ても自分の英語力ではいまだつかめていない。まあ、英語力だけでなくて、GTK+ がいまひとつわかっていないのだ。

Gtk.init_add はどう使うのかな。いや、これは何かイベントが呼び出されないといけないだろうな。自分で独自のイベントを作ることはできるのか?

Gdk::Eventクラスを見てみるか。イベントの種類(GdkEventType)に CLIENT_EVENT というのがあるぞ。説明としては「別のアプリケーションからメッセージを受け取る」とある。これはそれっぽいが…。

さらに調べてみる。Gtk::Widget のところに、シグナルの種類で client-event というのがある。self が Gtk::Widget で event が Gdk::EventClient だ。後者の説明には確かに「別のクライアント・アプリケーションから送信されるイベント」とある。ふむ。ということは、Gdk::Event.new(CLIENT_EVENT) とかで独自イベントを作ることができるようでもある。どうなのだろう。で、それが可能だとして、シグナルの発送はどうするのだろうな。シグナルの発送は Gtk::Widget#event() メソッドで行うようだが(その前に set_events() しないといけないのかな)、独自のクライアント・アプリケーションの Gtk::Widget オブジェクトはどう作ればいいのか。うーん、わからない。

おや、何やら Gtk::Socket などというのがあるが。こんなことが書いてある。

Gtk::Plug と一緒に使われて、Gtk::Socket はプロセスから別のプロセスへ、ユーザーに透明な方法でウィジェットを埋め込むことを可能にします。あるプロセスは Gtk::Socket ウィジェットを作り出し、別のプロセスにウィジェットのウィンドウID を渡しますが、その別のプロセスというのはそのウィンドウID とともに Gtk::Plug を作ります。Gtk::Plug に含まれるあらゆるウィジェットは、すると最初のアプリケーション・ウィンドウの中に現れるでしょう。ソケットのウィンドウID は Gtk::Socket#id メソッドによって得られます。このメソッドを用いる前にソケットは存在していなければならず、そのようにして「親」に追加されねばなりません。

うーん、これもそれっぽいが、まだよくわからない。とにかくこれは Gtk::Widget ではあるのだ。すると Gtk::Socket.newGtk::Widget オブジェクトを生成すればいいのかな?
続きも訳そう。

注意。もしソケットのウィンドウID を、そのソケットにおけるプラグを作る別のプロセスに渡そうとするなら、プラグが作られるまでソケットは destroy されないことを保証しなければなりません。これが守られないと何が起きるか確かではありませんし、おそらくプラグは別のトップレヴェル・ウィンドウとして現れてしまうことでしょう。プラグが作られたかどうかは、Gtk::Socket#plug_window メソッドで確かめられます。返り値が nil でなければ、プラグはソケット内で確かに作られているとわかります。埋め込まれたウィンドウが destroy されたと GTK+ が知らされれば、ソケットも同じく destroy されます。したがって、メイン・イベントループが動いている間は常に、ソケットが destroy されるかどうか気にかけるべきです。Gtk::Socket と Gtk::Plug の間の通信は XEmbed プロトコルに従います。このプロトコルは、例えば GTK に 同レヴェルで Qt ウィジェットを埋め込んでいるなら、Qt などの他のツールキットによっても実行されていますし、またその逆も真です。

よくわからないな。Gtk::Plug もまたウィジェットというわけか。では目的にはちょっとちがうようだ。
(ついでだが、Gtk::Socket についてはこんなサンプルがある。自分がアホでいまひとつわからんが(笑))

いや、「独自のクライアント・アプリケーションの Gtk::Widget オブジェクトはどう作ればいいのか」などと書いたが、アホや。Gtk::Socket はたぶん関係ない。シグナルを発するのも受け取るのもメイン・ウィンドウだな。別プロセスからプロセス間通信を受け取ってシグナルを発送すればいいのか。では、問題はプロセス間通信だな。Thread + Queue でいけるのか。Kernel#fork + IO.popen か何かなのか。

うーん、色いろやってみたが、client-event の使い方はよくわからないな。Gdk::EventClient.new(Gdk::Event::Type::CLIENT_EVENT) で # ができるのは確か。また GLib::Instantiatable#signal_connect("client_event") もエラーはでない。さて。



では別方向から。Gdk::Screen って何?
と思って

$ irb
irb(main):001:0> require 'gtk2'
=> true
irb(main):002:0> s = Gdk::Screen.new
=> #<Gdk::Screen:0x56226d2f2598 ptr=0x56226d2f6170>
irb(main):003:0> s.width

ってしたら SEGV した(笑)。