Ruby-GNOME2の再帰メインループ (gkt2 3.1.8)
Gtk2の再帰メインループとDialog#runの関係が思ってたとおりではなかった。絶対忘れるのでメモ。
検証用コード
# -*- coding: utf-8 -*- require 'gtk2' window = Gtk::Window.new window.signal_connect(:destroy){ Gtk.main_quit } box = Gtk::VBox.new window.add(box) button_a = Gtk::Button.new('Gtk.main') box.pack_start(button_a) button_a.signal_connect(:clicked){ dialog_open_gtk_main(window) false } button_b = Gtk::Button.new('Dialog#run') box.pack_start(button_b) button_b.signal_connect(:clicked){ dialog_open_dialog_run(window) false } window.show_all Gtk.quit_add(Gtk.main_level){ puts 'quit!' } ml = nil Gtk.idle_add{ n = Gtk.main_level if n != ml puts "level #{ml.inspect} -> #{n.inspect}" ml = n end true } def dialog_open_gtk_main(parent) window2 = Gtk::Dialog.new('dialog', parent, Gtk::Dialog::MODAL | Gtk::Dialog::DESTROY_WITH_PARENT, [Gtk::Stock::OK, Gtk::Dialog::RESPONSE_ACCEPT]) window2.signal_connect(:destroy){ Gtk.main_quit } window2.signal_connect(:response){ |w, r| window2.destroy } window2.show_all Gtk.main puts 'dialog_open_gtk_main: finish' end def dialog_open_dialog_run(parent) window2 = Gtk::Dialog.new('dialog', parent, Gtk::Dialog::MODAL | Gtk::Dialog::DESTROY_WITH_PARENT, [Gtk::Stock::OK, Gtk::Dialog::RESPONSE_ACCEPT]) window2.run{ |r| window2.destroy } puts 'dialog_open_dialog_run: finish' end puts Gtk::BINDING_VERSION.join('.') Gtk.main
同じようなダイアログボックスを、Gtk.main + イベントハンドリングで表示するのと Gtk::Dialog#run を使って表示するやつ。
出力
~/tmp $ ruby mainloop-test.rb 3.1.8 level nil -> 1 dialog_open_dialog_run: finish dialog_open_dialog_run: finish level 1 -> 2 quit! dialog_open_gtk_main: finish level 2 -> 1 level 1 -> 2 dialog_open_gtk_main: finish level 2 -> 1
わかったこと
Dialog#run は Blocks in a recursive main loop until the dialog either emits the response signal, or is destroyed. とのことだが再帰メインループレベルはインクリメントされない。当然、Gtk.quit_addで登録した再帰メインループ脱出時のハンドラも呼ばれない。ただし、Dialog#runで(ダイアログボックスに入力するまで)処理はブロックされ、再帰メインループのように扱うことが出来ている。