It is common to have multiple activities simultaneously operating
in the same Lisp process. Furthermore, Lisp programmers tend to
expect a flexible development environment. It must be possible to
load and modify application programs without requiring
modifications to other running programs. CMUCL achieves this by
having a central scheduling mechanism based on an event-driven,
object-oriented paradigm.

An event is some interesting happening
that should cause the Lisp process to wake up and do something.
These events include X events and activity on Unix file
descriptors. The object-oriented mechanism is only available with
the first two, and it is optional with X events as described later
in this chapter. In an X event, the window ID is the object
capability and the X event type is the operation code. The Unix
file descriptor input mechanism simply consists of an association
list of a handler to call when input shows up on a particular file
descriptor.

An object set is a collection of objects that have the
same implementation for each operation. Externally the object is
represented by the object capability and the operation is
represented by the operation code. Within Lisp, the object is
represented by an arbitrary Lisp object, and the implementation for
the operation is represented by an arbitrary Lisp function. The
object set mechanism maintains this translation from the external
to the internal representation.

[Function]system:make-object-setname&optionaldefault-handler

This function makes a new object set. Name is a string used only for purposes of
identifying the object set when it is printed. Default-handler is the function used as a handler
when an undefined operation occurs on an object in the set. You can
define operations with the serve-operation functions exported the extensions package for X events (see
section 7.4). Objects are added
with system:add-xwindow-object. Initially the
object set has no objects and no defined operations.

[Function]system:object-set-operationobject-setoperation-code

This function returns the handler function that is the
implementation of the operation corresponding to operation-code in object-set. When set with setf, the setter function establishes the new handler.
The serve-operation
functions exported from the extensions
package for X events (see section 7.4) call this on behalf of the user when
announcing a new operation for an object set.

[Function]system:add-xwindow-objectwindowobjectobject-set

These functions add port or window to object-set.
Object is an arbitrary Lisp object that
is associated with the port or window capability. Window
is a CLX window. When an event occurs, system:serve-event passes object as an argument to the handler
function.

The system:serve-event function is the
standard way for an application to wait for something to happen.
For example, the Lisp system calls system:serve-event when it wants input from X or a
terminal stream. The idea behind system:serve-event is that it knows the appropriate
action to take when any interesting event happens. If an
application calls system:serve-event when it
is idle, then any other applications with pending events can run.
This allows several applications to run ``at the same time''
without interference, even though there is only one thread of
control. Note that if an application is waiting for input of any
kind, then other applications will get events.

[Function]system:serve-event&optionaltimeout

This function waits for an event to happen and then dispatches to
the correct handler function. If specified, timeout is the number of seconds to wait before
timing out. A time out of zero seconds is legal and causes
system:serve-event to poll for any events
immediately available for processing. system:serve-event returns t if
it serviced at least one event, and nil
otherwise. Depending on the application, when system:serve-event returns t, you
might want to call it repeatedly with a timeout of zero until it
returns nil.

If input is available on any designated file descriptor, then this
calls the appropriate handler function supplied by system:add-fd-handler.

Since events for many different applications may arrive
simultaneously, an application waiting for a specific event must
loop on system:serve-event until the desired
event happens. Since programs such as Hemlock call system:serve-event for input, applications usually do
not need to call system:serve-event at all;
Hemlock allows other application's handlers to run when it goes
into an input wait.

[Function]system:serve-all-events&optionaltimeout

This function is similar to system:serve-event, except it serves all the pending
events rather than just one. It returns t if
it serviced at least one event, and nil
otherwise.

Object sets are not available for use with file descriptors, as
there are only two operations possible on file descriptors: input
and output. Instead, a handler for either input or output can be
registered with system:serve-event for a
specific file descriptor. Whenever any input shows up, or output is
possible on this file descriptor, the function associated with the
handler for that descriptor is funcalled with the descriptor as
it's single argument.

[Function]system:add-fd-handlerfddirectionfunction

This function installs and returns a new handler for the file
descriptor fd. direction can be either :input if the system should invoke the handler when
input is available or :output if the system
should invoke the handler when output is possible. This returns a
unique object representing the handler, and this is a suitable
argument for system:remove-fd-handlerfunction must take one argument, the file
descriptor.

[Function]system:remove-fd-handlerhandler

This function removes handler, that
add-fd-handler must have previously
returned.

[Macro]system:with-fd-handler (fddirectionfunction) {form}*

This macro executes the supplied forms with a handler installed
using fd, direction, and function.
See system:add-fd-handler. The forms are
wrapped in an unwind-protect; the handler is
removed (see system:remove-fd-handler) when
done.

[Function]system:wait-until-fd-usablefddirection&optionaltimeout

