安達@沖データです。

すみません。おそらくRuby/Gtkのバグではなくて、Gtk/Gdk/Glibの不具合の可
能性が高いと思うのですが、最後まで追えていないのでとりあえず報告してお
きます。

<不具合の状況>
ruby 1.6.1 (2000-09-27) [i386-freebsdelf3.4](Ruby/Gtk-0.23, Gtk1.2.8)
において、Ruby/Gtkを用いたプログラムAと、それを呼び出す親プログラムBに
おいて、期待したexitステータスが得られない場合がある。ruby 1.6.0
(2000-09-19)[i686-linux](Ruby/Gtk-0.23, Gtk1.2.8)でも発生を確認した。

<不具合の発生条件>
親プログラムBが、プログラムAを呼び出す前に$stdin, $stdout, $stderrのい
ずれかをcloseしていること。

<不具合の確認>
最後に添付するプログラム実行する。Helloボタンを押すとtrue、Worldボタン
を押すとfalseの表示が期待される動作なのだが、実際にはどちらでもfalseと
なる。

<不具合の回避>
$stdin, $stdout, $stderrをクローズしなければ回避できる。

<不具合の追跡状況>
FreeBSD付属のktraceでプログラムAのシステムコールの呼び出しを追跡した結
果、次のことが判明した。

プログラムBにおいてfdの0, 1, 2のうちどれかが閉じてあると、Xサーバとの
通信にその閉じたfdが利用される。ところが、終了ステータス表示(p
"delete: #{$state}")の後、つまりexit(又はatexit)処理の中でfdの0, 1, 2
を無条件に閉じている。そのため、gdkが登録したatexit処理の一部である
XCloseDisplayがエラーとなる。結果として、Rubyスクリプトの指示した終了
ステータスに関係なくエラーが帰る。

<不具合に関する予測>
fd0, 1, 2を閉じている主体が、gtk/gdk/glib/システムのいずれかまでは、調
査しなかった。しかし、システムはatexit関数群を呼んだ後にストリームを閉
じることになっているので、gtk/gdk/glibの登録している処理がこのような状
況を予想しておらず、内部で不整合をおこしていると思われる。

--helloworld.rb: プログラムA
#!/usr/local/bin/ruby

require 'gtk'

def destroy(widget)
  p "destroy: #{$state}"
  exit($state)
end

def main
  $state = 0
  window = Gtk::Window::new
  window.signal_connect("destroy") { |*args|
    destroy(*args)
  }
  window.border_width = 10

  hbox = Gtk::HBox.new.show

  button = Gtk::Button::new("Hello")
  button.signal_connect("clicked") {|*args|
    $state = 0
    print "Hello\n"
    window.destroy
  }
  hbox.add(button)
  button.show()

  button = Gtk::Button::new("World")
  button.signal_connect("clicked") {|*args|
    $state = 1
    print "World\n"
    window.destroy
  }
  hbox.add(button)
  button.show()

  window.add(hbox)
  window.show()
           
  Gtk::main()
end

main

--testmain.rb: プログラムA
#!/usr/bin/env ruby

$stderr.close
bool = system("./helloworld.rb")
p bool
--
*------*				adachi / okidata.co.jp
|人∧鷲|				沖データ ソフトウェア開発部
| <女> |				安達 淳
|牛∨獅|
*------*