Re: Run menu action in background




On Jan 11, 2007, at 10:26 AM, Philipp E. Letschert wrote:

On Wed, Jan 10, 2007 at 10:51:26PM -0500, muppet wrote:

On Jan 10, 2007, at 8:36 PM, Philipp E. Letschert wrote:

I have a subroutine connected to a popup menu item. When that routine is finished a new popup window displays the result. Sometimes the routine takes longer to finish and during that time the popup menu stays visible.

How can I run the subroutine in background and have the popup menu disappear
right after activating the menu item?

Have your menu item handler install an idle action that starts the dialog box. That is:

1  user activates menu item
2  menu handler is called
3  menu handler does Glib::Idle->add (\&do_the_thing);
4  menu handler finishes, menu disappears
5  control returns to main loop
6  main loop sees that there is a pending idle action
7  do_the_thing() fires
8  do_the_thing() launches your dialog box

In essence, it's just a layer of indirection to defer running the
dialog box until "sometime later".

Thanks, partial success. The menu disappears as requested, but when step 7 is reached, the main window freezes until do_the_thing() finishes. It would be great if the user could continue using the application normally during the subroutine runs (and queue additional calls to that subroutine...).

Aha... i apologize, for i misread your question. You have a step 7.5, "do_the_thing() performs long operation", which makes this a different situation altogether.

The main window is "Freezing" because you're not handling events in the event loop during your long operation.

There are three basic fixes for this:

a) Break the operation into small chunks, place them in a work queue, and process the queue in idle handlers.

b) Create a thread to handle the work.

c) Fork a child process to handle the work.

Option a) is desirable if the thing your doing is easily broken up, but can be a lot of work and bookkeeping. Option b) is all the rage with people coming from Java backgrounds, but threads and perl and gtk + are a delicate mixture that often blows up in your face. Option c) is much easier and more robust than option c), giving you the same benefit with less work.

Option c) is basically the same as the "How do I keep my GUI updating during a long file read?" question in the gtk2-perl FAQ.


To do this, you don't actually need your idle handler, but you'll use an IO watch, instead:

1.  user activates menu item
2.  menu handler fires
3. menu handler does a pipe-open to fork a child process: $pid = open($fh, "-|") This gives you $fh to communicate between the processes. 3.1 In the parent, set up an IO watch to monitor the stdout of the child. Glib::IO->add_watch (fileno($fh), ['in', 'hup'], \&child_io); The watch routine will watch for special messages from the child and can do stuff like update progress indicators, and show a dialog box summarizing the results when the child hangs up. 3.2 In the child, do the work, emitting status to stdout. Most important, emit a message when the work is finished! Then exit().

Of course, you can keep the idle indirection from the previous discussion if you like -- it won't hurt anything, and keeps the menu decoupled from the rest of this code.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]