Chapter 8. Events

This chapter is another must-read. Events are central to X. The fundamental framework for handling events was given in Chapter 3, but this chapter gives much more detail, both on selecting events for a window and on handling them when they arrive. It discusses each of the masks used to select events; for a description of the event structures themselves, see Appendix E.

An event, to quote the Oxford English Dictionary, is an “incident of importance” or a “consequence, result, or outcome.” This definition holds for X. An event reports some device activity or is generated as a side effect of an Xlib routine.

From a programmer's point of view, an event reports:

Programming with events is quite different from traditional methods of programming for input. You cannot simply wait for a user to type something and expect nothing else to happen in the meantime. Other programs are running concurrently and sharing the same system resources including the screen. They can affect your program. What happens if another window is placed over yours in the middle of the instruction your user is typing? The program must be able to listen to several types of events at once and jump back and forth when acting on them. Events imply a philosophy that the program should respond to the user's actions, not the other way around. Events make this type of programming straightforward.

Events occur asynchronously and get queued for each client that requested them. It is possible for more than one client to get copies of the same event. Usually a program handles each one in turn and performs the appropriate action before reading the next one. But there is usually no way for a program to predict in what order it will find the events on the queue.

This chapter covers events in detail, going further than the introduction to events in Chapter 2, “X Concepts” Here we discuss the event union and structure types, the selection and propagation of events, how each event type is usually used, how events are received and handled in a program, and how they are sent by one client to another.

After you have read and understood this chapter, see Chapter 9, “The Keyboard and Pointer” which demonstrates how to use events to handle the user's input, and Appendix E, Event Reference, which describes all the event types in a reference format.

Overview of Event Handling

There are three important steps in a program's handling of events. First, the program selects the events it wants for each window. Then it maps the windows. Finally, it provides an event loop which reads events from the event queue as they occur.

This process is quite simple, the only complication being the variety of events that may occur, each perhaps having a different meaning when it occurs in a different window. You have to know every circumstance in which a particular event is generated and make sure that your program does the right thing with it. But you will not need to understand the details of every event in order to begin using the most important ones.

The easiest way to select events is to call XSelectInput() for each window that you want to receive events. You can also set the event_mask attribute directly with XChangeWindowAttributes() or XCreateWindow(). You specify a mask which specifies which event types you want, combining any number of the event mask symbols with the bitwise OR operator (|).

You must make sure that every window that is to receive events appears on the screen after the events are selected for that window but before the event loop begins. Otherwise, the client will miss the first Expose event that triggers the drawing of the window's contents. For top-level windows, the client might also miss the ConfigureNotify event that reports the size of the window granted by the window manager. For a window to appear on the screen, it must be mapped and all its ancestors must be mapped. It is permissible to map all the windows except the top-level ones at any time, but the mapping of children of the root window must be done between the XSelectInput() call and the routine that gets events for the event loop.

A simple event loop was shown in Chapter 3, “Basic Window Program” The only difference between this loop and the loops in real clients is in the number of different event types handled and the complexity of each branch.

Even though selection of events must be done first, we are going to start by describing how to handle events once you have them, because there are fewer details involved. We will return to the exact procedure for selecting events and the meaning of each event mask symbol in “Selecting Events”

Event Processing

This section describes what an event type is and what an event structure contains, reviews how the event queue stores events and how a program reads events from it, and summarizes all the routines that can be used to get events.

The Event Structures

An event is implemented as a packet of information stored in a structure. The simplest event structure is shown in Example 8-1.

Example 8-1. The XAnyEvent structure

typedef struct {
   int type;               /* The type of event */
   unsigned long serial;   /* # of last request processed by server */
   Bool send_event;        /* True if sent from a SendEvent request */
   Display *display;       /* Display the event was read from */
   Window window;          /* Window that receives event */
} XAnyEvent;

There are 30 different event structures. Virtually all of them have the members shown in the XAnyEvent structure. Most of the event structures also contain various additional members that provide useful information for clients. The first member of every event structure, type, indicates the type of event. We will come back to the type in “Event Types and XEvent Union” The serial member identifies the last protocol request processed by the server, for use in debugging. The send_event flag indicates whether this event was sent from the server (False) or from another client (True). Other clients can send events with XSendEvent(), as described in “Sending Events”

Many of the event structures also have a display member or a root member or both. The display member identifies the connection to the server that this event came from. (Some applications connect with more than one server.) The root member indicates the screen on which the event occurred (a server may control more than one screen). Most programs only use a single screen and therefore do not need to worry about the root member. The display member can be useful for passing the display variable into routines by simply passing a pointer to the event structure.

Most event structures also have a window member, which indicates the window that selected and received the event. This is the window where the event arrives if it is a keyboard or pointer event and has propagated through the hierarchy, as described in “Propagation of Device Events” One event type may have two different meanings to a client, depending on which window the event appears in.

Event Types and XEvent Union

All the event structures are padded when necessary to be the same size. The XEvent union contains all the event structures, as shown in Example 8-2. [24] The first member of the XEvent union is the type of event. Each event structure within the XEvent union also begins with the type of event. A client determines the type of event by looking at the type member of XEvent. Then the client branches to specific code for that event type. After the initial determination of the event type, only the event structure containing the specific information for each event type should be used in each branch. For example, assuming you have declared an XEvent variable called report, the report.xexpose structure should be used within the branch for Expose events. This lets you use the fields unique to the Expose event structure.

The value of type is any one of the constants listed in the center column of Table 8-3, presented later in this chapter. After determining the event type, you know which event structure from the XEvent union contains specific information about the event. You can then use the appropriate event structure name, such as xkey, to access the specific information unique to that event structure. The event structure name is also shown on each event reference page in Appendix E, Event Reference.

Example 8-2. The XEvent union

typedef union _XEvent {
   int type;         /* Must not be changed; first member */
   XAnyEvent xany;
   XKeyEvent xkey;
   XButtonEvent xbutton;
   XMotionEvent xmotion;
   XCrossingEvent xcrossing;
   XFocusChangeEvent xfocus;
   XKeymapEvent xkeymap;
   XExposeEvent xexpose;
   XNoExposeEvent xnoexpose;
   XGraphicsExposeEvent xgraphicsexpose;
   XVisibilityEvent xvisibility;
   XCreateWindowEvent xcreatewindow;
   XDestroyWindowEvent xdestroywindow;
   XUnmapEvent xunmap;
   XMapEvent xmap;
   XMappingEvent xmapping;
   XMapRequestEvent xmaprequest;
   XReparentEvent xreparent;
   XConfigureEvent xconfigure;
   XGravityEvent xgravity;
   XResizeRequestEvent xresizerequest;
   XConfigureRequestEvent xconfigurerequest;
   XCirculateEvent xcirculate;
   XCirculateRequestEvent xcirculaterequest;
   XPropertyEvent xproperty;
   XSelectionClearEvent xselectionclear;
   XSelectionRequestEvent xselectionrequest;
   XSelectionEvent xselection;
   XColormapEvent xcolormap;
   XClientMessageEvent xclient;
} XEvent;


