From 3913d1778318cd0c6bfb871148d38abb33ec7fd3 Mon Sep 17 00:00:00 2001 From: nasr Date: Wed, 28 Jan 2026 13:13:40 +0100 Subject: checkpoint --- xlib-tutorial/2nd-program-anatomy.html | 282 +++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 xlib-tutorial/2nd-program-anatomy.html (limited to 'xlib-tutorial/2nd-program-anatomy.html') diff --git a/xlib-tutorial/2nd-program-anatomy.html b/xlib-tutorial/2nd-program-anatomy.html new file mode 100644 index 0000000..d156f7a --- /dev/null +++ b/xlib-tutorial/2nd-program-anatomy.html @@ -0,0 +1,282 @@ + + +Xlib programming tutorial: anatomy of the most basic Xlib program + + + +

Anatomy of the most basic Xlib program

+ +The program starts with the legal stuff: + +

+#include <X11/Xlib.h> // Every Xlib program must include this
+#include <assert.h>   // I include this to test return values the lazy way
+#include <unistd.h>   // So we got the profile for 10 seconds
+
+#define NIL (0)       // A name for the void pointer
+
+ +Then the serious thing. First we open a connection to the server. + +

+Display *dpy = XOpenDisplay(NIL);
+assert(dpy);
+
+ +If it fails (and it may), XOpenDisplay() will return NIL. + +

+ +We gonna create a window, but we need to get the window's background +color first. X uses a quite complex color model in order to accommodate +to every conceivable piece of hardware. Each color is encoded by an integer, +but the integer for a given color may change from a machine to another +one, and even on the same machine, from an execution of the program to +the next. The only "colors" that X guarantees to exist are black and +white. We can get them using the +BlackPixel() +and +WhitePixel() +macros. + +


+      int blackColor = BlackPixel(dpy, DefaultScreen(dpy));
+      int whiteColor = WhitePixel(dpy, DefaultScreen(dpy));
+
+ +As we yet can see, most of the Xlib calls take the "display" (the +value returned by +XOpenDisplay()) +as their first parameter. You want to know why ? + +

+ +There is still someting magic, (the +DefaultScreen() +stuff), but we gonna keep it for a later +explanation. We now can +create our window: + +


+      // Create the window
+
+      Window w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 
+				     200, 100, 0, blackColor, blackColor);
+
+ +Unlike what appears in the dialog, we use the +function +XCreateSimpleWindow() +instead of +XCreateWindow(). +XCreateSimpleWindow() +is not really simpler than +XCreateWindow() +(it takes only a few less parameters), but it uses less concepts, so +we gonna stick to it for now. There are still a bunch of parameters to +explain: + + + +

+      // We want to get MapNotify events
+
+      XSelectInput(dpy, w, StructureNotifyMask);
+
+ +As we're starting to know, X is based upon a +client-server architecture. The X server +sends events to the client (the program we're writing), to keep it +informed of the modifications in the server. There are many of them +(each time a window is created, moved, masked, unmasked, and many +other things), so a client must tell the server the events it is +interested in. With this XSelectInput() stuff, we tell the +server we want to be informed of "structural" changes occuring on the +w window. Creation and mapping are such changes. There is no +way to be informed for example of only mapping modification, and not +creations, so we've to take everything. In this particular application +we're interesting in "mapping" events (grosso modo, the window +appears on the screen). + +

+      // "Map" the window (that is, make it appear on the screen)
+
+      XMapWindow(dpy, w);
+
+ +And (once again) this is a client-server +system. The map request is asynchronous, meaning that the time this +instruction is executed doesn't tell us when the window is actually +mapped. To be sure, we've to wait for the server to send us a +MapNotify +event (this is why we want to be sensitive to such events). + +

+      // Create a "Graphics Context"
+
+      GC gc = XCreateGC(dpy, w, 0, NIL);
+
+ +Yet another magic stuff. But mastering them is the reason of the +existence of this tutorial... + +

+ +For several reasons, the graphical model of X is stateless, meaning +that the server doesn't remember (among other things) attributes such +as the drawing color, the thickness of the lines and so on. Thus, +we've to give all these parameters to the server on each +drawing request. To avoid passing two dozens of parameters, many of +them unchanged from one request to the next, X uses an object called +the Graphics Context, or GC for short. We store in the +graphics context all the needed parameters. Here, we want the color +used to draw lines, called the foregound color: + +


+      // Tell the GC we draw using the white color
+
+      XSetForeground(dpy, gc, whiteColor);
+
+ +There are many other parameters used to draw a line, but all of them +have reasonable default values. + +

+ +That's okay for now. Everything is set up, and we wait for the window +mapping. + +


+      // Wait for the MapNotify event
+
+      for(;;) {
+	    XEvent e;
+	    XNextEvent(dpy, &e);
+	    if (e.type == MapNotify)
+		  break;
+      }
+
+ +We loop, taking events as they come and discarding them. When we get a +MapNotify, we exit the loop. We may get events other than +MapNotify for two reasons: + + + +The non-maskable events are sent only in response to some program +requests (such as copying an area), so they aren't likely to happen in +our context. + +

+ +The +XNextEvent() +procedure is blocking, so if there are no event to read, the program +just wait inside the +XNextEvent(). + +

+ +When we have exited the loop, we have good confidence that the window +appears on the screen. Actually, this may not be the case since, for +example, the user may have iconified it using the +window manager, but for now, we assume the window +actually appears. We can draw our line: + +


+      // Draw the line
+      
+      XDrawLine(dpy, w, gc, 10, 60, 180, 20);
+
+ +The line is between points (10, 60) and (180, 20). The (0,0) is at the +upper left corner of the window, as usual. If the program just +sleeps here, nothing will happen, because, in case you don't +know, X has a client-server +architecture. Thus the request stays in the client, unless we tell it +to go to the server. This is done by XFlush(): + +

+      // Send the "DrawLine" request to the server
+
+      XFlush(dpy);
+
+ +Clever readers may have noticed that we didn't use +XFlush() +before, and it didn't prevent all the requests such as +XMapWindow() +to be sent to the server. The answer is that +XNextEvent() +performs an implicit +XFlush() +before trying to read some events. We have our line now, we just wait +for 10 seconds, so we can make people see how beautiful is our work: + +

+      // Wait for 10 seconds
+
+      sleep(10);
+
+ +That's all for now. In next +lesson, we will have a (very) little more interaction. [to be continued] + +
Christophe Tronche, ch.tronche@computer.org
+ + -- cgit v1.3