Beginner Xlib Tutorial

This document describes how to create a simple window, display the window on the screen, and how to draw two green rectangles. This document assumes that you are familiar with make files and compiling C/C++ files. If you are not familiar with make files and compiling C/C++ files then you should read the Understanding Compilation Flags and Makefiles tutorial.

This document and the example package may be copied and distributed provided that George Peter Staplin is given credit.

Common X Program Header Files


#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/Intrinsic.h>

Once that you have the header files included you can start by creating a structure for the connection to the X server. In the beginning of the source code add a line such as this:

Display *dis;

Create a variable to hold the window id.

For example:
Window win;

The next step is to create a window and map/display it on the screen.


int main() 
{
dis = XOpenDisplay(NULL);
win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 500, 500, \
0, BlackPixel (dis, 0), BlackPixel(dis, 0));
XMapWindow(dis, win);
XFlush(dis);
//Sleep 5 seconds before closing.
sleep(5);
return(0);
}

A complete program would probably check to see that XOpenDisplay does not return 0. If it did return 0 it should display an error message. The argument given to XOpenDisplay is the display name, which can be NULL. XOpenDisplay returns the display connection, which is placed in the dis variable.

The call to XCreateSimpleWindow uses the connection to the X server which is called dis, as the first argument. The next argument is the parent window, which is in this case the root window. The root window is the background of your desktop, it takes the display connection name and the screen number as the arguments. Next you have the X and Y coordinates for placing the window, which in our case are (X) 1 and (Y) 1. The next series of numbers which are 500 represent the size of the window. The next number 0 is the border width of the window. Then the last two arguments are for the border color and background color. Try replacing BlackPixel with WhitePixel. XCreateSimpleWindow returns a window id that is unique to this program. The id will change depending on when the program is run. For an in depth explanation see the manual page for XCreateSimpleWindow.

Map/Display the window using XMapWindow. It takes two arguments. The first argument is the display connection. The next argument is the variable name that stores the window id that was created with XCreateSimpleWindow.

The final request that you make will be to XFlush all requests to the X server. The X Window System has a queue for requests sent to the X server. Invoking XFlush causes all of the items in the queue to be executed. Without calling XFlush the window may not appear.

XEvents

Events in X are things like the mouse buttons being clicked, or the keys on the keyboard being pressed. The events can either be KeyPress or KeyRelease for control devices. When the window is resized the application is sent a ConfigureNotify event. When the window is below another window and is raised it is sent an Expose event, which would usually redraw the application. When the window is initially created an Expose event is sent.

The first step is to declare an X event.

XEvent report;

The next step is to tell the X server what kind of input the program wants to process.


XSelectInput(dis, win, ExposureMask | KeyPressMask | ButtonPressMask);

The first two arguments should be understood. The ExposureMask tells the X server that you want to process Expose events. The KeyPressMask tells the X server that you want to process KeyPress events. The ButtonPressMask tells the X server that you want to process mouse button events.

This is a simple event loop that outputs I have been exposed when the window first appears, and when the window is raised.


while (1)  {
XNextEvent(dis, &report);
switch  (report.type) {
        case Expose:   
	printf("I have been exposed.");
	fflush(stdout);
/*A local program function to redraw the window should be called.*/
	break;
                     }
	   }

This event loop is rather simple. It only checks for an expose event. XNextEvent waits for an event to occur. You can use other methods to get events, which are documented in the manual page for XNextEvent.

Now you will learn how to check if an event is a certain key being pressed. The first step is to put case KeyPress: in your switch for report.type. Place it in a similar manner as case Expose.


case KeyPress:
if (XLookupKeysym(&report.xkey, 0) == XK_space) 
{puts("The space bar was pressed.");}
break;

XLookupKeysym checks if the key pressed was equal to XK_space, and if it was it outputs a message. The keyboard key names can be found in /usr/X11R6/include/X11/keysymdef.h. More keyboard events can be processed in a similar manner.

Drawing in Color

You will need to have a drawing function that is called by an Expose event for this next part to work. You could have a simple Xlib function called such as XDrawLine after the expose event instead of having it call a local program function.

The first step is to create a variable for the graphics context for drawing. The next steps are to create a variable for the XColor structure, create a colormap for this window, create a character array with the color you wish to use in hexadecimal format, and finally set the foreground of the graphics context to the color. Hexadecimal format is base 16, which means that 255 in an RGB context would be FF. Only the most significant bits are counted.

Initializations

GC green_gc;
XColor green_col;
Colormap colormap;
char green[] = "#00FF00";

Assign a colormap to the colormap variable with the DefaultColormap function. The DefaultColormap function takes two arguments. The first argument is the display connection. The second argument is the screen number.


colormap = DefaultColormap(dis, 0);

Create the graphics context using XCreateGC and put the GC information in green_gc


green_gc = XCreateGC(dis, win, 0, 0);

Parse the color 00FF00 and allocate the color for later use.


XParseColor(dis, colormap, green, &green_col);
XAllocColor(dis, colormap, &green_col);

Now that the color has been allocated set the foreground of the graphics context with XSetForeground. The last argument to XSetForeground is the pixel value of the color allocated.


XSetForeground(dis, green_gc, green_col.pixel);

Now the program can draw using the foreground color set for green_gc.


case Expose:
XDrawRectangle(dis, win, green_gc, 1, 1, 497, 497);
XDrawRectangle(dis, win, green_gc, 50, 50, 398, 398);
break;

A package is available that provides a working Xlib example with a makefile. Download Xlib_Beginner.tgz

ThemeCounter