Xlib's Event Queue

The event structures are placed on an event queue in the order they occur, so that the program can read them and act accordingly. As shown in Figure 8-1, the server maintains one event queue, on which all events are placed, and distributes events to the Xlib in each client. The events in the server's queue are periodically transferred over the network to the Xlib queues. Two clients can receive copies of the same events if they each select them.

Figure 8-1. The server's event queue and client's event queue

The client sets up an event-receiving loop to handle the events that arrive on its event queue. There are several routines a client can use to get events. They differ in how many windows they monitor, how many types of events they look for, and whether they wait for events to appear before returning. For a description of the event-getting routines, see “Routines that Get Events”

Writing the Event Loop

In basicwin (the example program in Chapter 3, “Basic Window Program”), you have already seen the structure of the code you should write to handle events. In a more complex application, the code for each event type will simply be divided according to the values in the members in each event structure. Usually, the next branch after the event type will test the window in which the event occurred.

The branch for Expose events in Example 8-3 demonstrates how an event might be handled when there are several windows involved. The example also notes when each of the selected events--and the events that may be delivered without your selecting them--should be handled within your event loop. Depending on your application, other events might need to be handled as well.

Notice how the specific event structure names such as xexpose are used to access information in the event structures.

Example 8-3. An event-handling loop

XEvent report;
Window window1, window2, window3;
   .
   .
   .
/* Open display, create windows, etc. */
/* Window 1 is a top-level window, window 2 is a child
 * of window 1 */
XSelectInput(display, window1, StructureNotifyMask | ExposureMask
      | ButtonPressMask);
XSelectInput(display, window2, ExposureMask);
XSelectInput(display, window3, ExposureMask);
XMapWindow(display, window1);
XMapWindow(display, window2);
XMapWindow(display, window3);
/* Get events, use first to display text and graphics */
while (1)
{
   /* Get any type of event on any window; this gets
    * events on every window for which we have selected
    * events (three in this case) */
   XNextEvent(display, &report);
   switch (report.type)  {
   case Expose:
      printf("got an Expose event\n");
      /* Redraw contents of windows; note that we can't
       * use switch because window IDs are not constant */
      if (report.xexpose.window == window1)
         /* Redraw window 1 */;
      else if (report.xexpose.window == window2)
         /* Redraw window 2 */;
      else (report.xexpose.window == window3)
         /* Redraw window 3 */;
      break;
   case ButtonPress:
      printf("got a ButtonPress event\n");
      /* Respond to buttonpress, probably depending on
       * which window is reported in report.xbutton.window */
      break;
   case ConfigureNotify:
      printf("got a ConfigureNotify event\n");
      /* Window was resized, moved, or restacked or border
       * width was changed; reset application variables
       * so Expose branch will scale graphics properly */
      break;
   case MappingNotify:
      printf("got a MappingNotify event\n");
      /* Keyboard or Pointer mapping was changed by another
       * client; if keyboard, should call XRefreshKeyboardMapping,
       * unless keyboard events are not used */
      break;
   case ClientMessage:
      printf("got a ClientMessage event\n");
      /* Primarily used for transferring selection data,
       * also might be used in a private interclient
       * protocol; otherwise, not needed in event loop */
      break;
   case SelectionClear:
      printf("got a SelectionClear event\n");
      /* If this application previously called
       * XSetSelectionOwner, it may get this event;
       * otherwise, you don't need it in your
       * event loop */
      break;
   case SelectionNotify:
      printf("got a SelectionNotify event\n");
      /* If this application calls XConvertSelection,
       * it will get this event; otherwise, you don't
       * need it in your event loop */
      break;
   case SelectionRequest:
      printf("got a SelectionRequest event\n");
      /* If this application previously called
       * XSetSelectionOwner, it may get this event;
       * otherwise, you don't need it in your
       * event loop */
      break;
   case GraphicsExpose:
      /* Fall through into NoExpose */
   case NoExpose:
      printf("got a GraphicsExpose or NoExpose event\n");
      /* If this application calls XCopyArea or XCopyPlane
       * and the graphics_exposures member of the GC is
       * True and the source is a window, these events may
       * be generated; handle GraphicsExpose like Expose */
   default:
      printf("Event being thrown away\n");
      /* All *Notify events except ConfigureNotify will
       * be thrown away; they are not needed by most
       * applications but are sent because ConfigureNotify
       * can't be selected independently */
      break;
   }  /* End switch on event type */
} /* End while (1) */

The XNextEvent() routine gets the next event on the queue for our client or waits until one appears before returning. There are many other routines that get events of particular types, in particular windows, with or without waiting for the event to appear. These routines are described in “Routines that Get Events”

The first member of the XEvent report contains the type of event. This information is used in a “switch” statement to branch according to the event type. Once the type is known, the specific event structure is known, and its contents can be accessed. For example, the width of the exposed area in the window is contained in the XExposeEvent structure as report.xexpose.width, where report is the XEvent variable, xexpose is the member of the XEvent union, and width is a member of the XExposeEvent structure type.

Printing the Event Type

We recommend that you print the event type and perhaps other event information in each branch of the event loop while you are in the application debugging stage. Be very careful that the loop handles all the events that can occur and that the Xlib routine you choose to get events is capable of getting all the events you need. If your program hangs and cannot be interrupted with CTRL-C, it is probably waiting for an event that you did not select. For example, you may have called XMaskEvent() with a mask of ButtonReleaseMask but you did not select ButtonReleaseMask in the XSelectEvent() call. The event-getting routines do not check to make sure you have selected the events you are requesting.

Instead of printing the event type as a number which you then have to interpret using the <X11/X.h> include file, you can have your program print the real name of the event. Example 8-4 creates an include file containing an array of strings spelling out the event type names. Example 8-5 then prints the correct event name.

Example 8-4. An include file for printing the event type -- eventnames.h

static char *event_names[] = {
   "",
   "",
   "KeyPress",
   "KeyRelease",
   "ButtonPress",
   "ButtonRelease",
   "MotionNotify",
   "EnterNotify",
   "LeaveNotify",
   "FocusIn",
   "FocusOut",
   "KeymapNotify",
   "Expose",
   "GraphicsExpose",
   "NoExpose",
   "VisibilityNotify",
   "CreateNotify",
   "DestroyNotify",
   "UnmapNotify",
   "MapNotify",
   "MapRequest",
   "ReparentNotify",
   "ConfigureNotify",
   "ConfigureRequest",
   "GravityNotify",
   "ResizeRequest",
   "CirculateNotify",
   "CirculateRequest",
   "PropertyNotify",
   "SelectionClear",
   "SelectionRequest",
   "SelectionNotify",
   "ColormapNotify",
   "ClientMessage",
   "MappingNotify"
};

Note that eventnames.h is not a standard include file but one we have written for the purpose of printing the event type more legibly. You could use a similar method to identify windows, but since their IDs are not constants, you would need to load the array dynamically after you have created the windows.

Example 8-5 demonstrates printing an event using the include file shown in Example 8-4.

Example 8-5. Printing the event type

