いがらしです。

At Tue, 13 Mar 2001 03:18:06 +0900,
in [ruby-ext:01635] bug? in Ruby/Gtk::timeout,
surme <CZU13166 / nifty.com> wrote:
> 
> 以下に添付したscriptで、Gtk::timeout_addに渡すブロックで呼ばれる
> timeout_test関数がうまく動いてくれません。
> (1)の位置で$counterをインクリメントするとtimeout_testは一回しか
> 機能しないようです。

Gtk::timeout_addに渡すブロックの評価値の真偽によって
次回以降もこのブロックが呼び出されるかどうかが決まります。

> def start_timeout_test
>   $timer = Gtk::timeout_add(Interval) { timeout_test } if $timer.nil?
> end

ブロックの本体は単にtimeout_testを呼んでいて、そちらは

> def timeout_test
> 
> #if counter incrementation is done here, timeout works at only first time.
> # $counter += 1      #####(1)#####
> 
>   $label.set "count: #{$counter}" 

となっていますが、このGtk::Label#setメソッドの呼び出しは
nilを返すので、(1)の方を生かした場合、timeout_testメソッドの
評価値はnilになり、これがそのままブロックの評価値になります。
結果、次からは呼び出されなくなります。

>                     (2)の位置ですと正常に動作するにはしますが、
> インクリメントのタイミングが望み通りではないのです。
> もちろん$counterを1で初期化するなど回避はいくらでもできるのですが、
> これが仕様だと嬉しくないなぁ、と思います。

こちらでは、それなりに正確に動作しているように見えます。
# xclock -digital -update 1 の表示と並べてですが
「望み通りではない」とはどのようなことでしょうか。
Gtk::timeout_add(が中で呼んでいるC関数g_timeout_add())は
精度を保証していないので、多少の誤差は生じてしまうと思います。

また、g_timeout_add()の説明
    http://developer.gnome.org/doc/API/glib/glib-the-main-event-loop.html#G-TIMEOUT-ADD
によると、

Note that timeout functions may be delayed, due to the processing of other event sources. Thus they should not be relied on for precise timing. After each call to the timeout function, the time of the next timeout is recalculated based on the current time and the given interval (it does not try to 'catch up' time lost in delays).

なので、何かで一度呼び出しが遅れても、そのままみたいですね。

時間経過と$counterの増分を少しでも正確に対応させたいのなら、
Gtk::timeout_addはあくまで表示の更新のために使って、
$counterの値は時刻の差分から計算した方がいいように思います。

> 
> #incrementing here doesn't influence to timeout,
> #but I want increment correctly... 
>   $counter += 1      #####(2)#####
> 
> end

こちらの場合値がFixnumなので真とみなされて、
継続してブロックが呼び出されますが、
明示的にtrueを返した方が分かりやすいと思います。

> さらに、
> if $counter == 10
>   stop_timeout_test
>   Gtk.main_quit
> end
> のような条件文を入れて、自動的にダイアログを閉じさせようとすると、

こちらはif式の条件が成立しないとき(例えば最初の呼び出し時)の
評価値がnilなので、これを最後におくと、
次回以降呼ばれなくなってしまいます。

> 以上の動作はbug?それとも仕様でしょうか?
> 他にもうまく動作しないことがあるのですが、とりあえず以上のケースが
> 特定できましたので報告します。

示して下さったプログラムの問題については仕様です。
他に問題があれば教えて下さい。

--
五十嵐  宏  (Hiroshi IGARASHI)