| Applying C - Programming X Windows |
| Written by Harry Fairhead | ||||||||
| Tuesday, 11 November 2025 | ||||||||
Page 4 of 4
EventsThe final feature of X11 we have to deal with is events. The X11 server sends events to the client to keep it informed of what is happening and to signal user interaction with the window. Whenever you encounter a GUI framework you will nearly always encounter events in one form or another. The reason is that user actions are inherently asynchronous with the operation of your program. In other words, you cannot predetermine when a user will click a button or which button will be clicked. Your program has to respond to what the user does and this generally means what function is called and when it is called depends on what the user does. X11 has a very basic form of event handling compared to other frameworks. In fact, it is so simple that if you have encountered other asynchronous frameworks you may well misunderstand it. The server keeps a queue of events which your program can examine and read. It does this by calling the XNextEvent function. This takes the first event from the queue and returns it. If the queue is empty then the function blocks until there is an event available. If you want to examine the event queue without blocking, you can use XPeekEvent. In addition you can specify which events you want to handle in a number of different ways. The XSelectInput function can be used after a window has been created with an event_mask to specify which events are handled.
For example, in a previous example a sleep(10) was used to give the system enough time to map a window. This is not the usual way of doing the job as the system will issue a MapNotify event after the window has been displayed. So the usual way of making sure a window is mapped is to first specify that you want to accept all StructureNotify events using: XSelectInput(dpy, w, StructureNotifyMask);
XMapWindow(dpy, w);
XFlush(dpy);
for(;;) {
XEvent e;
XNextEvent(dpy, &e);
if (e.type == MapNotify) break;
}
GC gc = XCreateGC(dpy, w, 0, 0);
Notice that the for loop polls the event queue until it receives the MapNotify event. The event struct has fields that give information about the event in addition to the type field. This is an untypical use of events in that you specifically want to know that a specific event has occurred. Asynchronous programs nearly always take a very standard form. First there is some initialization which sets up the graphics and then the program starts an event loop which reads an event and calls an appropriate function to handle it: while(1){
XNextEvent(dpy, &e);
switch(e.type){
case ButtonPress:
handle mouse button pressing
break
case MotionNotify:
handle mouse move
break
. . .
default:
unknown event - ignore
break
}
}
The loop runs forever, or at least until the user selects an option which triggers an event that the program treats as a terminate command. The event handling loop usually has a large number of case clauses to deal with everything that can happen while the program is running. For example, to draw on a window you can write an event loop that draws a point each time the mouse button is clicked: XSelectInput(dpy, w, ButtonPressMask);
while (1) {
XEvent e;
XNextEvent(dpy, &e);
switch (e.type) {
case Expose:
/* handle this event type... */
break;
case ButtonPress:
XDrawPoint(dpy, w, gc, e.xbutton.x,
Notice the ButtonPress event is generated for any mouse button press. You can find out which button using the event struct. You can look up the range of events and how to handle them in the documentation but there is one event that deserves special mention - Expose. When a window is moved to cover up your window the system does nothing to preserve its contents. When it is uncovered the section that was covered will appear blank. The Expose event is sent to the window to signal that it is now uncovered and, if it needs to, now is the time to redraw its erased content. The Expose event occurs at other times, but it is always a signal to draw or redraw content. The XEvent struct contains fields x,y, width and height, which specify the minimum rectangle that needs to be redrawn. Clearly, in many cases, your only option is to store a copy of the graphic and restore it in response to an Expose event. The idea is simple, but the implementation may be more involved than you initially imagine. In chapter but not in this extract
Summary
Now available as a paperback or ebook from Amazon.Applying C For The IoT With Linux
Also see the companion book: Fundamental C <ASIN:1871962609> <ASIN:1871962617> To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.
Comments
or email your comment to: comments@i-programmer.info |
||||||||
| Last Updated ( Tuesday, 11 November 2025 ) |