#ifdef DEBUG
#include "eventnames.h"
#endif
XEvent event;
XNextEvent(display, &event);
#ifdef DEBUG
fprintf(stderr, "winman: got a %s event\n", event_name[event.type]);
#endif


Routines that Get Events

There are several functions that get event structures from the queue. They differ in the following respects:

  • The number of windows they monitor (whether they inspect the window member).

  • Whether they look for particular event types.

  • Whether the event is removed from the queue when it is read.

  • Whether a routine you write is used to determine whether the event should be returned.

  • Whether Xlib waits until an event meeting the criteria arrives or immediately returns a success or failure code.

  • Whether the connection to the server is flushed to see if any more events become available.

The following is a list of the event-handling routines and their differences. In all of these routines, you pass a pointer to an XEvent structure to be filled.

XNextEvent() 

Gets the next event of any type on any window. This function flushes the request buffer if Xlib's queue does not contain an event and waits for an event to arrive from the server connection.

XMaskEvent() 

Gets the next event matching the specified mask on any window. This function flushes the request buffer if Xlib's queue does not contain a matching event and waits for a matching event to arrive from the server connection.

XCheckMaskEvent() 

Behaves like XMaskEvent() but immediately returns False if there is no matching event in Xlib's queue and none could be read from the server connection after flushing the request buffer. Returns True if a matching event was found.

XWindowEvent() 

Gets the next event matching both the specified mask and the specified window. This function flushes the request buffer if Xlib's queue does not contain a matching event and waits for a matching event to arrive from the server connection.

XCheckWindowEvent() 

Behaves like XWindowEvent but immediately returns False if there is no matching event in Xlib's queue and none could be read from the server connection after flushing the request buffer. Returns True if a matching event was found.

XIfEvent() 

Looks for an event on the queue that matches the conditions set by a user-supplied predicate procedure. This function flushes the request buffer if Xlib's queue does not contain a matching event and waits for a matching event to arrive from the server connection.

XCheckIfEvent() 

Behaves like XIfEvent() but immediately returns False if there is no matching event in Xlib's queue and none could be read from the server connection after flushing the request buffer. Returns True if a matching event was found.

XPeekEvent() 

Gets the next event of any type from any window without removing the event from the queue. This function flushes the request buffer if Xlib's queue is empty and waits for an event to arrive from the server connection.

XPeekIfEvent() 

Gets the next event that matches the specified predicate procedure, without removing the event from the queue. This function flushes the request buffer if Xlib's queue does not contain a matching event and waits for a matching event to arrive from the server connection.

XCheckTypedEvent() 

Searches the queue from the oldest event for the desired event type, without discarding all those searched that do not match. If no matching event is found in Xlib's queue, this function flushes the request buffer and returns False.

XCheckTypedWindowEvent() 

Searches the queue from the oldest event for the desired window and event type, without discarding those searched that do not match. If no matching event is found in Xlib's queue, this function flushes the request buffer and returns False.

XEventsQueued() 

Returns the number of events on the queue but has three modes that specify what else is done. All three modes count the events already in Xlib's queue and return if there are any. QueuedAlready returns even if there are not any events in the queue. QueuedAfterFlush flushes the request buffer and attempts to read more events from the connection before returning. QueuedAfterReading attempts to read more events from the connection without flushing the buffer.

XPending() 

Returns the number of events on the queue. If there are none, it flushes the request buffer and tries another count. This is identical to XEventsQueued() with mode QueuedAfterFlush.

XPutBackEvent() 

Puts an event you supply back on Xlib's queue, so that it will be the next to be received by XNextEvent().

XGetMotionEvents() 

Gets all the motion events that occurred on the specified window in a specified time period. Motion history buffers were implemented for the first time in the R5 sample servers from MIT. An application should check to see if XDisplayMotionBufferSize(display) == 0, which indicates that motion history buffer is not supported.

XQLength() 

Returns the number of events on the queue, without flushing the request buffer.

Note that the functions that have mask arguments do not return non-maskable events (MappingNotify, Selection events, and ClientMessage).

You may notice that there are two broad categories of routines that get input: those that wait for a matching event and those that do not wait. The latter may be used in porting applications that use the “polling” style of programming, which checks to see if input has arrived at regular intervals by continuously calling a “polling” function in a loop. Given the choice, however, it is much better to use the routines that wait for events as much as possible, since this technique does not waste processor cycles. This is true event-driven programming.

Table 8-1 organizes the event-receiving functions according to whether they wait for events if none are present on Xlib's queue.

Table 8-1. Event-getting Routines

Event Specifications

Desired Result:Wait if necessary

Desired Result:Return False immediately if none queued

Desired Result:Leave in queue (may wait)

Any event

XNextEvent

n/a

XPeekEvent

With predicate

XIfEvent

XCheckIfEvent

XPeekIfEvent

For window

XWindowEvent

XCheckWindowEvent

n/a

For event mask

XMaskEvent

XCheckMaskEvent

n/a

For type

n/a

XCheckTypedEvent

n/a

For window and type

n/a

XCheckTypedWindowEvent

n/a

Note that most of the routines apparently missing from Xlib according to Table 8-1 can be simulated with other routines and fairly simple code. The hole on the top row can be filled by calling XCheckMaskEvent() with a mask set to all 1's. For the four routines missing in the last column, you can write a predicate procedure and call XPeekIfEvent(). An example predicate procedure is shown in Example 8-6. The two routines missing in the first column can also be replaced with a predicate procedure and XIfEvent().

The event-getting routines with Check in their names are useful for programs that need to poll for input to handle interrupts. To illustrate the handling of interrupts, let's say you have a routine in a program that performs a complex, lengthy calculation like a Fourier transform. You want to be able to abort the calculation midway. Therefore, you need to be able to check the keyboard to see if a CTRL-C or other interrupt character has been typed. You also might want to provide for exposure events during the long wait, though you might be able to get away without this provision. This would be a good application for XCheckTypedEvent() or XCheckTypedWindowEvent(), since these routines poll without waiting if no events can be read. When an event does arrive, you can decide from the type or window whether to bother processing it.

Predicate Procedures

The routines XCheckIfEvent(), XIfEvent(), and XPeekIfEvent() allow you to supply a procedure that returns True or False depending on some characteristic of the event. You would use one of these routines if you have a matching algorithm that is complicated or simply to enable you to clear up the code by putting some of the event processing in a separate routine.

Your predicate procedure is called with the same arguments as the event-getting routine (except for the predicate procedure pointer, of course). Example 8-6 shows a predicate procedure and the XIfEvent() call that uses it. This code would normally use XNextEvent(), but we have substituted XIfEvent() so that we can filter out button events on buttons other than button 1. This predicate procedure returns True for all events except the undesirable button events.

Example 8-6. A predicate procedure and XIfEvent() call

