The X Window System is a windowing system commonly used in UNIX-based operating systems. The latest version of X is version 11 (released 2012), that’s why it’s often abbreviated as X11.

X11 is based on a client-server architecture. The server is the one who has direct access over the hardware devices such as the monitor screens, the keyboard and the mouse. Client applications should make requests to the server in order to achieve any kind of graphical output to the screen.

X is not the only Window System available for Linux and other UNIX-like operating systems. Wayland is a more modern project with the aim of replacing X.

Prerequisites

  • A linux machine (or VM) with X installed and configured
  • The X11 development package libx11-dev (Ubuntu) libx11 (Arch)
  • The code for this post, which you can find here

Implementation

Most definitions for X11 can be found in the X11/Xlib.h header, so make sure to include this at the start of your program.

#include <X11/Xlib.h>

The first thing every X client needs to do is establish a connection with the X server. This is achieved by calling the XOpenDisplay function, which on success, returns a handle representing the connection established, commonly referred to as the “display”. From this point forward, the display handle can be used to issue commands to the x server, such as creating a window, getting input from the keyboard or drawing text. When the client application is about to quit or it no longer requires access to the Windowing system, it should close the connection by calling the XCloseDisplay function.

Display *display = XOpenDisplay(NULL); // display name

Once we have established a connection to the display, we can start making requests to the X server. For instance, we can request to create a new window by calling XCreateSimpleWindow. We can use XDefaultRootWindow to grab the root window for the display and use it as our parent window. Another way to create a window is by calling XCreateWindow instead, which provides more options for specifying window attributes, but we won’t cover it on this post.

Window window = XCreateSimpleWindow(
	display,
	XDefaultRootWindow(display),	// parent
	0, 0,							// x, y
	800, 600,						// width, height
	0,								// border width
	0x00000000,						// border color
	0x00000000						// background color
);

The XStoreName procedure let’s us set a name or caption for the window.

XStoreName(display, window, "Amazing X11 Window");

By default, the X server will not report any event to clients in order to save bandwitdh. A client application should specify which events it’s interested on, via XSelectInput with a mask of event types. In our case, we are only going to request to be notified about key press and key release events.

XSelectInput(display, window, KeyPressMask|KeyReleaseMask);

If you ran the program up to this point you would realize that no window is displayed to the screen. We first need to request for the window to be displayed or “mapped” by calling XMapWindow. You can think of mapping and unmapping as showing and hiding a window.

XMapWindow(display, window);

At the heart of any graphical application we have the event processing loop. There are many ways of writing an event loop, which may vary depending on the domain of your application, the event loop for a game is going to be different from the event loop for a spreadsheet program or a business management application.

bool quit = false;
while (!quit) {
	while (XPending(display) > 0) {
		XEvent event = {0};
		XNextEvent(display, &event);
		if (event.type == KeyPress) {
			quit = true;
		}
	}

	// Do your application work here
}

Finally, as we already discussed, the connection should be closed by calling XCloseDisplay before quitting the application.

XCloseDisplay(display);

Next steps

So far, we have only created the basic skeleton for a GUI application. From here onwards we could start working on many things, such as:

  • Drawing to the window
  • Add and improve event handling
  • Make use of hardware accelerated graphics via OpenGL or Vulkan

But we will leave that for next time 😉