The event loop is activated once the Perl/Tk programs MainLoop statement is reached. From that point in time onwards, MainLoop controls our program. As events happen, MainLoop dispatches them to a handler (a callback) for processing, and puts the application to sleep for a short amount of time when the event queue is empty. This repeats until there are no more events from any of the programs MainWindows, at which time MainLoop returns. Any code after the MainLoop statement is then executed. Here is the salient portion of the actual MainLoop subroutine from the Perl/Tk source distribution: use Tk :eventtypes; while (Tk::MainWindow->Count) { DoOneEvent(ALL_EVENTS); } As you see, the Tk main loop processes all events, one by one, until the count of MainWindows becomes zero. The use tag :eventtypes imports various symbols used by DoOneEvent, the subroutine that actually dispatches individual events. For now its sufficient to know that the subroutine expects one argument, a bit pattern, specifying what types of events to process, and whether to return immediately if there are no such events, or to wait. The symbol ALL_EVENTS is the inclusive OR of all the various event types. The individual event types that DoOneEvent recognizes are: WINDOW_EVENTS include things such as keyboard entry, button clicks and window size and visibility changes. FILE_EVENTS deal with reading and writing files and network sockets. TIMER_EVENTS are created by the after and repeat commands. IDLE_EVENTS are low priority callbacks only executed after all events of the previous types have been processed. The most common idle events are those that redraw widgets and refresh the display. You can queue idle callbacks using DoWhenIdle. The :eventtypes tag defines one other symbol, DONT_WAIT, that can be inclusively ORed with a DoOneEvent bit pattern to make the subroutine call non-blocking. Notice that MainLoop does not include DONT_WAIT in its DoOneEvent bit pattern, meaning that DoOneEvent sleeps when there is nothing to do, instead of returning to MainLoop. This is actually a good thing, as it allows other programs running on our computer a slice of the CPU pie. MainLoops job is to dispatch events to callbacks in a timely fashion. As you write callbacks, keep in mind you are in a mutually cooperative environment all callbacks should be brief and non-blocking so the application remains responsive. ################################################################### > IDLE_EVENTS > are low priority callbacks only executed after all events of the > previous types have been processed. The most common idle events are > those that redraw widgets and refresh the display. You can queue idle > callbacks using DoWhenIdle. ################################################################### > Is there a way to selectively update() a certain widget and not > others? No, this is not possible. See also Message-Id: <87sn21mesh.fsf@vran.herceg.de> (in the comp.lang.tcl newsgroup) with a suggestion for a new "display" command for the Canvas widget. Unfortunately, DisplayCanvas is a static method so you can't already use Inline::C or XS to call this function. > I > have an application which is plotting a density map on a canvas, using > thousands of little rectangles. I also have a ProgressBar that I would > like to show me the plotting progress. If I call $progressbar->update then > the whole window gets updated, including the canvas, which slows down the > execution. Ideally, I would like the progressbar to update only, and then > for the canvas to update only when all the plotting is done. > > Is this possible? > > It would be nice if the Canvas had a hidden buffer which we draw to, and > then blit everything in one shot once we're done drawing ... hmmm ... > My solution for this problem is to unpack the canvas, do all the updating along with progressbar changes, and finally re-pack the canvas. ################################################################### >> use Tk :eventtypes; >> >> while (Tk::MainWindow->Count) { >> DoOneEvent(ALL_EVENTS); >> } > ################################################################### Just for kicks, I modified my code such that all the canvas items are hidden (using the brand new, oh-so-useful -state option) as I'm plotting everything to my canvas, and changed back to normal only when everything is done. Doing that, only the progressbar got updated as I wanted, and the execution time was considerably shorter. ################################################################### #for fastest processing sub MainLoop { my ($self) = @_; unless ($Tk::inMainLoop) { local $Tk::inMainLoop = 1; while (Tk::MainWindow->Count) { DoOneEvent(Tk::DONT_WAIT()); my $job=shift(@{$self->{WorkQue}}); if(defined $job){ my($cmd,@args) = @$job; &{$cmd}(@args); } } } } } ####################################################### For an event primer please refer to The Perl Journal #3 (Volume 1, Issue 3, Fall 1996), Events and Other Things. (Old, but not dated). A large (in progress) chapter titled Anontomy of the MainLoop will bring things up-to-date. This is a difficult arena to come to grasp with, but, essentially, as Marc noted, MainLoop{} looks like this: while (we have 1 or more MainWindows active) { DoOneEvent(but don't block) } DoOneEvent() looks for events in the various Tk event queues and executes them - events are things like button clicks, timers, file I/O, etcetera. There are also low-priority idle events handled after all the important events are cleared. > I just did a little experiment, and I think this will set you > in the right direction: > > use strict; > use Tk qw/tkinit DoOneEvent exit DONT_WAIT ALL_EVENTS/; You can also do: use Tk qw/:eventtypes/; to import all the good event stuff, including these event "bit masks", which can be inclusively ORed together to specify what events to process. DONT_WAIT return immediately if no events - DO NOT BLOCK WINDOW_EVENTS X11 keyboard/mouse events FILE_EVENTS file I/O events TIMER_EVENTS repeat/after, etc. IDLE_EVENTS low priority events ALL_EVENTS all of the above Quoting the Pocket Ref: When passed ALL_EVENTS DoOneEvent() processes events as they arise, and puts the application to sleep when no further events are outstanding. It first looks for an X or I/O event and, if found, calls the handler and returns. If there is no X or I/O event, it looks for a single timer event, invokes the callback, and returns. If no X, I/O or timer event is ready, all pending idle callbacks are executed, if any. In all cases DoOneEvent() returns 1. When passed DONT_WAIT, DoOneEvent() works as above except that it returns immediately with a value of 0 if there are no events to process. > > my $mw = tkinit; > $mw->Button( > -text => 'Test', > -command => sub {print "Pushed\n"}, > )->pack(); > $mw->Button( > -text => 'Quit', > -command => sub {Tk::exit(0)}, > )->pack(); > > my $I; > while (1) { > $mw->DoOneEvent(DONT_WAIT|ALL_EVENTS); > if (++$I > 1000) { > print '.'; > $I = 0; > } > } > > -- > Marc Dashevsky (remove "_" from address to reply by e-mail) So, for X10 home automation programming, you need two basic ingredients: 1) a non-blocking way to process X10 events. So, basically, be able to send an all-lights-on w/o blocking, or poll (w/o blocking) to determine if A10 in On or off (e.g.). 2) a non-blocking way to process perl/Tk events - DoOneEvent. Something like this: while (my $stat = $mw->DoOneEvent( DONT_WAIT | ALL_EVENTS )){} sprinkled throughout your code might work, but that's just really this in disguise: $mw->update; You can balance which events get priority by using an event mask, but make sure you process idle event occasionally else the display will never updated. So your "mainloop" might be: while ( 1 ) { &process_x10_event; $mw->DoOneEvent(blah); # or simply $mw->update() might suffice } You should check out the X10 codes on CPAN, as well as (I think) Mister House, which, when I discovered it, caused me to drop my Perk/Tk X10 project because it was so good!