This function waits for up to timeout
seconds for fd to become usable for
direction (either :input or :output). If timeout is nil or
unspecified, this waits forever.

[Function]system:invalidate-descriptorfd

This function removes all handlers associated with fd. This should only be used in drastic cases (such
as I/O errors, but not necessarily EOF). Normally, you should use
remove-fd-handler to remove the specific
handler.

Remember from section 7.1, an object set
is a collection of objects, CLX windows in this case, with some set
of operations, event keywords, with corresponding implementations,
the same handler functions. Since X allows multiple display
connections from a given process, you can avoid using object sets
if every window in an application or display connection behaves the
same. If a particular X application on a single display connection
has windows that want to handle certain events differently, then
using object sets is a convenient way to organize this since you
need some way to map the window/event combination to the
appropriate functionality.

The following is a discussion of functions exported from the
extensions package that facilitate handling
CLX events through system:serve-event. The
first two routines are useful regardless of whether you use
system:serve-event:

[Function]ext:open-clx-display&optionalstring

This function parses string for an X
display specification including display and screen numbers.
String defaults to the following:

(cdr (assoc :display ext:*environment-list* :test #'eq))

If any field in the display specification is missing, this signals
an error. ext:open-clx-display returns the
CLX display and screen.

[Function]ext:flush-display-eventsdisplay

This function flushes all the events in display's event queue including the current event,
in case the user calls this from within an event
handler.

Since most applications that use CLX, can avoid the complexity of
object sets, these routines are described in a separate section.
The routines described in the next section that use the object set
mechanism are based on these interfaces.

[Function]ext:enable-clx-event-handlingdisplayhandler

This function causes system:serve-event to
notice when there is input on display's
connection to the X11 server. When this happens, system:serve-event invokes handler on display in a
dynamic context with an error handler bound that flushes all events
from display and returns. By returning,
the error handler declines to handle the error, but it will have
cleared all events; thus, entering the debugger will not result in
infinite errors due to streams that wait via system:serve-event for input. Calling this repeatedly
on the same display establishes
handler as a new handler, replacing any
previous one for display.

[Function]ext:disable-clx-event-handlingdisplay

This function undoes the effect of ext:enable-clx-event-handling.

[Macro]ext:with-clx-event-handling (displayhandler)
{form}*

This macro evaluates each form in a
context where system:serve-event invokes
handler on display whenever there is input on display's connection to the X server. This destroys
any previously established handler for display.

This section discusses the use of object sets and system:serve-event to handle CLX events. This is
necessary when a single X application has distinct windows that
want to handle the same events in different ways. Basically, you
need some way of asking for a given window which way you want to
handle some event because this event is handled differently
depending on the window. Object sets provide this feature.

For each CLX event-key symbol-name iXXX (for example, key-press), there is a function serve-iXXX of two arguments, an object set and a
function. The serve-iXXX function establishes
the function as the handler for the :XXX
event in the object set. Recall from section 7.1, system:add-xwindow-object associates some Lisp object
with a CLX window in an object set. When system:serve-event notices activity on a window, it
calls the function given to ext:enable-clx-event-handling. If this function is
ext:object-set-event-handler, it calls the
function given to serve-iXXX, passing the
object given to system:add-xwindow-object and
the event's slots as well as a couple other arguments described
below.

To use object sets in this way:

Create an object set.

Define some operations on it using the serve-iXXX functions.

Add an object for every window on which you receive requests.
This can be the CLX window itself or some structure more meaningful
to your application.

Call system:serve-event to service an X
event.

[Function]ext:object-set-event-handlerdisplay

This function is a suitable argument to ext:enable-clx-event-handling. The actual event
handlers defined for particular events within a given object set
must take an argument for every slot in the appropriate event. In
addition to the event slots, ext:object-set-event-handler passes the following
arguments:

The object, as established by system:add-xwindow-object, on which the event
occurred.

event-key, see xlib:event-case.

send-event-p, see xlib:event-case.

Describing any ext:serve-event-key-name function, where event-key-name is an event-key symbol-name (for
example, ext:serve-key-press), indicates
exactly what all the arguments are in their correct order.

When creating an object set for use with ext:object-set-event-handler, specify ext:default-clx-event-handler as the default handler
for events in that object set. If no default handler is specified,
and the system invokes the default default handler, it will cause
an error since this function takes arguments suitable for handling
port messages.

This example involves more work, but you get a little more for your
effort. It defines two objects, input-box and
slider, and establishes a :key-press handler for each object, key-pressed and slider-pressed.
We have two object sets because we handle events on the windows
manifesting these objects differently, but the events come over the
same display connection.