Next: , Previous: , Up: A Quick Tour of CLX   [Contents][Index]


2.2.1 A Simple Menu

The example client program creates and displays a simple pop-up menu consisting of a column of strings–a title string followed by selectable menu item strings. The implementation uses one window to represent the entire menu, plus a set of subwindows, one for each menu item. Here is the definition of a structure which represents such a menu.

(defstruct (menu)
  "A simple menu of text strings."
  (title "Choose an item:")
  item-alist				;((item-window item-string))
  window
  gcontext
  width
  title-width
  item-width
  item-height
  (geometry-changed-p t))	     ;nil if unchanged since displayed

The window slot will contain the window (see window) object that represents the menu. The item- alist represents the relationship between the menu items and their associated subwindows. Each entry in item-alist is a list whose first element is a (sub)window object and whose second element is the corresponding item string. A window (see window) object is an instance of a CLX-defined data type which represents X windows. A window (see window) object actually carries two pieces of information: an X window ID integer and a display (see display) object. A display (see display) is another CLX-defined data type that represents a connection to a specific X display server. The gcontext slot contains an instance of a CLX data type known as a graphics context. A graphics context is a set of display attribute values, such as foreground color, fill style, line style, text font, and so forth. Each X graphics request (and hence each CLX graphics function call) must supply a graphics context to use in displaying the request. The menu’s gcontext will thus hold all of the attribute values used during menu display.

The first thing to do is make an instance of a menu object:

(defun create-menu (parent-window text-color background-color text-font)
  (make-menu
   ;; Create menu graphics context
   :gcontext (CREATE-GCONTEXT :drawable   parent-window
			      :foreground text-color
			      :background background-color
			      :font       text-font)

   ;; Create menu window
   :window    (CREATE-WINDOW
	       :parent            parent-window
	       :class             :input-output
	       :x                 0	;temporary value
	       :y                 0	;temporary value
	       :width             16	;temporary value
	       :height            16	;temporary value
	       :border-width 2
	       :border            text-color
	       :background        background-color
	       :save-under        :on
	       :override-redirect :on ;override window mgr when positioning
	       :event-mask        (MAKE-EVENT-MASK :leave-window :exposure))))

create-window (see create-window) is one of the most important CLX functions, since it creates and returns a window (see window) object. Several of its options are shown here. The default window class is :input-output, but X provides for :input-only windows, too. Every window must have a parent window, except for a system-defined root window, which represents an entire display screen. The :event-mask keyword value, a CLX event-mask (see event-mask) data type, says that an input event will be received for the menu window when the window is exposed and also when the pointer cursor leaves the window. The window border is a pattern-filled or (as in this case) a solid-colored boundary which is maintained automatically by the X server; a client cannot draw in a window’s border, since all graphics requests are relative to the origin (upper-left corner) of the window’s interior and are clipped by the server to this inside region. Turning on the :save-under option is a hint to the X server that, when this window is made visible, it may be more efficient to save the pixels it obscures, rather than require several client programs to refresh their windows when the pop-up menu disappears. This is a way to work around X’s client-managed refresh policy when only a small amount of screen space is needed temporarily.

Why is :override-redirect turned on for the menu window? This is actually a little unusual, because it prevents any window manager client from redirecting the position of the menu when it is popped up. Remember that the window manager represents the user’s policy for controlling the positions of his windows, so this kind of redirection is ordinarily correct. However, in this case, as a favor to the user, the menu avoids redirection in order to pop up the menu at a very specific location; that is, under the pointer cursor.

What about the item subwindows? The menu-set-item-list function in the following example creates them whenever the menu’s item list is changed. The upper-left x and y coordinates and the width and height are not important yet, because they are computed just before the menu is displayed. This function also calls create-window (see create-window), demonstrating the equal treatment of parent and children windows in the X window hierarchy.

(defun menu-set-item-list (menu &rest item-strings)
  ;; Assume the new items will change the menu's width and height
  (setf (menu-geometry-changed-p menu) t)

  ;; Destroy any existing item windows
  (dolist (item (menu-item-alist menu))
    (DESTROY-WINDOW (first item)))

  ;; Add (item-window item-string) elements to item-alist
  (setf (menu-item-alist menu)
	(let (alist)
	  (dolist (item item-strings (nreverse alist))
	    (push (list (CREATE-WINDOW
			 :parent       (menu-window menu)
			 :x            0 ;temporary value
			 :y            0 ;temporary value
			 :width        16 ;temporary value
			 :height       16 ;temporary value
			 :background   (GCONTEXT-BACKGROUND (menu-gcontext menu))
			 :event-mask   (MAKE-EVENT-MASK :enter-window
							:leave-window
							:button-press
							:button-release))
			item)
		  alist)))))

Next: , Previous: , Up: A Quick Tour of CLX   [Contents][Index]