void main(argc, argv)
int argc;
char **argv;
{
     .
     .
     .
        Bool predproc();
        static char *stuff = "do this or that";
     .
     .
     .
        XSelectInput(display, wint, ExposureMask | ButtonPressMask
         | ButtonReleaseMask | ButtonMotionMask
         | PointerMotionHintMask);
     .
     .
     .
        while (1)  {
                XIfEvent(display, &report, predproc, stuff);
                switch  (report.type) {
      /* Note that no code here for eliminating button
       * events on other buttons, because only button
       * one events are returned by XIfEvent */
                case ButtonPress:
                        points[index].x = report.xbutton.x;
                        points[index].y = report.xbutton.y;
                        break;
                case ButtonRelease:
                        index++;
                        points[index].x = report.xbutton.x;
                        points[index].y = report.xbutton.y;
                        break;
                     .
                     .
                     .
      }
   }
}
Bool predproc(display, event, arg)
Display *display;
XEvent *event;
char *arg;
{
        printf("The arg is %s\n", arg);
        switch (event->type) {
                case Expose:
                case MotionNotify:
                case ConfigureNotify:
                case KeyPress:
                        return(True);
                        break;
                case ButtonPress:
                case ButtonRelease:
                        if (event->xbutton.button == Button1)
                                return(True);
                        else
                                return(False);
                        break;
                default:
        }
}


Selecting Events

For each window, a client must select which event types it wants placed in its queue when they occur in that window. This is normally done with XSelectInput(), which sets the event_mask attribute of a window. The client need not select events on all of its windows, only those in which it wants to see the events that occur.

To select event types for a window, pass an event_mask as an argument to XSelectInput() or set the event_mask member of the XSetWindowAttributes structure and call XChangeWindowAttributes() or XCreateWindow(). (For more information on the XSetWindowAttributes structure, see “Setting Window Attributes” in Chapter 4)

The event_mask is formed by combining the event mask symbols listed in the first column of Table 8-2 with the bitwise OR operator (|). Each mask symbol sets a bit in the event_mask.

Table 8-2 also describes briefly the circumstances under which you would want to specify each symbol. You will need to read about each mask in “Event Masks”; see the examples using the events in Chapter 9, “The Keyboard and Pointer” and throughout this manual; and look at the event structures in Appendix E, Event Reference, before you will really understand when to use each of these symbols.

Table 8-2. Event Mask Definitions

Event Mask Symbol

Circumstances

NoEventMask

No events

KeyPressMask

Keyboard down events

KeyReleaseMask

Keyboard up events

ButtonPressMask

Pointer button down events

ButtonReleaseMask

Pointer button up events

EnterWindowMask

Pointer window entry events

LeaveWindowMask

Pointer window leave events

PointerMotionMask

All pointer motion events

PointerMotionHintMask

Fewer pointer motion events

Button1MotionMask

Pointer motion while button 1 down

Button2MotionMask

Pointer motion while button 2 down

Button3MotionMask

Pointer motion while button 3 down

Button4MotionMask

Pointer motion while button 4 down

Button5MotionMask

Pointer motion while button 5 down

ButtonMotionMask

Pointer motion while any button down

KeymapStateMask

Any keyboard state change on EnterNotify , LeaveNotify , FocusIn or FocusOut

ExposureMask

Any exposure (except GraphicsExpose and NoExpose )

VisibilityChangeMask

Any change in visibility

StructureNotifyMask

Any change in window configuration.

ResizeRedirectMask

Redirect resize of this window

SubstructureNotifyMask

Notify about reconfiguration of children

SubstructureRedirectMask

Redirect reconfiguration of children

FocusChangeMask

Any change in keyboard focus

PropertyChangeMask

Any change in property

ColormapChangeMask

Any change in colormap

OwnerGrabButtonMask

Modifies handling of pointer events


The do_not_propagate_mask window attribute is formed in the same way as event_mask but can only be set with XChangeWindowAttributes() or XCreateWindow(). Its function is described in “Propagation of Device Events”

Example 8-7 shows how to set the event_mask and call XSelectInput().

Example 8-7. An example of selecting input

Display display;
Window window;
unsigned long event_mask;
   .
   .
   .
/* Must open display, create window, etc. */
/* Select key events */
event_mask = ExposureMask | KeyPressMask | KeyReleaseMask;
XSelectInput(display, window, event_mask);
/* Map window after selecting */
/* Get events */

In Example 8-7, events are selected before the window is mapped. This sequence is important, since otherwise the window will not receive the first Expose event that occurs after a new window is mapped and it will not know when to redraw the window. You will remember from basicwin that an Expose event signifies that a window has become visible and needs to be redrawn. Every Expose event, including the first, should trigger the drawing of the window's contents.

Also, note that you cannot add to the selected events by calling XSelectInput() with a single additional mask. You must specify all the desired event masks every time you call it.

Correspondence Between Event Masks and Events

Each event mask symbol indicates that a certain type of event or group of event types should be queued when they occur. For example, when used alone as an event_mask argument to XSelectInput(), a KeyPressMask symbol indicates that only KeyPress events are desired. A FocusChangeMask symbol, on the other hand, indicates an interest in two types of events: FocusIn and FocusOut.

On the other hand, there is more than one event mask symbol for MotionNotify events; the different masks specify the conditions under which pointer motion events are desired. For example, if both Button1MotionMask and Button3MotionMask symbols are combined to form an event_mask argument to XSelectInput(), only one event type is requested: MotionNotify events. However, this event type will be queued only if the pointer moves while the first or third button (or both) is held down.

Table 8-3 lists each event mask, its associated event types, and the associated structure definition. The structures for each event type are described in Appendix E, Event Reference.

Table 8-3. Event Masks, Event Types, and Event Structures

Event Mask

Event Type

Structure

KeyPressMask

KeyPress

XKeyPressedEvent

KeyReleaseMask

KeyRelease

XKeyReleasedEvent

ButtonPressMask

ButtonPress

XButtonPressedEvent

ButtonReleaseMask

ButtonRelease

XButtonReleasedEvent

OwnerGrabButtonMask

n/a

n/a

KeymapStateMask

KeymapNotify

XKeymapEvent

PointerMotionMask PointerMotionHintMask ButtonMotionMask Button1MotionMask Button2MotionMask Button3MotionMask Button4MotionMask Button5MotionMask

MotionNotify

XPointerMovedEvent

EnterWindowMask

EnterNotify

XEnterWindowEvent

LeaveWindowMask

LeaveNotify

XLeaveWindowEvent

FocusChangeMask

FocusIn FocusOut

XFocusInEvent XFocusOutEvent

ExposureMask

Expose

XExposeEvent

(Selected in GC by graphics_expose member)

GraphicsExpose NoExpose

XGraphicsExposeEvent XNoExposeEvent

ColormapChangeMask

ColormapNotify

XColormapEvent

PropertyChangeMask

PropertyNotify

XPropertyEvent

VisibilityChangeMask

VisibilityNotify

XVisibilityEvent

ResizeRedirectMask

ResizeRequest

XResizeRequestEvent

StructureNotifyMask

CirculateNotify ConfigureNotify DestroyNotify GravityNotify MapNotify ReparentNotify UnmapNotify

XCirculateEvent XConfigureEvent XDestroyWindowEvent XGravityEvent XMapEvent XReparentEvent XUnmapEvent

