Applying C - Programming X Windows
Written by Harry Fairhead   
Tuesday, 11 November 2025
Article Index
Applying C - Programming X Windows
Device, Screen and Window
An Example
Events

Events

The 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, 
e.xbutton.y); break; default:
/* unknown event type - ignore it. */ break; } }

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

  • GTK - a GUI Framework
  • A First Window
  • Glade
  • Graphics Beyond GTK

Summary

  • Selecting a graphics system for Linux is difficult because there is so much choice and many different levels of operation.

  • The framebuffer gives you direct access to the graphics buffer.

  • You can use it to write directly to the screen and it doesn't take account of windows or any other part of the GUI.

  • It is possible to use font files to write text to the framebuffer.

  • The standard window system is X11 and it has a client-server architecture with the program that does the drawing as the client, and the program that does the rendering on a device as the server.

  • X11 can be used via the Xlib library.

  • X11 can also handle user input and for this you have to implement an event handling loop.

  • The GTK Framework is a complete GUI system with windows, buttons and events.

  • The structure of almost any GUI framework makes your program asynchronous and this can be confusing at first.

  • You can use GTK via function calls, but it is much easier to use the Glade drag-and-drop editor.

Now available as a paperback or ebook from Amazon.

Applying C For The IoT With Linux

  1. C,IoT, POSIX & LINUX
  2. Kernel Mode, User Mode & Syscall
  3. Execution, Permissions & Systemd
    Extract Running Programs With Systemd
  4. Signals & Exceptions
    Extract  Signals
  5. Integer Arithmetic
    Extract: Basic Arithmetic As Bit Operations
    Extract: BCD Arithmetic 
  6. Fixed Point
    Extract: Simple Fixed Point Arithmetic
  7. Floating Point 
  8. File Descriptors
    Extract: Simple File Descriptors 
    Extract: Pipes 
  9. The Pseudo-File System
    Extract: The Pseudo File System
    Extract: Memory Mapped Files 
  10. Graphics
    Extract: framebuffer
    Extract: Programming X Windows ***NEW
  11. Sockets
    Extract: Sockets The Client
    Extract: Socket Server
  12. Threading
    Extract:  Pthreads
    Extract:  Locking
    Extract:  Condition Variables
    Extract:  Deadline Scheduling
  13. Cores Atomics & Memory Management
    Extract: Applying C - Cores 
  14. Interupts & Polling
    Extract: Interrupts & Polling 
  15. Assembler
    Extract: Assembler

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.

Banner


Qodana Revisited
20/10/2025

It's been some years since we first looked at Qodana, the solid SAST tool from JetBrains. Let's find out what's new in its latest release, Qodana 2025.2.



The Pico Gets Zephyr And Rust Support
30/10/2025

Zephyr, a real time operating system and Rust, a memory safe language, are both hot topics at the  moment and Raspberry Pi has decided they are hot enough to support in its extension for VS Code. [ ... ]


More News

pico book

 

Comments




or email your comment to: comments@i-programmer.info



Last Updated ( Tuesday, 11 November 2025 )