Asynchronous events in GTK application?

(Clifford Heath) #1

I have a GTK app with a thread monitoring a COM port for particular
input events. What's the best way to notify the main GTK thread of
these events? Can i hook into the main loop somehow?

Clifford Heath.

(Clifford Heath) #2

Ok, I learnt some more, and I think I'm hung up on a GTK "feature".
This is with the Debian Linux version that calls itself 0.9.1.

My asynchronous device events cause a condition variable to get
set. I've written a main loop that checks the variable, like this:

  while true
    processEvent if (@device_event)
    Gtk.main_iteration
  end

(According to the documentation, I should use:
  break if Gtk.main_iteration
but in this version, main_iteration always returns true. I guess
that's a change from the 0.9.1 version.)

In case there are no GUI events, I added a timeout which pumps
the loop. If the timeout is set to 1000ms, 500ms, no problem.
As soon as I drop the timeout much more (like 250ms or, what I'd
like, 100ms) the display never gets refreshed.

It seems that Gtk.main_iteration doesn't seem to ever process
paint (expose) events if an event has occurred recently, including
a timeout event(!).

What I'd like is to inject a NULL event into Gtk's queue when
an asynchronous event occurs, instead of using timeouts. But if
I can just get the timeout down to 100ms, that would work also.

Anyone have a solution to this? I wish the Debian packages weren't
always so far behind :-(.

Clifford Heath.

(Masao Mutoh) #3

Hi,

Ok, I learnt some more, and I think I'm hung up on a GTK "feature".
This is with the Debian Linux version that calls itself 0.9.1.

My asynchronous device events cause a condition variable to get
set. I've written a main loop that checks the variable, like this:

  while true
    processEvent if (@device_event)
    Gtk.main_iteration
  end

(According to the documentation, I should use:
  break if Gtk.main_iteration

Do you mean to call Gtk.events_pending? ?

but in this version, main_iteration always returns true. I guess
that's a change from the 0.9.1 version.)

Hmm. I've not change the behavior of Gtk.main_iteration for long time.

Anyway, if you don't call Gtk.main anywhere, Gtk.main_iteration
doesn't work correctly.

In case there are no GUI events, I added a timeout which pumps
the loop. If the timeout is set to 1000ms, 500ms, no problem.
As soon as I drop the timeout much more (like 250ms or, what I'd
like, 100ms) the display never gets refreshed.
It seems that Gtk.main_iteration doesn't seem to ever process
paint (expose) events if an event has occurred recently, including
a timeout event(!).

Anyone have a solution to this? I wish the Debian packages weren't
always so far behind :-(.

How about to use Gtk.timeout_add ?

P.S.
I think gtk-demo(in Ruby-GNOME2 tar ball) scripts may be helpful.

···

On Mon, 15 Aug 2005 22:11:13 +0900 Clifford Heath <no@spam.please.net> wrote:

--
.:% Masao Mutoh<mutoh@highway.ne.jp>

(Clifford Heath) #4

Masao Mutoh wrote:

Do you mean to call Gtk.events_pending? ?

No, I'm happy if it blocks inside main_iteration, as long as the
timeout I added makes main_iteration return - which it does.

but in this version, main_iteration always returns true. I guess
that's a change from the 0.9.1 version.)

Hmm. I've not change the behavior of Gtk.main_iteration for long time.

Well, then either the documentation or the code is wrong, because it
always returns true. I don't see how I can tell when quit has been
called...?

Anyway, if you don't call Gtk.main anywhere, Gtk.main_iteration
doesn't work correctly.

Ouch! I can't do that, I don't think. What is the effect if main
never gets called?

In case there are no GUI events, I added a timeout which pumps
the loop.

How about to use Gtk.timeout_add ?

That's what I did, I just didn't want to confuse the issue with too
much code. A bigger snippet of what I'm doing follows:

  device_change = false
  Gtk.timeout_add(500) {
             return true if (@busy)
      device_change = true if checkDevice
             true
         }
         while true
             if device_change
                 processDeviceChange
                 device_change = false
             end
             puts "iteration"
             p Gtk.main_iteration
  end

If the timeout is set to 500 or more, all works well. If I set it to
250 or less, then the GUI doesn't refresh, even though "iteration" is
printed continuously.

Ok, I see what I need to do. Where I call main_iteration, I have to
continue calling it while events_pending?, before looping to check
for a device_change again. That seems to work better! I should've
realised.

The reason I'm doing all this is because I don't want the "process"
to occur in the middle of a flurry of GUI events, but at the end.

If I add an "idle" callback, I'll have the problem that it will chew
CPU. For an app that uses idle not to busy wait, should it call
main_iteration once to block before returning? What I really want is
a method that says "wait until the next event", but I can't see one
inthe documentation.

Also, I moved my Debian installation to "unstable", from "testing",
and I find I now have ruby-gnome2 version 1.13.0, yaay!

P.S.
I think gtk-demo(in Ruby-GNOME2 tar ball) scripts may be helpful.

I'll check that out, thanks.

Clifford Heath.

(Masao Mutoh) #5

Hi,

That's what I did, I just didn't want to confuse the issue with too
much code. A bigger snippet of what I'm doing follows:

  device_change = false
  Gtk.timeout_add(500) {
             return true if (@busy)
      device_change = true if checkDevice
             true
         }
         while true
             if device_change
                 processDeviceChange
                 device_change = false
             end
             puts "iteration"
             p Gtk.main_iteration
  end

Usually, we use Gtk.timeout_add with
Gtk.main something like as:

   Gtk.timeout_add(500) {
            return true if (@busy)
            if checkDevice
                processDeviceChange
            end
            true
        }
        Gtk.main

It's not good idea to make mainloop by yourself.
If you really need it, you need to learn GLib/GTK mainloops
seriously. Though I don't recommand it.

···

On Tue, 16 Aug 2005 08:26:15 +0900 Clifford Heath <no@spam.please.net> wrote:

--
.:% Masao Mutoh<mutoh@highway.ne.jp>

(Clifford Heath) #6

Masao Mutoh wrote:

Usually, we use Gtk.timeout_add with
Gtk.main something like as:

Ok, I considered that, but since the external input will cause
various updates to GUI objects which might not be in a stable
state, I thought it would be better to delay it, which is why
I wrote:

: The reason I'm doing all this is because I don't want the "process"
: to occur in the middle of a flurry of GUI events, but at the end.

It's not good idea to make mainloop by yourself.
If you really need it, you need to learn GLib/GTK mainloops seriously. Though I don't recommand it.

Ok, I believe you. I've built such things before. There should be
a warning like this in the documentation BTW. It'd be good if some
indication of the possible consequences was offered, too.

Thanks for your help.

Clifford Heath.