SubstructureNotifyMask

CirculateNotify ConfigureNotify CreateNotify DestroyNotify GravityNotify MapNotify ReparentNotify UnmapNotify

XCirculateEvent XConfigureEventXCreate WindowEvent XDestroyWindowEvent XGravityEvent XMapEvent XReparentEvent XUnmapEvent

SubstructureRedirectMask

CirculateRequest ConfigureRequest MapRequest

XCirculateRequestEven XConfigureRequestEven XMapRequestEvent

(Always selected)

MappingNotify

XMappingEvent

(Always selected)

ClientMessage

XClientMessageEvent

(Always selected)

SelectionClear

XSetSelectClearEvent

(Always selected)

SelectionNotify

XSelectionEvent

(Always selected)

SelectionRequest

XSelectionRequestEvent

There is no event mask for several of the event types listed at the end of this table, because the X server or another client can send them to any client without them being selected. For example, MappingNotify indicates that the keyboard mapping (see “Keycodes to Keysyms” in Chapter 9) or pointer mapping has changed. This event is reported to all clients by the server when any client changes those mappings. The selection events are a means of interclient communication, where one client announces with an event that it has a selection of text or graphics available for pasting, and another client responds with an event specifying in what format it would like the information. Similarly, ClientMessage events are always selected because they are sent from one client directly to another using the XSendEvent() routine.

Also note that SubstructureNotifyMask and StructureNotifyMask select the same event types but on different windows. The former selects the events when they occur in any child of the window specified in the call to XSelectEvent(), and the latter only when they occur in the window specified. (These are perhaps the two least often used masks.)

Propagation of Device Events

The fifth member in almost every event structure, window, contains the ID of the window in which the event appears to have occurred. This is called the event window. For ButtonPress, ButtonRelease, KeyPress, KeyRelease, and MotionNotify events, the event window is not necessarily the window in which the event originally happened, which is called the source window.

Which window is reported in the event on the queue depends on the results of propagation up through the window hierarchy and is controlled by the event_mask and do_not_propagate_mask window attributes.

The source window is the lowest visible window in the hierarchy that encloses the pointer when the device event occurs. It is also the smallest visible window enclosing the pointer. The window member of the event in the queue (the event window) will be the source window only if the event_mask attribute (set with XSelectInput()) of the source window selected the event's type.

If the event was not selected for the source window, then the event is sent to the parent and so on until the event arrives at an ancestor window that has selected the right event type. The ID of this window is then placed in the window member of the event structure and that structure is placed on the queue for this client. Once a window that has selected the event is found, the event no longer propagates. If no window selected the event anywhere in the hierarchy up to and including the root window, the server never sends the event.

The do_not_propagate_mask window attribute also gets involved in this process. When an event arrives at a window but finds it has not been selected, the do_not_propagate_mask determines whether the event will be sent to ancestor windows. By default, all events that can propagate do. If the mask for the event type that occurred is included in the do_not_propagate_mask, the event is never sent.

Figures 8-2a, 8-2b, and 8-2c demonstrate the propagation of an event through the hierarchy, given three different event_mask and do_not_propagate attribute settings.

Figure 8-2. One possible selection scheme

The do_not_propagate_mask is rarely used. However, here is one scenario in which setting the do_not_propagate_mask attribute would be useful. Consider an application with two windows, a parent and a child. The program lets the user draw in the child by moving the pointer while holding down a pointer button. However, like basicwin, the application exits on a ButtonPress event in the parent window. Since ButtonPress events are not selected in the child window, they will be propagated to the parent and will cause the application to exit. But a ButtonPress is necessary because we want the drawing in the child window to occur only when a button is held. By setting the do_not_propagate_mask attribute of the child window to ButtonPressMask, this problem is solved.

Figure 8-3. Another possible selection scheme


Figure 8-4. Yet another possible selection scheme

Here's an example of where event propagation requires care in selecting events. Imagine a program that creates one large window and a small subwindow. The large window takes ButtonPress events to exit, and the small subwindow draws dots whenever the pointer is moved with a button held down. If you select ButtonPressMask alone for the parent, and ButtonMotionMask alone for the child, it does not work! The reason is that when the ButtonPress occurs, it propagates to the parent, and initiates a grab of all pointer events. (This is an automatic grab, discussed in the next section, not the result of an XGrabButton() or XGrabPointer() call). Since the parent did not select motion events, no MotionNotify events are received by the program. The moral of the story is that if a parent (or any ancestor) selects ButtonPress events, then its children must also select ButtonPress events in order for the children to get any other type of pointer events (including MotionNotify, EnterNotify, LeaveNotify).


Note: For brevity, we need conventions for describing the distribution of events. We'll say that an event is sent to a window when it is generated in that window either because of device action or as a side effect to an Xlib routine. A window receives an event sent to it only if the window has selected that event type or if the event type is always selected. Only when a window receives an event is it placed on the queue for that client. Another convention is helpful in describing the selection of events. We will say that "the window has selected that event type" rather than the more cumbersome "the program has called XSelectInput(), specifying the window and the mask that selects that event type."

We have described the way device events propagate normally. But two other actions can modify this operation: changing the keyboard focus window or grabbing the keyboard or pointer. Not only do these change the distribution of normal events, they create new events as side effects. We'll just introduce these here and return to them in Chapter 9, “The Keyboard and Pointer”

The Keyboard Focus Window

The keyboard focus window affects the distribution of KeyPress and KeyRelease events. Normally, the window manager allows the user to specify which window, if any, should be the keyboard focus. Only the focus window and its descendants receive keyboard input, and within them, event propagation occurs normally. Events occurring outside the focus window are delivered to the focus window. By default, the focus window is the root and keyboard events are normally distributed to all windows on the screen, since all the windows on a screen are descendants of the root.

The keyboard focus is set to a window with XSetInputFocus(). The focus window must be viewable. [25] If it is not viewable or later becomes not viewable, the focus reverts to another window specified in the XSetInputFocus() call, the revert_to window.

The current focus window can be read with XGetInputFocus().

FocusOut events are delivered to the old focus window, and FocusIn events to the window which receives the focus. Windows in between these two windows in the hierarchy are said to be virtually crossed and receive focus change events depending on the relationship and direction of transfer between the origin and destination windows. Some or all of the windows between the window containing the pointer at the time of the focus change and that window's root can also receive focus change events. By checking the detail member of FocusIn and FocusOut events, a client can tell which of its windows can receive input. See Chapter 9, “The Keyboard and Pointer” for more information about tracking the keyboard focus.

Applications should set the keyboard focus to one of their own windows only when absolutely necessary, because this will prevent other clients from receiving keyboard events. It is permissible for clients to set the focus window when the mouse enters their top-level window, as long as they set it back to the root window when the pointer leaves again. A client might want to do this to send all keyboard input to one of its subwindows. See Chapter 12, “Interclient Communication” for more information about what a client should do regarding the keyboard focus.

Keyboard and Pointer Grabbing

