Next: The Main Program, Previous: Displaying the Menu, Up: A Quick Tour of CLX [Contents][Index]
Now that a menu can be displayed, the sample client program must define
how the menu will process user input. The menu-choose
function (shown in the following example) has the classic structure of
an X client program. First, do some initialization (for example, present
the menu at a given location). Then, enter an input event loop. Read an
input event, process it, and repeat the loop until a termination event
is received. The
event-case (see event-case)
macro continues reading an event from the menu window’s display object
until one of its clauses returns non-nil. These clauses specify
the action to be taken for each event type and also bind values from the
event report to local variables, such as the event-window
receiving the event. Notice that the :force-output-p option is
enabled, causing
event-case (see event-case)
to begin by sending any client requests which CLX has not yet output to
the server. To improve performance, CLX quietly queues up requests and
periodically sends them off in a batch. However, in an interactive
feedback loop such as this, it is important to keep the display crisply
up-to-date.
(defun menu-choose (menu x y) ;; Display the menu so that first item is at x,y. (menu-present menu x y) (let ((items (menu-item-alist menu)) (mw (menu-window menu)) selected-item) ;; Event processing loop (do () (selected-item) (EVENT-CASE ((DRAWABLE-DISPLAY mw) :force-output-p t) (:exposure (count) ;; Discard all but final :exposure then display the menu (when (zerop count) (menu-refresh menu)) t) (:button-release (event-window) ;;Select an item (setf selected-item (second (assoc event-window items))) t) (:enter-notify (window) ;;Highlight an item (menu-highlight-item menu (find window items :key #'first)) t) (:leave-notify (window kind) (if (eql mw window) ;; Quit if pointer moved out of main menu window (setf selected-item (when (eq kind :ancestor) :none)) ;; Otherwise, unhighlight the item window left (menu-unhighlight-item menu (find window items :key #'first))) t) (otherwise () ;;Ignore and discard any other event t))) ;; Erase the menu (UNMAP-WINDOW mw) ;; Return selected item string, if any (unless (eq selected-item :none) selected-item)))
The event loop in menu-choose
demonstrates an idiom used in
all X programs: the contents of a window are displayed (in this case, by
calling menu-refresh
) only when an
:exposure (see exposure)
event is received, signaling that the server has actually made the
window viewable. The handling of
:exposure (see exposure)
in menu-choose
also implements a little trick for improving
efficiency. In general, when a window is exposed after being previously
obscured (perhaps only partially), the server is free to send several
:exposure (see exposure)
events, one for each rectangular tile of the exposed region. For small
windows like this menu, it is not worth the trouble to redraw the image
one tile at a time. So the code above just ignores all but the last tile
exposure and redraws everything in one call to
menu-refresh
.
Next: The Main Program, Previous: Displaying the Menu, Up: A Quick Tour of CLX [Contents][Index]