home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


14.7 Event Loops

MainLoop executes an event loop that picks up events from the underlying windowing system and dispatches it to the appropriate widgets. When a callback procedure is called in response to an event, it is the responsibility of the callback to return (or "yield") as soon as possible; otherwise, it holds up all events that have since arrived.

For long-running activities that are CPU-intensive, it is your responsibility to chop that activity up into manageable pieces and arrange for a timer to call the processing routine at regular intervals. This gives the event loop a chance to dispatch pending events. This kind of CPU sharing is called cooperative multitasking. Early versions of Microsoft Windows (until Version 3.1) similarly depended on your application being a good citizen; otherwise, it would hang the entire operating system.

For tasks such as ray-tracing and animations that are both CPU- and GUI-intensive, you can use the $widget->update method to process all events. This method doesn't return until all pending event messages (including repaint events) in the event queue have been processed.

Blocking system calls are not a very good idea in an event-driven environment, as we discussed in Chapter 12 . The most common of these are the read and write calls, especially if they are talking to pipes and sockets. For example, the diamond operator ( <> ) blocks until it can get a line of text. Instead of directly calling an I/O call, you must let Perl/Tk tell you that it is safe to use that call, since it won't block. Tk provides a procedure called fileevent that notifies a callback when the file descriptor becomes readable or writable. This is how you use it:

open (F, "/tmp/foo");
$button->fileevent(F, "readable", \&read_file);
sub read_file {
    if (eof(F)) {
        $button->fileevent(F, "readable", undef); # cancel binding
            return ;
    }
    if (sysread (F, $buf, 1024)) {
        $text->insert('end', $buf); # Append the data read
    } else {
        # sysread returned undef. Problem with file
        $text->insert('end', "ERROR !!!"; 
        button->fileevent(F, "readable", undef); # cancel binding
    }
}

When the callback is invoked, Tk (which on Unix uses the select call internally) guarantees that at most one character is ready to be read or written. Beyond that it may or may not block; no assurances are given. The callback is also called if there's an end-of-file or error, so you must check both these conditions. Otherwise, the callback is called again as soon it returns, resulting in an infinite loop. As we discussed in the networking chapters, it is best to use nonblocking I/O if your system supports it.

In this chapter, we have studied widgets, event loops, timers, and event bindings. The next two chapters are designed to pull all these concepts together and to apply them to some practical problems. They also give us a chance to go beyond a mere test run of the two really neat widgets in the Tk pantheon: canvas and text.