The keyboard and/or the pointer can be grabbed when their input should not be allowed to be interrupted by other clients. As the name implies, grabbing prevents other clients from receiving input and, therefore, can be antisocial. It should not be done unless absolutely necessary. Grabbing the pointer is particularly troublesome, because there is no event to announce to other clients that this has happened. See Appendix L, Interclient Communcation Conventions, of Volume Zero (as of the second printing).

In general, grabbing is an advanced topic that you do not need to understand in detail until you find a reason to use it. But there are two exceptions to this rule. You do need to know what will happen when other clients grab, so that your client can prepare for it. Secondly, an automatic grab takes place between ButtonPress and ButtonRelease events if your client has selected both. You must understand grabbing to understand the implications of this automatic grab.

An active grab causes pointer and keyboard events to be sent to the grabbing window regardless of the current position of the pointer. Active grabs are invoked directly by calling XGrabPointer() and XGrabKeyboard(). A passive grab (invoked by calling XGrabKey() or XGrabButton()) causes an active grab to begin when a certain key or button combination is pressed. Passive grabs are useful in implementing menus.

When you grab a device, you have the option of confining the pointer to any window within the grabbing client and of controlling the further processing of both keyboard and pointer events.

Grabbing the keyboard effectively selects all keyboard events, whether you selected them previously or not. Grabbing the keyboard also causes FocusIn and FocusOut events to be sent to the old and new focus windows, but they must be selected by each window to be received. In the call to grab the pointer, however, you specify what types of pointer, button, and enter/leave events you want.

Grabs take precedence over the keyboard focus window. Grabs of the keyboard generated FocusIn and FocusOut events, so that if your client selects these, it can determine whether or not it can get keyboard events. Pointer grabbing is more problematic, since no event notifies other clients when one client has grabbed it. However, pointer grabs are almost always temporary.

For more on keyboard and pointer grabbing, see “Grabbing the Keyboard and Pointer” in Chapter 9 For a description of server grabbing, which is a different topic though still related to events, see Chapter 16, “Window Management”

Event Masks

This section describes the event masks and the events they select. After reading this section, you should have a good idea of what types of events exist, what they are for, how to select them, and when to use them. Chapter 9, “The Keyboard and Pointer” and the sections listed in Table 8-5 provide practical examples and describe the use of some of the more commonly used events in more detail. Appendix E, Event Reference, provides a complete reference to each event type.

KeyPressMask and KeyReleaseMask

KeyPress and KeyRelease events report when a keyboard key has been pressed or released. Most, but not all, servers are capable of generating KeyRelease events. Shift, Control, and other modifier keys generate events just like the main keyboard.

The KeyPress and KeyRelease events provide a keycode that identifies the key, but the keycodes are server-dependent and should not be used to interpret the event. Instead you can use XLookupString() to translate the keycode into a portable symbol called a keysym, which represents the symbol on the cap of the key, and into an ASCII character string. Both the mapping between keycodes and keysyms and the mapping between keysyms and ASCII strings can be modified.

In XLookupString(), the main routine used for interpreting KeyPress and KeyRelease events, there is a provision for a special Compose key which is available on some keyboards, so that multikey sequences, usually used to type characters for languages other than English, can be entered and translated into the appropriate keysym. The Compose key feature, however, is not implemented in the versions of Xlib provided by MIT.

The events selected by KeyPressMask and KeyReleaseMask are used in the examples in “Simple Keyboard Input” in Chapter 9

ButtonPressMask, ButtonReleaseMask, and OwnerGrabButtonMask

ButtonPress and ButtonRelease events occur when the pointer buttons are pressed. There are generally between three and five buttons on the pointer, and the event structure specifies not only the button that caused the event but also the current state of all the pointer buttons and the modifier keys on the keyboard. The mapping between the bits in the button mask and the physical buttons can be changed with XSetPointerMapping() and read with XGetPointerMapping() and is global to the server.

The pointer is automatically grabbed between the ButtonPress and ButtonRelease events on behalf of the client for whose window the ButtonPress was selected. This way, you always expect to receive button events in pairs since the release will be sent to your client regardless of the position of the pointer at that time. Only one client can select button events on any one window at one time, due to the grab that automatically takes place.

The OwnerGrabButtonMask does not select any event by itself, but it controls the distribution of button events to your client during the automatic grab between the ButtonPress and ButtonRelease (and during any grab your client might make). If it is selected, the automatic grab has the same effect as an XGrabButton() call with the owner_events argument set to True, so that the ButtonRelease event is sent to whichever of the client's windows the pointer is in. If the ButtonRelease occurs outside the client's windows or if OwnerGrabButtonMask is not selected, all events will be sent only to the window where the ButtonPress occurred. Current wisdom suggests that you should always select OwnerGrabButtonMask with ButtonPressMask.

The events selected by ButtonPressMask and ButtonReleaseMask are discussed in “Handling Pointer Button Events” in Chapter 9 and demonstrated in Examples 9-9, 16-1, and 16-2.

The Pointer Motion Masks

There are eight pointer motion masks: PointerMotionMask, PointerMotionHintMask, ButtonMotionMask, Button1MotionMask, Button2MotionMask, Button3MotionMask, Button4MotionMask, and Button5MotionMask. Up to five pointer buttons are supported, even though most mice have only three buttons and some have only one.

  • PointerMotionMask selects motion events that occur when any or none of the pointer buttons are pressed. Each event includes the position of the pointer within the event window and the position relative to the origin of the root window. All motion events contain a mask that gives the current status of the modifier keys and pointer buttons and the current server time. MotionNotify events occur in large numbers while the pointer is moving steadily. Therefore, this mask is selected alone only by clients that require a complete record of pointer position, such as painting programs.

  • PointerMotionHintMask is used in concert with other pointer motion masks to reduce the number of events generated. By itself, it does not select any events. PointerMotionHintMask specifies that the server should send only one MotionNotify event when the pointer moves, until a key or button state changes, the pointer leaves the window, or the client calls XQueryPointer() or XGetMotionEvents(). The idea is that instead of processing hundreds of pointer motion events, the client gets only one event per movement and then queries the pointer position or examines the motion history buffer (the latter may not exist on some servers) for the current position. This approach is suitable for clients that need the pointer position at particular times but that do not need all the intermediate positions. Even though each query for the pointer position is a round-trip request, the performance of this approach is better than that of selecting all the events with PointerMotionMask alone, because of the reduced network traffic.

  • ButtonMotionMask selects any pointer motion events that occur when at least one button is pressed.

  • Button1MotionMask, Button2MotionMask, Button3MotionMask, Button4MotionMask, and Button5MotionMask select pointer motion events that occur when the specified button is pressed. If two or more of these masks are used, events with any combination of the specified buttons (except both released) will be selected.

Handling the events selected by these masks is described in “Tracking Pointer Motion” in Chapter 9 and demonstrated in three examples in that section.

FocusChangeMask

