The X Programming Model

Events: the Input Side

X applications are clients of the X server that is managing their display. They have to be written around an event loop that waits for incoming event notifications from the server. But not all applications care about every input type; a terminal-emulator window, for example, may only want to notice keystrokes, while a task bar will only want to notice mouse button clicks. So one of the first things an application generally does is tell the X server to set the application's event mask to the repertoire of event types it wants to see. This restriction both simplifies the application code (which won't have to explicitly ignore anything) and cuts down on client-server network traffic.

It's also useful to know that X identifies the source of every event by two numbers; a display number and a window ID that ua unique to the display it's on. In the commmon case, one X server runs a single display and the display number is always zero. Windows are a tree-shaped hierachy, with parent windows containing child windows and every window inside the root window thst covers the entire display. Events are first associated with the smallest window containing the mouse pointer, or the window that has grabbed the pointer input (if any). Then they bubble up the window hierarchy until they either find a window that has selected that evnt type or set a “do not propagate” bit for it. [20]

Here are the event types that X recognizes. Every event has an associated timestamp, a serial number, a window identifier, and a display identifier. Many events include a modifier mask, which describes the combination of shift keys (Shift, Control, Alt, etc.) and mouse buttons that are down as the event is generated.

ButtonPress, ButtonRelease

A mouse button has been pressed or released. There is a detail field that specifies the mouse button; another field will contain a modifier mask.

CirculateNotify, CirculateRequest

CirculateNotify tells the client that its window has been raised (moved to the top of the stacking order) or buried (moved to the bottom). CirculateRequest (normally only selected by window managers) is a curculate requestr which the client may apply policy to before generating a synthetic CirculateNotify to another client

ClientMessage

This event is a short message (up to 20 bytes of data) from another client, identified by its display and window. It is up to clients to agree on the message encoding. This event type can't be unselected.

ColormapNotify

Reports when the ColorMap attribute of a window changes; the new colormap is included in the event data. This event is meaningful only when the display is using indexed color — that is, pixel values in it are actually indexes into a color map. Indexed color was a memory-saving device that is unusual on modern hardware, which tends to use direct 16- or 24-bit color.

ConfigureNotify, ConfigureRequest

ConfigureNotify is sent when a window's size, position, border, or stacking order changes. Event fields contain the new configuration. ConfigureRequest (normally only selected by window managers) is a request for such a change, to which the client may apply policy to before shipping a synthetic ConfigureNotify to another client.

CreateNotify, DestroyNotify

These events inform a client when a window associated with it has been created or destroyed by the server. Toolkits usually hide CreateNotify.
EnterNotify, LeaveNotify

The application gets these when the mouse pointer moves into or out of one of its windows. This event is reported even when the motion does not trigger any window focus change.

Expose

The application receives this events when any portion of one of its windows that had been hidden (e.g., beneath other windows) becomes exposed. Event fields specify the exposed rectangle in pixel coordinates and a rough count of how many other Expose events are waiting after this one.

FocusIn, FocusOut

The application gets this event when one of its windows acquires or loses keyboard focus. Analogous to EnterNotify and LeaveNotify.

GraphicsExpose, NoExpose

These are not actual input events and can't be unselected; instead they are enabled by a flag in the graphics context. They are sent when certain kinds of bit-copy operations fail because the source area was out of bounds. Toolkits normally hide these.

GravityNotify

Sent to an application when a window moves because its parent window has been resized.

KeymapNotify

Reports the state of the keymap (the mapping from keycaps to X key types). Normally sent just after EnterNotify or FocusIn. Toolkits hide this.

KeyPress, KeyRelease

Sent when a keyboard key is pressed or released. Event field includes the X key symbol obtained by indexing into the current keyboard map with the raw key value, and a modifier mask.
MapNotify, UnmapNotify

The application receives these when one of its windows is mapped (physically realized on the display, as when it is unminimized) or unmapped (removed from the screen but still able to accept output, as for example when it is minimized). Toolkits normally hide these.

MappingNotify

An application receives this when its keymap changes. Event fields indicate which part of the keymap has been modified.

MapRequest

Only window managers normally select this event, which requests that a particular window be mapped (see MapNotify). The window manager may reject the request or apply policy before shipping a synthetic MapNotify.

MotionNotify

The appplication receives this on a mouse motion in one of its windows. Event fields include the mouse coordinates and a modifier mask.

PropertyNotify

An application gets this when a property value associated with one of its windows is named or deleted. Properties are name/value pairs that can be set by the server, perhaps in response to an application request.

ReparentNotify

An application receives this when one of its windows is moved in the window hiearcy, giving it a new parent.

ResizeRequest

This event reports another client's request to resize a window. It is normally only sent by window managers. Event fields include the new size.

SelectionClear, SelectionNotify, SelectionRequest

Applications receive these events in connection with uses of the X cut buffer. They cannot be unselected. Toolkits normally hide them.

VisibilityNotify

An application receives this when the visibility of one of its windows changes. An event field describes the visibility change. Toolkits often hide this.

Every application running on an X server has an event loop waiting for the next event. Which application gets which events, and when, is a function of the user's mouse and keyboard actions, as filtered through the currently-running window manager's policy.

Applications respond to events by sending requests to the server. Usually those requests are to do output, e.g. to paint pixels in a window. Occasionally they may ask the server to send synthetic input events to the other clients.

Rendering: the Output Side

We went into some detail about the X event model because the details of event processing not infrequently percolate up to the X application level. Rendering output is simpler than handling input, so X applications can be (and usually are) better insulated from the low-level details by the toolkit libraries they use. There is an exception and a bit of a chronic trouble spot near font handling, but even that tends to be a configuration and administration problem rather than having any direct effect on how you code applications.

The X library has a rich set of primitives for drawing points, lines, rectangles, polygons, arcs, and splines (curves fitted to arbitrary control points). The server also knows how to fill boxes and closed paths. All these facilities can be grouped together as graphics and contrasted with text output, which is handled somewhat differently. Toolkit libraries generally need only a thin layer of code over the graphics parts, but have to do much more to transform text output requests for Xlib in order to reflect concerns such as internationalization and Unicode support that were not issues when X was originally devised.

As previously noted, X is in the process of changing its rendering model. This changes the programming model for the output side of X, though the change is mainly of concern to toolkit authors. Most programs will see the change only as added features (notably, support for alpha channels) and better performance (as toolkits convert from using the old model to the new one).

The original X model was based on BitBlt (painting, copying, and blending rectangles). The server translated all geometric operations into BitBlts. Fonts were handled separately, with an elaborate facility that involved the server knowing about mappings from text characters to a server-side collection of typographic glyphs. In the 1990s some X servers evolved towards limited support for accelerated graphics cards by adding some driver calls above BitBlt level, meant to be passed through to the driver-card firmware.

The new model (formally, the Render extension) is based on Porter-Duff image algebra. It renders geometric objects as collections of triangles and parallelograms. Fonts are handled much more simply, as collections of alpha-mask glyphs uploaded to the server. These choices work well with the 3D-oriented firmware now found on most graphics cards; they point towards a world in which most X objects will be 3D textures, with rendering computations pushed down to the card firmware, less bus traffic per update, and significant increases in performance.



[20] Actually, this oversimplifies a little. Multiple clients can chare a window, and there is a separate event mask for each. If wore than one client has selected an event type, events of that type are duplicated and sent to all clients.