You are on page 1of 7

accepting event inputs.

InputOnly windows are invisible windows that can receive input

events but cannot display any output. If you try to draw into an InputOnly window, the
server will generate an error. You can use InputOnly windows, for example, to change the
cursor shape as you move from one area of the screen to another, because these windows
can have cursor shapes associated with them .
• The visual attribute indicates the color model used by the physical display screen where
the window appears .
• The depth is the number of bits per pixel of the window. The depth of an InputOnly
window must be 0. Chapter 11 discusses visual, depth, and other concepts of color.

Amongthe attributes that you can set in the XSet~indowAttributes structure, there is a long in-
tegerfield named event_mask. The value of this mask determines which types of events occurring
in the window are reported to your application. Recall from Chapter 6, "The Xlib Programming
Mood," that you can use the XSelectlnput function to select the events to be reported for a win-
dow.For the main window, ini tapp selects the Expose event:
1* Select Exposure events for the main window * I

XSelectlnput(theDisplay, theMain, ExposureMaskj;

Youcan select multiple events by using as the last argument of XSelectlnput the bitwise-OR of
definedevent masks from the header file <x 11 / X. h>. For example, to enable buttonpresses as well
as Expose events, you can use the following call:

xselectlnput(theDisplay, theMain,
ExposureMask : ButtonPressMask);

Insteadof calling XSelectlnput, you can set the event_mask field in an XSetWindowAttributes
structureand select the events with a call to the XChangeWindowAttributes function. For example,
toselectthe Expose and ButtonPress events for-the main window, you can use the following code:

xswa.colormap = DefaultColormap(theDisplay,
xswa.bit_9ravity = NorthWestGravity;
xswa.event_mask = ExposureMask : ButtonPressMask;
XChangeWindowAttributes(theDisplay, theMain,
(CWColormap : CWBitGravity : CWEventMask), &xswa);

Sometimesyou may want to select a new event or drop an event without disturbing the other input I

selections.If you have to change the event selectio;1s, use the following procedure:

1. Get the window attributes using XGetWindowAttributes.

2. Copy the your _event_mask field of the XWindowAttributes structure into the
event_mask field of an XSetWindowAttributes structure.
3. Alter the mask as needed, and set the new mask using the XSetWindowAttributes
fuoccio~ "

A good approach is to develop two utility functions, AddNewEvent and IgnoreEvent, that respec-
tively enable or disable an event specified by an event mask. Listing 7.3 shows such a pair of func-
tions. These functions can be very handy. For example, if you want to stop receiving ButtonPress
events in a section of your code, you can use these functions to achieve your objective:
IgnoreEvent(theMain, ButtonPressMask)j
/* No more buttonpresses reported ... */

/* Reenable buttonpresses ... */

AddNewEvent(theMain, ButtonPress)j

/ * ... - - . - - - - - - - .. - - - . - - - - . - - . - - . - - . - - . - - - - -.' - . - ."- . - - - - - . - . - - - - * /

/* Add New Eve n t

void AddNewEvent(Window xid, long event_mask)
XWindowAttributes xwa;
XSetWindowAttributes xswaj

if (XGetWindowAttributes(theDisplay, xid, &xwa) 1= 0)

xswa. event_.mask = xwa. your _event_mask : event_maskj

XChangeWindowAttributes(theDisplay, xid,
CWEventMask, &xswa)j

/*_ ... _ ..... _ .. _ .. _ ..• _ .. _ ... _. _. - -- _. - _. - - _.. - -- - -- -- - - - - - - - -*/
/* I 9 nor e Eve n t

void IgnoreEvent(Window xid, long event_mask)

XWindowAttributes xwaj
XSetWindowAttributes xswaj

if (XGetWindowAttributes(theDisplay, xid, &xwa) 1= 0)

xswa.event_mask = xwa.your_event_mask & (-event_mask);
Display *display;
Window this_window;

If you want to destroy only the subwindows of a window, but not the window itself, you can use.
exit(0); the function XDestroySubwi.ndows, which is called in the same manner as XDestroyWindow.

Window M~pping and Unmapping

Whev. a window is created, it does not appear on the screen automatically. First you have to map
it-using, for example, the XMapWindowfunction. In fact, even after mapping a window, it may not
Other Window Operations appear on the display. In X terminology, the window must be viewable, which means that all ances-
In the course of setting up the me-in window, you have to go through many basic operations on tors of the window must be mapped. Even then, the window m~e visible because other win-
windows. For example, you have to create the window, map it, select events for it, and inform the dows, higher up in ·the hierarchy, may"be obscuring it.
window manager of its location and size. If you study the example shown in Listing 7.4, you will
realize that these basic operations are enough for a small program. Let's reexamine these basic win- As a window is created, itis pl~ced on top of the.§J.ack.of:.s~bJ.~ngs.
The commonly used XMapWindow
dow operations and consider a few others that can be useful in certain applications. function'maps a window without changing its position 1nthe stacking order. The XMapSubwindows
function maps all the subw~w. You can create a hierarchy of wind~ncriIiap;rll
windows by calling XMapsubwi.ndowsfollowed by XMapWindow,with the top window as the argu-
XCreateSimpl.eWindow provides the simplest way to create a window. This function creates an
. ment. This is more efficient than calling XMapWindowfor each window in the hierarchy. These func-·
tions are called as follows:
InputOutput window that can be used for both drawing output and for accepting events. The call- Display *display;
ing syntax of the XCreateSimpleWindow function takes the following form: Window main_window;

Display *display; /* X display */

Window parent, new_window; /* Window IDs */ XMapSubwindows{display, main_window);
int x, y; /* Position */ XMapWindow{display, main_window);
unsigned int width, height, border_width;/* Size */
unsigned long border, background; /* Pixel values */ When a window is.mapped, the X server generates a MapNoti fy event. If the window becomes view..
able (because all its ancestors are mapped), the server also generates Expose events for all visible
new_window = XCreateSimpleWindow{display, parent, x, y, width,
height, border_width, border, background); parts of the window. Because window managers usually intervene when you map the main win-
dow, it is safer to draw in the windows only in response to the Expose ~vents.
The arguments to XCreateSimpleWindow specifY the size, position, background, and border col-
ors. Because windows are organized in a hierarchy, you also have to specifYthe parent window's ID. Another mapping functiOli is useful for pop-up windows. XMapRaised, with a syntax similar to that
This function returns a window resource identifier that you have to save for later use. ofXMapWindow,raises the window to the top of its siblings and maps it. A pop-up menu or a dialog
box should be fully visible; you can use XMapRaised to achieve this.
XCreateWindowis another, more general, functi n for creating windows. You have to use this function
if you want to create an In put On 1y window for receiving events only. Whereas When you use pop-up windows, you have to hide them once their job is done (for example, after
XCreateSimpleWindow sets the attributes of the newly created window from the parent, the user has selected an item from a pop-up menu). You can use the XUnmapWindowto hide a win-
XCreateWindow requires you to specifYthe attribute values explicitly. Unless you need InputOnly dow. All descendants of the window become invisible when you unmap a window. You can unmap
windows, you can get by without any problems with XCreateSimpleWindow only. the window with the ID DialogBox, from the display connection p_disp, by calling XUnmapWindow:

Usually, you do nor have to destroy windows explicitly. When you close the connection to a display Display *p_disp;
Window DialogBox;
(with XCloseElispl..ay), the X server automatically destroys all resources associated with your appli-
cation. However, if you have an occasion in which you want to destroy a window and all its
subwindows, you can use XDestroyWindow to do the job: XUnmapWindow{p_disp, DialogBox);

Use XUnmapSubwindowsto unmap only the subwindows of a window.

Window Positioning and Sizin • XLowerWindowbrings a window to the bottom of the stack.
• XMapRaised maps and brings a window to the top at the same time.
aVlllgcreatea your windows, you are by no means stuck with your original choice of position and
-size. You can resize and reposition windows by calling certain X1ib functions. Typically, an applica- • XCirculateSubwindowsUp brings the current bottom window to the top.
tion should not move or resize the top-level window. The user does this through the window man- • XCirculateSubwindowsDown sends the top window to the bottom of the stack.
• XCirculateSubwindows can circulate up or down, depending on the value of its last
The programmer can, however, move and reposition the child windows in an application as and argument.
when necessary. You can arrange it so that the application receives a ConfigureNoti fy event when
The circulating window's function is used mostly by window managers. Applications typically use
the window manager moves or resizes the main window. In certain applications, you/may want to XMapRaised and XRaiseWindow.
rearrange the child windows in response to the ConfigureNotify event on the main window.
An example that requires moving a window is a scrollbar. If you implement the thumbwheel of a
scrollbar as a window, you have to"'rnovethis window to indicate the current thumbwheel position. Summary
You can achieve this effect by calling the XMoveWindowfunction to reposition the thumbwheel In the X Window System, a window is an area of screen in which the input and output operations
window with respect to its parent's origin: of an application take place. Although windows generally are rectangular in shape, X provides an
Display *p_disp; /* Identifies the X display */ experimental extension that enables arbitrarily shaped windows. In X, windows are organized in a
Window this_windowj /* The window being moved */ hierarchy. The root window (usually the entire screen) is at the top of the hierarchy. The root
int new_x, new_y; /* New origin of window */
window's next level of children is the top-level windows of all applications currently displaying in
that screen. Applications usually confine their output to a single top-level window, which is the
XMoveWindow(p_disp, this_window, new_x, new_y)j parent of all other windows used by the application.
Here, new_x and new_yare the new coordinates of the window's origin in its parent's coordinate All children at a particular level in the hierarchy are clipped at the borders of their pare'nt, and the
frame. order in which they overlap each other is determined by their stacking order. The stacking order of
You can resize a window using the function XResizeWindow. The call is similar to that for the top-level windows determines which application's window is at the top and ready for interac-
tion with the user.
XMoveWindowexcept that you specifYthe new width and height in place of the new position. To
move and resize a window at the same time, use XMoveResizeWindow. Here is an example call to The user manipulates the top-level windows of applications through the window manager, a spe-
this function: cial type of X application. The window manager enables the user to move and resize the topmost
XMoveResizeWindow(p_disp, this_window, new_x, new_y, windows of applications and alter their stacking order. Because of this, the top-level window of an
new_width, new_height); application requires special treatment. When creating it for the first time, you should inform the
window manager of its placement and size.
Stacking Order Alteration When a window is created, it does not automatically appear on the screen. You have to map it to
Suppose you have implemented a word processing program in which each document is displayed make it visible. Of course, you can unmap it to hide it. There are a number ofXlib routines to help
in a subwindow of the main window. When there are several open documents, these windows over- you create and manage windows. In X, the following are the basic operations on windows:
lap one another as reflected by the'stacking order among these sibling windows. Now suppose you • Creating and destroying
have a menu item that enables the user to bring a document to the top. To implement this in X,
• Mapping and unmapping
you have to change the stacking order of the windows. For this example, you can use XRaiseWindow
to bring the selected document's window to the top. For example, the following call brings tlie • Positioning and sizing
window won display p_disp to the top of the stack: • Enabling and disabling event reports
• Setting attributes
• Altering stacking order

Windows are the reason programmers use the X Window System, the mechanism that enables sev-
eral applications to share the limited space in a physical display screen.
Chapter 8

andling Events

The event-driven X programming model (described in Chaprer 6, "The

Xli ProgrammlDg 1 oae re ies on events for everyrhing from main-
raining rhe contents of a window to receiving mouse and keyboar mput
fr.~the user. X applications rely on events to pace the program and do
the user's bidding. The programs of Ohapters 5, "A Simple X Applica-
tion," and 7, "Creating and Managing Windows," provide examples of
event handling. This chapter further describes events and how they are
handled. Rather than giving an encyclopedic description of each type of
event, additional examples illustrate event handling. The chapter begins
by describing a smart way to manage the event loop when there are too
ma1iy windows in a program. Later in the chapter, you learn the details
of sevetaLtypes of~ events, in.s!...udingmouseevents, keyboard e ems, and
Expose events. -

Smart Event Handling

When building a small application with three or four windows, you can
get by with the structure'used by die examp!es-'show'n i~ Listi~g 5.1 in
Chapter 5 and Listing 7.4 in Chapter 7. In those programs, you create
the main window and then the child windows. The event handling loop
gets events from Xlib by calling XNext~ent. T~;ct action in .esponse
to an event depen s on the window where th; event o~curred. Thus, the:
evem handlin loop uses a number of if statements to compare the win-
do~ ;eported b)1me..event, with theidentifier ot each window in the
program. This results in an event processing loop:
int AppDone = 0; f* Exit event loop when 1 *f
XEvent theEvent.; f* Structure to hold event *f 2. Once you have decided on a context, save the data:
<Window theMain, QuitButton; f* Window identifiers *f
if (XSaveContext (theDisplay, w, contextl,
while (!AppDone) (caddr_t) new_p_data) != 0)
XNextEvent(theDisplay, &theEvent);
if(theEvent.xany.window theMain) fprintf (stderr, "Error saving context data");
exit (1) ;
f* Process events occurring in the main window *f

} Even though the display pointer appears as an argument to XSaveContext, storing data this way
if(theEvent.xany.window QuitButton) has nothing to with the X server, and everything is handled locally by Xlib. (An arbitrary collection
of data stored in a window at the server is known as that window's property, properties are described
f* Process events occurring in the QuitButton window *f
in Chapter 16, "Advanced Topics in X.")

Context is used to identifY the type of data. You can use the same context to store the same type of
data in many different windows. You do not have to have a separate context for each window. The
} ,context help~ you distinguish between different data types stored at a window.
f* Check for other windows ... and process events *f
Finally, the last argument to XSaveContext is of type caddr _ t, which denotes the address of any
type of data Of function in C (caddr _t is usually defined in the header file <sys/types. h». The
exact meaning of the data is irrelevant to the context management routines. How you interpret this
The problem with this processing loop is that as the number of windows grows, the event handling data is up to you.
loop gets out of hand. There are too many if statements testing for the window 10 and processing
the events. Because there are many windows in any reasonable user interface, you need to organize You can retrieve the stored data using XFindContext:
the program in a way that helps you manage the complexity of event handling. This is where the caddr_t data;
context management routines ofXlib can help you. A side benefit of using these routines is that you
if (XFindContext (theDisplay , w, context1,
can begin to develop a structure that enables you to create and manage multiple copies of a single (caddr_t *) &data) == 0)
type of window (for example, several buttons for menus). {
f* Data retrieved without error. Use data in 'this block *f

Xlib Context Manager

One way to manage the complexity of event handling is to have an event handling function for
each window and somehow store that information so that it can be retrieved by using the window'
10 as a key. Xlib provides this capability through its context manager utility routines. The routine
Window-Specific Data Management
XSaveContext enables you to save any data (actually, you store a pointer to a data structure) in- Now you know the mechanics of saving and retrieving data for a window using the context man-
dexed by the window 10 and a context, which is an. integer identifier (defined as a data type named ager. How can you use that knowledge to help you manage the complexity of the event handling
XContext in the header file <Xll /Xresource. h». For example, suppose you decide that you want loop? The example illustrates the use of the context manager to set up multiple button
to store in window w a pointer p_data to a data structure. This is what you do:

1. Call XUniqueContext to get a unique context identifier for this type of data:
windows and handle "the events in a convenient manner.

First, yo~ set up the following data structure


named XWINto store information needed by each

#include <Xll/Xresource.h>
typedef struct XWIN
Window xid; f* The 10 of the window *f
Window parent; f* The 10 of parent Window *f
void '*data; f* Pointer to data *f
int (*event_handler)(); f* Pointer to event handler *f
When an event is reported by the X server, the program must be able to determine the type of the
The XAnyEvent Structure
event and, depending on the type, other relevant information describing the event. For example, if The simplest of the event data structures is XAnyEvertt:
the event reports a mouse buttonpress, you may want to know which button and the location of the typedef struct
mouse pointer at the time of the burtonpress. Because of the diversity of events in X, the informa- {
int type; /* The event type */
tion necessary to describe one classof events (mouse events, for example) differs significantly from
unsigned long serial; /* Number of last processed event */
that needed by another (keyboard events). Thus, a number of different data structures are used to Bool send_event;/* True = event is from SendEvent */
describe the events. Because a common format i~ needed to report all events, a C union of these Display *displayj /* Ident"ifies the reporting server*!
Window window; /* Window requesting this event */
data structures is used to hold the information. The header file <X11/Xlib. h> defines this union
named XEvent: '
The fields appearing in the XAnyEvent structure happen to be the first five entries in every event's
typedef union _XEvent
{ data structure. The type field tells you the kind of event being reported. The X server keeps track
int type; /* Event's type comes first */ of the sequence of protocol requests it has processed so far and reports the sequence number of the
XAnyEvent xany; last processed request in the serial field.
XKeyEvent xkey;
XButtonEvent xbutton; The next field, send_event, describes how the event originated. In X; you can send a ~imulated
XMotionEvent xmotionj
XCrossingEvent xcrossing; event to a window. For example, even when there is no keypress, you can prepare an event structure
XFocusChangeEvent xfocus; for a keypress event and send it to a window using the XSendEvent function. The seJYer indicates
XExposeEvent xexpose; such events by setting the send_event flag in the event structure to True. If the event was gener-
XGraphicsExposeEvent xgraphicsexposej
XNoExposeEvent xnoexposej ated by the server, send_event will be 0 (False).
XVisibilityEvent xvisibility j
XCreateWindowEvent xcreatewindowj
XDestroyWindowEvent xdestroywindow; TIP:
XUnmapEvent xunmap;
XMapEvent xmap; If y6u do not want your application to b~ spoofed by fake keyboard and mouse events .sent
XMapRequestEvent xmaprequest;
XReparentEvent xreparent; by other X clients, process these events only if the xC\ny. send_event field in the XEvent
XConfigureEvent xconfigure; union is False.
XGravityEvent xgravity;
XResizeRequestEvent xresizerequestj
XConfigureRequestEvent xconfigurerequest;
XCirculateEvent xcirculate; The display field identifies the server from which the event arrives. The next field is the window
XCirculateRequestEvent xcirculaterequestj that requested this type of event. The window hierarchy determines which window receives an event.
XPropertyEvent xproperty;
XSelectionClearEvent xselectionclear;
XSelectionRequestEvent xselectionrequest;
XSelectionEvent xselection;
XColormapEvent xcolormap; Suppose you get event reports in the XEvent union theEvent. You can test the event's type by com-
XClientMessageEvent xclient;
XMappingEvent xmappingj paring the type field with the names of events defined in <X11/ Xlib. h>. If your program has a
XErrorEvent xerror; single window, you can process the events with a few if statements:
XKeymapEvent xkeymap;
long pad[24] ; if(theEvent.type == Expose)
XEvent; {
/* Process Expose event ..."Redraw contents of window */
~ data type XEvent is defined as the union of a large number of different data structures. You XClearWindow(theEvent.xny.display, theEvent.xany.window);
1In ter some of these structures later in this chapter. Appendix J, "X Event Reference," incl udes
-{information on each of these structures.