FocusIn and FocusOut events occur when the keyboard focus window is changed. A window that selects FocusChangeMask receives a FocusOut event if it was the old focus window or is in the same branch of the hierarchy as the old focus window. It receives a FocusIn event if it is the new focus window or is in the same branch of the hierarchy as the new focus window. The detail member in the event tells the relationship of the window to the new or old focus window. With this information, it is possible to tell whether the window can receive keyboard input. You can read the details of what events are delivered in Appendix E, Event Reference.

EnterNotify, LeaveNotify, FocusIn, and FocusOut events are often used together to track whether the pointer is in a window and whether the client has the keyboard focus. If the focus is the root, EnterNotify and LeaveNotify events are used. With any other focus, the FocusIn and FocusOut events take precedence.

FocusIn and FocusOut events are described and used in “Border Crossing and Keyboard Focus Change Events” in Chapter 9

EnterWindowMask and LeaveWindowMask

EnterNotify and LeaveNotify events are typically used to inform a client that the pointer just entered or just left one of its windows. If the client receives a LeaveNotify event in its top-level window, the client will not be receiving any more key, button, or motion events until it gets an EnterNotify event, unless it is the keyboard focus window or has grabbed the keyboard or pointer.

An EnterNotify event is also generated when a window is mapped over the current position of the pointer, and a LeaveNotify is generated when a window containing the pointer is unmapped.

EnterNotify and LeaveNotify events are described and used in “Border Crossing and Keyboard Focus Change Events” in Chapter 9

KeymapStateMask

A KeymapNotify event notifies the client about the keyboard state when the pointer or keyboard focus enters a window. The keyboard state is represented (in the event structure) by 32 bytes of data called a keyboard vector, with one bit for each keyboard key. The number of a bit in the vector for a particular key is the same as the key's keycode. This vector is the same as the vector returned by XQueryKeymap().

This event type, if it is selected, always follows immediately after an EnterNotify or FocusIn event. It allows a client to find out which keys were pressed when the pointer or the keyboard focus entered the window. Since the state of the modifier keys is already reported in EnterNotify and FocusIn events, the KeymapNotify event is only useful for reporting the state of other keys.

KeymapState events are not used in the examples in this manual, because they are rarely needed. For more information about them, see Appendix E, Event Reference.

ExposureMask

An Expose event tells a client which window or area within a window has just become visible. The usual response is to redraw the contents of the area or of the entire window, if that is easier and comparably fast. Figure 8-5 shows a typical window hierarchy before and after window C is lowered. Two Expose events are sent to window A specifying areas E1 and E2, and one Expose event is sent to window B specifying area E3.

Figure 8-5. Expose events generated by lowering of window C

The handling of Expose events is fully described and demonstrated in “Repainting the Window” in Chapter 3

VisibilityChangeMask

A VisibilityNotify event is sent when a window makes any change in visibility, as shown in Table 8-4, except when the window becomes not viewable. (Becoming not viewable means that the window or one of its ancestors was unmapped, which generates an UnmapNotify event.) This event might be used by a client that must be completely visible in order to be useful.

The symbol returned in the state flag of the event is shown in the third column of the table.

Table 8-4. Visibility Transitions Causing VisibilityNotify Events

Beginning State

Final State

state Flag

unobscured

partially obscured

VisibilityPartiallyObscured

unobscured

fully obscured

VisibilityFullyObscured

partially obscured

unobscured

VisibilityUnobscured

partially obscured

fully obscured

VisibilityFullyObscured

fully obscured

unobscured

VisibilityUnobscured

fully obscured

partially obscured

VisibilityPartiallyObscured

not viewable

unobscured

VisibilityUnobscured

not viewable

partially obscured

VisibilityPartiallyObscured

not viewable

fully obscured

VisibilityFullyObscured

VisibilityNotify events are not demonstrated in this manual. For more information on them, see Appendix E, Event Reference.

ColormapChangeMask

A ColormapNotify event reports when the colormap attribute of the window (for which this mask was selected) changes and when the colormap specified by the attribute is installed, uninstalled, or freed. XChangeWindowAttributes() can generate this event when the colormap window attribute is changed. XFreeColormap(), XInstallColormap(), and XUninstallColormap() generate this event if called on the colormap specified in the attribute of the window. From the information in the structure, you can tell which of these calls generated the event and what the current status of the colormap is. The conventions for what the client should do in response to each of these contingencies has not yet been determined. See Chapter 12, “Interclient Communication”

ColormapNotify events are discussed in “The ColormapNotify Event” in Chapter 7

PropertyChangeMask

A PropertyNotify event indicates that a property of a certain window was changed or deleted. This event is generated when XChangeProperty(), XDeleteProperty(), or XRotateWindowProperties() is called or when XGetWindowProperty() is called with certain arguments. Beyond its normal purpose, this event can be used to get the current server time. This is done by appending zero-length data to a property using XChangeProperty(), which generates a PropertyNotify event containing the time.

The uses of PropertyNotify events are described in Chapter 12, “Interclient Communication”

StructureNotifyMask and SubstructureNotifyMask

StructureNotifyMask selects a group of event types that report when the state of a window has changed. This includes the window's configuration (size, position, border width, stacking order), whether it was destroyed, whether it was moved due to its win_gravity window attribute, whether it was mapped or unmapped, and whether it was reparented.

SubstructureNotifyMask selects the same events plus one that indicates that a window has been created; it monitors all the subwindows of the window specified in the XSelectInput() call that used this mask. Only SubstructureNotifyMask selects CreateNotify events, because the window does not exist beforehand, and therefore, no ID exists to use in a call to XSelectInput() using StructureNotifyMask.

Applications often select StructureNotifyMask to be notified that they have been manipulated by the window manager or some other client, so that they can act accordingly.

The following list describes the events selected by StructureNotifyMask and SubstructureNotifyMask:

  • A CirculateNotify event reports a call to change the stacking order and includes whether the final position is on top or on bottom. This event is generated by XCirculateSubwindows(), XCirculateSubwindowsDown(), or XCirculateSubwindowsUp().

  • A ConfigureNotify event reports changes to a window's configuration, including its size, position, border width, and stacking order. This event is generated by XConfigureWindow(), XLowerWindow(), XMapRaised(), XMoveResizeWindow(), XMoveWindow(), XRaiseWindow(), XResizeWindow(), XRestackWindows(), and XSetWindowBorderWidth().

  • A CreateNotify event reports that a new window has been created with either XCreateSimpleWindow() or XCreateWindow().

  • A DestroyNotify event reports that a window has been destroyed with XDestroyWindow() or XDestroySubwindows(). When a window is destroyed, this event is delivered to all subwindows of the window before it is delivered to the window itself, unless the subwindows are in another client's save-set (see Chapter 16, “Window Management” for a description of save-sets).

  • A GravityNotify event reports when a window is moved because its parent was resized and had its window gravity attribute set.

  • A MapNotify event reports when a window is mapped. This event is generated by XMapWindow(), XMapRaised(), and XMapSubwindows().

  • A ReparentNotify event reports when a client successfully reparents a window (see Chapter 16, “Window Management” for a description of window reparenting).

  • An UnmapNotify event reports when a mapped window is unmapped. This event also indicates whether the unmapping of a child window was due to the fact that the parent window was resized and the child had a window gravity attribute of UnmapGravity.

