40.4.5 Servicing Tcl and Tk events

The notion of an event in the Prolog+Tcl/Tk system is overloaded. We have already come across the following kinds of events:

It is further about to be overloaded with the notion of Tcl/Tk events. It is possible to create event handlers in Tcl/Tk for reacting to other kinds of events. We will not cover them here but describe them so that the library functions are understandable and in case the user needs these features in an advanced application.

There are the following kinds of Tcl/Tk events:

idle events
happen when the Tcl/Tk system is idle
file events
happen when input arrives on a file handle that has a file event handler attached to it
timer events
happen when a Tcl/Tk timer times out
window events
when something happens to a Tk window, such as being resized or destroyed

The problem is that in advanced Tcl/Tk applications it is possible to create event handlers for each of these kinds of event, but they are not normally serviced while in Prolog code. This can result in unresponsive behavior in the application; for example, if window events are not serviced regularly then if the user tries to resize a Tk window, it will not resize in a timely fashion.

The solution to this is to introduce a Prolog predicate that passes control to Tk for a while so that it can process its events, tk_do_one_event/[0,1]. If an application is unresponsive because it is spending a lot of time in Prolog and is not servicing Tk events often enough, then critical sections of the Prolog code can be sprinkled with calls to tk_do_one_event/[0,1] to alleviate the problem.

tk_do_one_event/[0,1] has the following forms:

     tk_do_one_event
     tk_do_one_event(+ListOrBitMask)

which passes control to Tk to handle a single event before passing control back to Prolog. The type of events handled is passed through the ListOrBitMask variable. As indicated, this is either a list of atoms that are event types, or a bit mask as specified in the Tcl/Tk documentation. (The bit mask should be avoided for portability between Tcl/Tk versions.)

The ListOrBitMask list can contain the following atoms:

tk_dont_wait
don't wait for new events, process only those that are ready
tk_x_events
tk_window_events
process window events
tk_file_events
process file events
tk_timer_events
process timer events
tk_idle_events
process Tk_DoWhenIdle events
tk_all_events
process any event

Calling tk_do_one_event/0 is equivalent to a call to tk_do_one_event/1 with all flags set.

A call to either of these predicates succeeds only if an event of the appropriate type happens in the Tcl/Tk interpreter. If there are no such events, then tk_do_one_event/1 will fail if the tk_dont_wait wait flag is present, as will tk_do_one_event/0, which has that flag set implicitly.

If the tk_dont_wait flag is not set, then a call to tk_do_one_event/1 will block until an appropriate Tk event happens (in which case it will succeed).

It is straight forward to define a predicate that handles all Tk events and then returns:

     tk_do_all_events :-
         tk_do_one_event, !,
         tk_do_all_events.
     tk_do_all_events.

The predicate tk_next_event/[2,3] is similar to tk_do_one_event/[0,1] except that it processes Tk events until at least one Prolog event happens. (We came across this predicate before when discussing Prolog event queue predicates. This shows the overloading of the notion event where we have a predicate that handles both Tcl/Tk events and Prolog queue events.)

It has the following forms:

     tk_next_event(+TclInterpreter, -Event)
     tk_next_event(+ListOrBitMask, +TclInterpreter, -Event)

The Prolog event is returned in the variable Event and is the first term on the Prolog event queue associated with the interpreter TclInterpreter. (Prolog events are initiated on the Tcl side through the new Tcl command prolog_event, covered earlier; see prolog_event).