The ConfigureNotify event is used in the basicwin application described in Chapter 3, “Basic Window Program” The rest of these events are used in a similar fashion by applications that need detailed knowledge of their state.

SubstructureRedirectMask

The three event types selected by SubstructureRedirectMask--CirculateRequest, ConfigureRequest, and MapRequest--can be used by a client (virtually always the window manager) to intercept and cancel window-configuration-changing requests made by other clients to change the window configuration. Only one client at a time can select SubstructureRedirectMask on a particular window. Normally, SubstructureRedirectMask is selected on the root window to allow the window manager to intercept layout-changing requests for the top-level windows of each application. When these events are selected, the Xlib requests noted in the paragraphs below do not perform their usual function but instead simply generate these events. The window manager is then able to modify the requests according to its layout policy before repeating the requests itself with its modified arguments.

These events differ from CirculateNotify, ConfigureNotify, and MapNotify in that the *Request events [26] deliver the parameters of the request before the requests are carried out and indicate that the original request has been cancelled. The *Notify requests indicate the final outcome of such requests, unhindered.

Each of the event structures associated with the following event types includes an override_redirect member, which is either True or False. If it is True, the window manager should ignore the event, since this indicates that the client has set the override_redirect attribute to indicate that this is a temporary window. (For more information, see “Substructure Redirection” in Chapter 16)

  • CirculateRequest events report when an Xlib function, such as XCirculateSubwindows(), XCirculateSubwindowsDown(), XCirculateSubwindowsUp(), or XRestackWindows() is called to change the stacking order of a group of children.

  • ConfigureRequest events report when an Xlib function, such as XConfigureWindow(), XLowerWindow(), XMoveResizeWindow(), XMoveWindow(), XRaiseWindow(), XResizeWindow(), or XSetWindowBorderWidth() is called to resize, move, restack, or change the border width of a window.

  • MapRequest events report when XMapWindow() or XMapSubwindows() is called to map a window.

The uses of the event types selected by SubstructureRedirectMask are described in Chapter 16, “Window Management”

ResizeRedirectMask

The ResizeRequest event is generated when some other client (usually the window manager) attempts to resize the window on which ResizeRedirectMask is selected. XConfigureWindow(), XMoveResizeWindow(), and XResizeWindow() generate this event. Only one client can select ResizeRedirectMask at a time on a particular window.

This event includes the requested size. The final size may be adjusted by the window manager and can be found from the resulting ConfigureNotify event or, if the window is visible, from the Expose event.

A client might wish to select this mask if it has only one acceptable size. Then when any client attempted to resize the window, the request would be sent as an event and can be safely ignored. However, if some client (say, the window manager) has selected SubstructureRedirectMask for the parent of the window on which ResizeRedirectMask was selected, the substructure redirect takes precedence. Therefore, this usually will not work. ResizeRedirectMask is not very useful, given that most window managers select SubstructureRedirectMask.

Automatically Selected Events

Seven types of events can be sent to your program even if you do not explicitly select them. Your client must handle or throw away MappingNotify events regardless of whether the client reads the keyboard. All the others are generated in response to your own actions (either by the server or by other clients), and therefore, you should know that you are going to get them. Example 8-3 described when each of these events should be present in your event loop.

  • MappingNotify events are caused by XChangeKeyboardMapping(), XSetModifierMapping(), and XSetPointerMapping() calls that set the pointer button, keyboard key, and keyboard modifier key mappings. Since these mappings are global to the server, each client must call the correct function to refresh its knowledge of the mappings.

    If the changed mapping is of the keyboard, a receiving client should call XRefreshKeyboardMapping(), which updates a client's knowledge of the server's mapping between keycodes and keysyms.

    If the changed mapping is of the pointer, the client can call XGetPointerMapping() to update its knowledge. Most current clients do not do this, however, because it is assumed that the button mappings were intentionally changed by the user. That means that the client should not attempt to adjust its operation so that the buttons have their old meanings.

  • ClientMessage events are sent as a result of a call to XSendEvent() by a client to a particular window. They contain data described by an Atom. These events are normally used to transfer selection data. The send_event member of the event structure will always be set.

  • SelectionClear, SelectionNotify, and SelectionRequest events are used to communicate back and forth between two applications that are transferring information. This process is described in “Selections” in Chapter 12

  • GraphicsExpose and NoExpose events are selected not by an event mask but by the graphics_exposures member of the GC. One or the other of them (or both) is generated by each XCopyArea() or XCopyPlane() request when the GC specified for the request has this member set to True. Otherwise, the events are not generated. The GraphicsExpose event indicates that a source area could not be completely copied into a destination because the source was partially or fully obscured. The NoExpose event indicates that the copy was not affected by an obscured source. More than one GraphicsExpose event can be generated by a single XCopyArea() or XCopyPlane() request, depending on the number and position of the obscuring windows, but only one NoExpose is possible as a result of a single copy. GraphicsExpose events are often handled just like Expose events.

Sending Events

The XSendEvent() function may be used to send a ClientMessage event or any other event type to a particular window, to the current keyboard focus window, or to the window in which the pointer is located. Sending events is necessary in selection processing, as described in “Selections” in Chapter 12 It may also be useful for designing test procedures for your input handling or for making demonstration programs that simulate user input.

The send_event member of each event structure indicates the origin of the event. If True, it was sent from another client rather from the server. Note that, unless this flag is explicitly checked, events from the server and from other clients will appear the same to your application.

Where to Find More on Each Event

All event types are described in reference format in Appendix E, Event Reference. The information on each page includes the event structure definition, description of each event structure member, XEvent union name, how to select the event, when it is generated, and notes on its use. Table 8-5 shows other places in this manual where you can find information about using certain event types.

Table 8-5. Where Events are Described Further

Event Type

Section

KeyPress KeyRelease

Section 9.1.1.1

ButtonPress ButtonRelease

Section 9.2.2

KeymapNotify

Section 9.3.1

MotionNotify

Section 9.2.1

EnterNotify LeaveNotify

Section 9.3

FocusIn FocusOut

Section 9.3

Expose

Section 3.2.13.1

GraphicsExpose NoExpose

Section 5.6

ColormapNotify

Section 7.10.2

PropertyNotify

Section 12.1

ConfigureNotify

Section 3.2.16

CirculateRequest ConfigureRequest MapRequest

Section 16.2

MappingNotify

Section 9.1.2.3

SelectionClear

Section 12.4[a]

SelectionNotify

Section 12.4[a]

SelectionRequest

Section 12.4[a]

[a] Also in Appendix L, Interclient Communcation Conventions, of Volume Zero (as of the second printing).




[24] See a C language tutorial or reference manual if you are unfamiliar with unions.

[25] For a window to be viewable, it must be mapped and all its ancestors must be mapped, but it may be obscured.

[26] The wildcard (*) notation is used occasionally in this manual to indicate a number of events or routines with similar names. In this case, *Request means all event types whose symbols end in Request.