diff options
Diffstat (limited to 'doc/tutorial/index.html')
-rwxr-xr-x | doc/tutorial/index.html | 3772 |
1 files changed, 3772 insertions, 0 deletions
diff --git a/doc/tutorial/index.html b/doc/tutorial/index.html new file mode 100755 index 0000000..ac6e502 --- /dev/null +++ b/doc/tutorial/index.html @@ -0,0 +1,3772 @@ +<!DOCTYPE html public "-//W3C//DTD HTML 4.01 Transitional//EN" +"http://www.w3.org/TR/html4/loose.dtd"> + +<html> + +<head> + <title>Basic Graphics Programming With The XCB Library</title> + <link href="xcb.css" rel="stylesheet" type="text/css" /> +</head> + +<body> + <div class="title"> + Basic Graphics Programming With The XCB Library + </div> + <div class="toc"> + <ol> + <li><a class="section" href="#intro">Introduction</a></li> + <li><a class="section" href="#Xmodel">The client and server model of the X window system</a></li> + <li><a class="section" href="#asynch">GUI programming: the asynchronous model</a></li> + <li><a class="section" href="#notions">Basic XCB notions</a></li> + <ol> + <li><a class="subsection" href="#conn">The X Connection</a></li> + <li><a class="subsection" href="#requestsreplies">Requests and replies: the Xlib killers</a></li> + <li><a class="subsection" href="#gc">The Graphics Context</a></li> + <li>Object handles</li> + <li>Memory allocation for XCB structures</li> + <li><a class="subsection" href="#events">Events</a></li> + </ol> + <li><a class="section" href="#use">Using XCB-based programs</a></li> + <ol> + <li><a class="subsection" href="#inst">Installation of XCB</a></li> + <li><a class="subsection" href="#comp">Compiling XCB-based programs</a></li> + </ol> + <li><a class="section" href="#openconn">Opening and closing the connection to an X server</a></li> + <li><a class="section" href="#screen">Checking basic information about a connection</a></li> + <li><a class="section" href="#helloworld">Creating a basic window - the "hello world" program</a></li> + <li><a class="section" href="#drawing">Drawing in a window</a></li> + <ol> + <li><a class="subsection" href="#allocgc">Allocating a Graphics Context</a></li> + <li><a class="subsection" href="#changegc">Changing the attributes of a Graphics Context</a></li> + <li><a class="subsection" href="#drawingprim">Drawing primitives: point, line, box, circle,...</a></li> + </ol> + <li><a class="section" href="#xevents">X Events</a></li> + <ol> + <li><a class="subsection" href="#register">Registering for event types using event masks</a></li> + <li><a class="subsection" href="#loop">Receiving events: writing the events loop</a></li> + <li><a class="subsection" href="#expose">Expose events</a></li> + <li><a class="subsection" href="#userinput">Getting user input</a></li> + <ol> + <li><a class="subsubsection" href="#mousepressrelease">Mouse button press and release events</a></li> + <li><a class="subsubsection" href="#mousemvnt">Mouse movement events</a></li> + <li><a class="subsubsection" href="#mouseenter">Mouse pointer enter and leave events</a></li> + <li><a class="subsubsection" href="#focus">The keyboard focus</a></li> + <li><a class="subsubsection" href="#keypress">Keyboard press and release events</a></li> + </ol> + <li><a class="subsection" href="#eventex">X events: a complete example</a></li> + </ol> + <li><a class="section" href="#font">Handling text and fonts</a></li> + <ol> + <li><a class="subsection" href="#fontstruct">The Font structure</a></li> + <li>Loading a Font</li> + <li>Assigning a Font to a Graphic Context</li> + <li>Drawing text in a window</li> + </ol> + <li>Windows hierarchy</li> + <ol> + <li>Root, parent and child windows</li> + <li>Events propagation</li> + </ol> + <li><a class="section" href="#wm">Interacting with the window manager</a></li> + <ol> + <li><a class="subsection" href="#wmprop">Window properties</a></li> + <li><a class="subsection" href="#wmname">Setting the window name and icon name</a></li> + <li>Setting preferred window size(s)</li> + <li>Setting miscellaneous window manager hints</li> + <li>Setting an application's icon</li> + </ol> + <li><a class="section" href="#winop">Simple window operations</a></li> + <ol> + <li><a class="subsection" href="#winmap">Mapping and un-mapping a window</a></li> + <li><a class="subsection" href="#winconf">Configuring a window</a></li> + <li><a class="subsection" href="#winmove">Moving a window around the screen</a></li> + <li><a class="subsection" href="#winsize">Resizing a window</a></li> + <li><a class="subsection" href="#winstack">Changing windows stacking order: raise and lower</a></li> + <li>Iconifying and de-iconifying a window</li> + <li><a class="subsection" href="#wingetinfo">Getting informations about a window</a></li> + </ol> + <li><a class="section" href="#usecolor">Using colors to paint the rainbow</a></li> + <ol> + <li><a class="subsection" href="#colormap">Color maps</a></li> + <li><a class="subsection" href="#colormapalloc">Allocating and freeing Color Maps</a></li> + <li><a class="subsection" href="#alloccolor">Allocating and freeing a color entry</a></li> + <li>Drawing with a color</li> + </ol> + <li><a class="section" href="#pixmaps">X Bitmaps and Pixmaps</a></li> + <ol> + <li><a class="subsection" href="#pixmapswhat">What is a X Bitmap ? An X Pixmap ?</a></li> + <li>Loading a bitmap from a file</li> + <li>Drawing a bitmap in a window</li> + <li><a class="subsection" href="#pixmapscreate">Creating a pixmap</a></li> + <li><a class="subsection" href="#pixmapsdraw">Drawing a pixmap in a window</a></li> + <li><a class="subsection" href="#pixmapsfree">Freeing a pixmap</a></li> + </ol> + <li>Messing with the mouse cursor</li> + <ol> + <li>Creating and destroying a mouse cursor</li> + <li>Setting a window's mouse cursor</li> + </ol> + <li><a class="subsection" href="#translation">Translation of basic Xlib functions and macros</a></li> + <ol> + <li><a class="subsection" href="#displaystructure">Members of the Display structure</a></li> + <ol> + <li><a class="subsection" href="#ConnectionNumber">ConnectionNumber</a></li> + <li><a class="subsection" href="#DefaultScreen">DefaultScreen</a></li> + <li><a class="subsection" href="#QLength">QLength</a></li> + <li><a class="subsection" href="#ScreenCount">ScreenCount</a></li> + <li><a class="subsection" href="#ServerVendor">ServerVendor</a></li> + <li><a class="subsection" href="#ProtocolVersion">ProtocolVersion</a></li> + <li><a class="subsection" href="#ProtocolRevision">ProtocolRevision</a></li> + <li><a class="subsection" href="#VendorRelease">VendorRelease</a></li> + <li><a class="subsection" href="#DisplayString">DisplayString</a></li> + <li><a class="subsection" href="#BitmapUnit">BitmapUnit</a></li> + <li><a class="subsection" href="#BitmapBitOrder">BitmapBitOrder</a></li> + <li><a class="subsection" href="#BitmapPad">BitmapPad</a></li> + <li><a class="subsection" href="#ImageByteOrder">ImageByteOrder</a></li> + </ol> + <li><a class="subsection" href="#screenofdisplay">ScreenOfDisplay related functions</a></li> + <ol> + <li><a class="subsection" href="#ScreenOfDisplay">ScreenOfDisplay</a></li> + <li><a class="subsection" href="#DefaultScreenOfDisplay">DefaultScreenOfDisplay</a></li> + <li><a class="subsection" href="#RootWindow">RootWindow / RootWindowOfScreen</a></li> + <li><a class="subsection" href="#DefaultRootWindow">DefaultRootWindow</a></li> + <li><a class="subsection" href="#DefaultVisual">DefaultVisual / DefaultVisualOfScreen</a></li> + <li><a class="subsection" href="#DefaultGC">DefaultGC / DefaultGCOfScreen</a></li> + <li><a class="subsection" href="#BlackPixel">BlackPixel / BlackPixelOfScreen</a></li> + <li><a class="subsection" href="#WhitePixel">WhitePixel / WhitePixelOfScreen</a></li> + <li><a class="subsection" href="#DisplayWidth">DisplayWidth / WidthOfScreen</a></li> + <li><a class="subsection" href="#DisplayHeight">DisplayHeight / HeightOfScreen</a></li> + <li><a class="subsection" href="#DisplayWidthMM">DisplayWidthMM / WidthMMOfScreen</a></li> + <li><a class="subsection" href="#DisplayHeightMM">DisplayHeightMM / HeightMMOfScreen</a></li> + <li><a class="subsection" href="#DisplayPlanes">DisplayPlanes / DefaultDepth / DefaultDepthOfScreen / PlanesOfScreen</a></li> + <li><a class="subsection" href="#DefaultColormap">DefaultColormap / DefaultColormapOfScreen</a></li> + <li><a class="subsection" href="#MinCmapsOfScreen">MinCmapsOfScreen</a></li> + <li><a class="subsection" href="#MaxCmapsOfScreen">MaxCmapsOfScreen</a></li> + <li><a class="subsection" href="#DoesSaveUnders">DoesSaveUnders</a></li> + <li><a class="subsection" href="#DoesBackingStore">DoesBackingStore</a></li> + <li><a class="subsection" href="#EventMaskOfScreen">EventMaskOfScreen</a></li> + </ol> + <li><a class="subsection" href="#misc">Miscellaneaous macros</a></li> + <ol> + <li><a class="subsection" href="#DisplayOfScreen">DisplayOfScreen</a></li> + <li><a class="subsection" href="#DisplayCells">DisplayCells / CellsOfScreen</a></li> + </ol> + </ol> + </ol> + </div> + <div class="section"> + <ol> + <li class="title"><a name="intro">Introduction</a></li> + <p> + This tutorial is based on the + <a href="http://users.actcom.co.il/~choo/lupg/tutorials/xlib-programming/xlib-programming.html">Xlib Tutorial</a> + written by <a href="mailto:choor@atcom.co.il">Guy Keren</a>. The + author allowed me to take some parts of his text, mainly the text which + deals with the X Windows generality. + </p> + <p> + This tutorial is intended to people who want to start to program + with the <a href="http://xcb.freedesktop.org">XCB</a> + library. As for the <a href="http://tronche.com/gui/x/xlib/introduction">Xlib</a> + library, it is useless and a real X + programmer should use a much higher level of abstraction, such + as using Motif, + <a href="http://www.lesstif.org">LessTiff</a>, + <a href="http://www.gtk.org">GTK</a>, + <a href="http://www.trolltech.com">QT</a> or + <a href="http://www.enlightenment.org">EWL</a>. However, + we need to start somewhere. More than this, knowing how things + work down below is never a bad idea. + </p> + <p> + After reading this tutorial, one should be able to write very + simple graphical programs, but not programs with a descent user + interface. For such programs, one of the previously mentioned + library should be used. + </p> + <p> + But what is XCB ? Xlib has been + the standard C binding for the <a href="http://www.xfree86.org">X + Window System</a> protocol for many years now. It is an + excellent piece of work, but there are applications for which it + is not ideal, for example + <ul> + <li><b>Small platforms</b>: Xlib is a large piece of code, and + it's difficult to make it smaller</li> + <li><b>Latency hiding</b>: Xlib requests requiring a reply are + effectively synchronous: they block until the reply appears, + whether the result is needed immediately or not.</li> + <li><b>Direct access to the protocol</b>: Xlib does quite a + bit of caching, layering, and similar optimizations. While this + is normally a feature, it makes it difficult to simply emit + specified X protocol requests and process specific + responses.</li> + <li><b>Threaded applications</b>: While Xlib does attempt to + support multithreading, the API makes this difficult and + error-prone.</li> + <li><b>New extensions</b>: The Xlib infrastructure provides + limited support for the new creation of X extension client side + code.</li> + </ul> + </p> + <p> + For these reasons, among others, XCB, an X C binding, has been + designed to solve the above problems and thus provide a base for + <ul> + <li>Toolkit implementation.</li> + <li>Direct protocol-level programming.</li> + <li>Lightweight emulation of commonly used portions of the + Xlib API (in progress)</li> + </ul> + </p> + <p></p> + <li class="title"><a name="Xmodel">The client and server model of the X window system</a></li> + <p> + The X Window System was developed with one major goal: + flexibility. The idea was that the way things look is one thing, + but the way things work is another matter. Thus, the lower + levels provide the tools required to draw windows, handle user + input, allow drawing graphics using colors (or black and white + screens), etc. To this point, a decision was made to separate + the system into two parts. A client that decides what to do, and + a server that actually draws on the screen and reads user input + in order to send it to the client for processing. + </p> + <p> + This model is the complete opposite of what is used to when + dealing with clients and servers. In our case, the user seats + near the machine controlled by the server, while the client + might be running on a remote machine. The server controls the + screens, mouse and keyboard. A client may connect to the server, + request that it draws a window (or several windows), and ask the + server to send it any input the user sends to these + windows. Thus, several clients may connect to a single X server + (one might be running an mail software, one running a WWW + browser, etc). When input is sent by the user to some window, + the server sends a message to the client controlling this window + for processing. The client decides what to do with this input, + and sends the server requests for drawing in the window. + </p> + <p> + The whole session is carried out using the X message + protocol. This protocol was originally carried over the TCP/IP + protocol suite, allowing the client to run on any machine + connected to the same network that the server is. Later on, the + X servers were extended to allow clients running on the local + machine with more optimized access to the server (note that an X + protocol message may be several hundreds of KB in size), such as + using shred memory, or using Unix domain sockets (a method for + creating a logical channel on a Unix system between two processors). + </p> + <li class="title"><a name="asynch">GUI programming: the asynchronous model</a></li> + <p> + Unlike conventional computer programs, that carry some serial + nature, a GUI program usually uses an asynchronous programming + model, also known as "event-driven programming". This means that + that program mostly sits idle, waiting for events sent by the X + server, and then acts upon these events. An event may say "The + user pressed the 1st button mouse in spot (x,y)", or "The window + you control needs to be redrawn". In order for the program to e + responsive to the user input, as well as to refresh requests, it + needs to handle each event in a rather short period of time + (e.g. less that 200 milliseconds, as a rule of thumb). + </p> + <p> + This also implies that the program may not perform operations + that might take a long time while handling an event (such as + opening a network connection to some remote server, or + connecting to a database server, or even performing a long file + copy operation). Instead, it needs to perform all these + operations in an asynchronous manner. This may be done by using + various asynchronous models to perform the longish operations, + or by performing them in a different process or thread. + </p> + <p> + So the way a GUI program looks is something like that: + <ol> + <li>Perform initialization routines.</li> + <li>Connect to the X server.</li> + <li>Perform X-related initialization.</li> + <li>While not finished:</li> + <ol> + <li>Receive the next event from the X server.</li> + <li>Handle the event, possibly sending various drawing + requests to the X server.</li> + <li>If the event was a quit message, exit the loop.</li> + </ol> + <li>Close down the connection to the X server. </li> + <li>Perform cleanup operations.</li> + </ol> + </p> + <p></p> + <li class="title"><a name="notions">Basic XCB notions</a></li> + <p> + XCB has been created to eliminate the needs of + programs to actually implement the X protocol layer. This + library gives a program a very low-level access to any X + server. Since the protocol is standardized, a client using any + implementation of XCB may talk with any X server (the same + occurs for Xlib, of course). We now give a brief description of + the basic XCB notions. They will be detailed later. + </p> + <ol> + <li class="subtitle"><a name="conn">The X Connection</a></li> + <p> + The major notion of using XCB is the X Connection. This is a + structure representing the connection we have open with a + given X server. It hides a queue of messages coming from the + server, and a queue of pending requests that our client + intends to send to the server. In XCB, this structure is named + 'XCBConnection'. When we open a connection to an X server, the + library returns a pointer to such a structure. Later, we + supply this pointer to any XCB function that should send + messages to the X server or receive messages from this server. + </p> + <li class="subtitle"><a name="requestsreplies">Requests and + replies: the Xlib killers</a></li> + <p> + To ask informations to the X server, we have to make a request + and ask for a reply. With Xlib, these two tasks are + automatically done: Xlib locks the system, sends a request, + waits for a reply from the X server and unlocks. This is + annoying, especially if one makes a lot of requests to the X + server. Indeed, Xlib has to wait for the end of a reply + before asking for the next request (because of the locks that + Xlib sends). For example, here is a time-line of N=4 + requests/replies with Xlib, with a round-trip latency + <b>T_round_trip</b> that is 5 times long as the time required + to write or read a request/reply (<b>T_write/T_read</b>): + </p> + <pre class="text"> + W-----RW-----RW-----RW-----R +</pre> + <ul> + <li>W: Writing request</li> + <li>-: Stalled, waiting for data</li> + <li>R: Reading reply</li> + </ul> + <p> + The total time is N * (T_write + T_round_trip + T_read). + </p> + <p> + With XCB, we can suppress most of the round-trips as the + requests and the replies are not locked. We usually send a + request, then XCB returns to us a <b>cookie</b>, which is an + identifier. Then, later, we ask for a reply using this + <b>cookie</b> and XCB returns a + pointer to that reply. Hence, with XCB, we can send a lot of + requests, and later in the program, ask for all the replies + when we need them. Here is the time-line for 4 + requests/replies when we use this property of XCB: + </p> + <pre class="text"> + WWWW--RRRR +</pre> + <p> + The total time is N * T_write + max (0, T_round_trip - (N-1) * + T_write) + N * T_read. Which can be considerably faster than + all those Xlib round-trips. + </p> + <p> + Here is a program that computes the time to create 500 atoms + with Xlib and XCB. It shows the Xlib way, the bad XCB way + (which is similar to Xlib) and the good XCB way. On my + computer, XCB is 25 times faster than Xlib. + </p> + <pre class="code"> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> + +#include <X11/XCB/xcb.h> + +#include <X11/Xlib.h> + +double +get_time(void) +{ + struct timeval timev; + + gettimeofday(&timev, NULL); + + return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000); +} + +int +main () +{ + XCBConnection *c; + XCBATOM *atoms; + XCBInternAtomCookie *cs; + char **names; + int count; + int i; + double start; + double end; + double diff; + + /* Xlib */ + Display *disp; + Atom *atoms_x; + double diff_x; + + c = XCBConnectBasic (); + + count = 500; + atoms = (XCBATOM *)malloc (count * sizeof (atoms)); + names = (char **)malloc (count * sizeof (char *)); + + /* init names */ + for (i = 0; i < count; ++i) + { + char buf[100]; + + sprintf (buf, "NAME%d", i); + names[i] = strdup (buf); + } + + /* bad use */ + start = get_time (); + + for (i = 0; i < count; ++i) + atoms[i] = XCBInternAtomReply (c, + XCBInternAtom (c, + 0, + strlen(names[i]), + names[i]), + NULL)->atom; + + end = get_time (); + diff = end - start; + printf ("bad use time : %f\n", diff); + + /* good use */ + start = get_time (); + + cs = (XCBInternAtomCookie *) malloc (count * sizeof(XCBInternAtomCookie)); + for(i = 0; i < count; ++i) + cs[i] = XCBInternAtom (c, 0, strlen(names[i]), names[i]); + + for(i = 0; i < count; ++i) + { + XCBInternAtomRep *r; + + r = XCBInternAtomReply(c, cs[i], 0); + if(r) + atoms[i] = r->atom; + free(r); + } + + end = get_time (); + printf ("good use time : %f\n", end - start); + printf ("ratio : %f\n", diff / (end - start)); + diff = end - start; + + /* free var */ + for (i = 0; i < count; ++i) + { + free (names[i]); + } + free (atoms); + free (cs); + + XCBDisconnect (c); + + /* Xlib */ + disp = XOpenDisplay (getenv("DISPLAY")); + + atoms_x = (Atom *)malloc (count * sizeof (atoms_x)); + + start = get_time (); + + for (i = 0; i < count; ++i) + atoms_x[i] = XInternAtom(disp, names[i], 0); + + end = get_time (); + diff_x = end - start; + printf ("Xlib use time : %f\n", diff_x); + printf ("ratio : %f\n", diff_x / diff); + + free (atoms_x); + free (names); + + XCloseDisplay (disp); + + return 1; +} +</pre> + <li class="subtitle"><a name="gc">The Graphic Context</a></li> + <p> + When we perform various drawing operations (graphics, text, + etc), we may specify various options for controlling how the + data will be drawn (what foreground and background colors to + use, how line edges will be connected, what font to use when + drawing some text, etc). In order to avoid the need to supply + hundreds of parameters to each drawing function, a graphical + context structure is used. We set the various drawing options + in this structure, and then, we pass a pointer to this + structure to any drawing routines. This is rather handy, as we + often need to perform several drawing requests with the same + options. Thus, we would initialize a graphical context, set + the desired options, and pass this structure to all drawing + functions. + </p> + <p> + Note that graphic contexts have no client-side structure in + XCB, they're just XIDs. Xlib has a client-side structure + because it caches the GC contents so it can avoid making + redundant requests, but of course XCB doesn't do that. + </p> + <li class="subtitle"><a name="events">Events</a></li> + <p> + A structure is used to pass events received from the X + server. XCB supports exactly the events specified in the + protocol (33 events). This structure contains the type + of event received, as well as the data associated with the + event (e.g. position on the screen where the event was + generated, mouse button associated with the event, region of + the screen associated with a "redraw" event, etc). The way to + read the event's data epends on the event type. + </p> + </ol> + <p></p> + <li class="title"><a name="use">Using XCB-based programs</a></li> + <p></p> + <ol> + <li class="subtitle"><a name="inst">Installation of XCB</a></li> + <p> + To build XCB from source, you need to have installed at + least: + </p> + <ul> + <li>pkgconfig 0.15.0</li> + <li>automake 1.7</li> + <li>autoconf 2.50</li> + <li><a href="http://www.check.org">check</a></li> + <li><a href="http://xmlsoft.org/XSLT/">xsltproc</a></li> + </ul> + <p> + You have to checkout in CVS the following modules: + </p> + <ul> + <li>Xproto from xlibs</li> + <li>Xau from xlibs</li> + <li>xcb-proto</li> + <li>xcb</li> + </ul> + <p> + Note that Xproto and xcb-proto exist only to install header + files, so typing 'make' or 'make all' will produce the message + "Nothing to be done for 'all'". That's normal. + </p> + <li class="subtitle"><a name="comp">Compiling XCB-based programs</a></li> + <p> + Compiling XCB-based programs requires linking them with the XCB + library. This is easily done thanks to pkgconfig: + </p> + <pre class="text"> +gcc -Wall prog.c -o prog `pkg-config --cflags --libs xcb` +</pre> + </ol> + <li class="title"><a name="openconn">Opening and closing the connection to an X server</a></li> + <p> + An X program first needs to open the connection to the X + server. There is a function that opens a connection. It requires + the display name, or NULL. In the latter case, the display name + will be the one in the environment variable DISPLAY. + </p> + <pre class="code"> +XCBConnection *XCBConnect (const char *displayname, + int *screenp); +</pre> + <p> + The second parameter returns the screen number used for the + connection. The returned structure describes an XCB connection + and is opaque. Here is how the connection can be opened: + </p> + <pre class="code"> +#include <X11/XCB/xcb.h> + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + + /* Open the connection to the X server. use the DISPLAY environment variable as the default display name */ + c = XCBConnect (NULL, NULL); + + return 1; +} +</pre> + <p> + To close a connection, it suffices to use: + </p> + <pre class="code"> +void XCBDisconnect (XCBConnection *c); +</pre> + <div class="comp"> + <div class="title"> + Comparison Xlib/XCB + </div> + <div class="xlib"> + <ul> + <li>XOpenDisplay ()</li> + </ul> + </div> + <div class="xcb"> + <ul> + <li>XCBConnect ()</li> + </ul> + </div> + <div class="xlib"> + <ul> + <li>XCloseDisplay ()</li> + </ul> + </div> + <div class="xcb"> + <ul> + <li>XCBDisconnect ()</li> + </ul> + </div> + </div> + <p> + </p> + <li class="title"><a name="screen">Checking basic information about a connection</a></li> + <p> + Once we opened a connection to an X server, we should check some + basic informations about it: what screens it has, what is the + size (width and height) of the screen, how many colors it + supports (black and white ? grey scale ?, 256 colors ? more ?), + and so on. We get such informations from the XCBSCREEN + structure: + </p> + <pre class="code"> +typedef struct { + XCBWINDOW root; + XCBCOLORMAP default_colormap; + CARD32 white_pixel; + CARD32 black_pixel; + CARD32 current_input_masks; + CARD16 width_in_pixels; + CARD16 height_in_pixels; + CARD16 width_in_millimeters; + CARD16 height_in_millimeters; + CARD16 min_installed_maps; + CARD16 max_installed_maps; + XCBVISUALID root_visual; + BYTE backing_stores; + BOOL save_unders; + CARD8 root_depth; + CARD8 allowed_depths_len; +} XCBSCREEN; +</pre> + <p> + We could retrieve the first screen of the connection by using the + following function: + </p> + <pre class="code"> +XCBSCREENIter XCBConnSetupSuccessRepRootsIter (XCBConnSetupSuccessRep *R); +</pre> + <p> + Here is a small program that shows how to use this function: + </p> + <pre class="code"> +#include <stdio.h> + +#include <X11/XCB/xcb.h> + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + XCBSCREEN *screen; + int screen_nbr; + XCBSCREENIter iter; + + /* Open the connection to the X server. Use the DISPLAY environment variable */ + c = XCBConnect (NULL, &screen_nbr); + + /* Get the screen #screen_nbr */ + iter = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)); + for (; iter.rem; --screen_nbr, XCBSCREENNext (&iter)) + if (screen_nbr == 0) + { + screen = iter.data; + break; + } + + printf ("\n"); + printf ("Informations of screen %ld:\n", screen->root.xid); + printf (" width.........: %d\n", screen->width_in_pixels); + printf (" height........: %d\n", screen->height_in_pixels); + printf (" white pixel...: %ld\n", screen->white_pixel); + printf (" black pixel...: %ld\n", screen->black_pixel); + printf ("\n"); + + return 1; +} +</pre> + <li class="title"><a name="helloworld">Creating a basic window - the "hello world" program</a></li> + <p> + After we got some basic informations about our screen, we can + create our first window. In the X Window System, a window is + characterized by an Id. So, in XCB, a window is of type: + </p> + <pre class="code"> +typedef struct { + CARD32 xid; +} XCBWINDOW; +</pre> + <p> + We first ask for a new Id for our window, with this function: + </p> + <pre class="code"> +XCBWINDOW XCBWINDOWNew(XCBConnection *c); +</pre> + <p> + Then, XCB supplies the following function to create new windows: + </p> + <pre class="code"> +XCBVoidCookie XCBCreateWindow (XCBConnection *c, /* Pointer to the XCBConnection structure */ + CARD8 depth, /* Depth of the screen */ + XCBWINDOW wid, /* Id of the window */ + XCBWINDOW parent, /* Id of an existing window that should be the parent of the new window */ + INT16 x, /* X position of the top-left corner of the window (in pixels) */ + INT16 y, /* Y position of the top-left corner of the window (in pixels) */ + CARD16 width, /* Width of the window (in pixels) */ + CARD16 height, /* Height of the window (in pixels) */ + CARD16 border_width, /* Width of the window's border (in pixels) */ + CARD16 _class, + XCBVISUALID visual, + CARD32 value_mask, + const CARD32 *value_list); +</pre> + <p> + The fact that we created the window does not mean that it will + be drawn on screen. By default, newly created windows are not + mapped on the screen (they are invisible). In order to make our + window visible, we use the function <span class="code">XCBMapWindow()</span>, whose + prototype is + </p> + <pre class="code"> +XCBVoidCookie XCBMapWindow (XCBConnection *c, XCBWINDOW window); +</pre> + <p> + Finally, here is a small program to create a window of size + 150x150 pixels, positioned at the top-left corner of the screen: + </p> + <pre class="code"> +#include <unistd.h> + +#include <X11/XCB/xcb.h> + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + XCBSCREEN *screen; + XCBDRAWABLE win; + + /* Open the connection to the X server */ + c = XCBConnect (NULL, NULL); + + /* Get the first screen */ + screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data; + + /* Ask for our window's Id */ + win.window = XCBWINDOWNew(c); + + /* Create the window */ + XCBCreateWindow (c, /* Connection */ + 0, /* depth */ + win.window, /* window Id */ + screen->root, /* parent window */ + 0, 0, /* x, y */ + 150, 150, /* width, height */ + 10, /* border_width */ + InputOutput, /* class */ + screen->root_visual, /* visual */ + 0, NULL); /* masks, not used yet */ + + /* Map the window on the screen */ + XCBMapWindow (c, win.window); + + XCBSync (c, 0); + + pause (); + + return 1; +} +</pre> + <p> + In this code, you see one more function - <span class="code">XCBSync()</span>, not explained + yet. It is used to flush all the pending requests. More + precisely, there are 2 functions that do such things. The first + one is <span class="code">XCBFlush()</span>: + </p> + <pre class="code"> +int XCBFlush (XCBConnection *c); +</pre> + <p> + This function flushes all pending requests to the X server (much + like the <span class="code">fflush()</span> function is used to + flush standard output). The second function is + <span class="code">XCBSync()</span>: + </p> + <pre class="code"> +int XCBSync(XCBConnection *c, XCBGenericError **e); +</pre> + <p> + This functions also flushes all pending requests to the X + server, and then waits until the X server finishing processing + these requests. In a normal program, this will not be necessary + (we'll see why when we get to write a normal X program), but for + now, we put it there. + </p> + <p> + The window that is created by the above code has a default + background (gray). This one can be set to a specific color, + thanks to the two last parameters of + <span class="code">XCBCreateWindow()</span>, which are not + described yet. See the subsections + <a href="#winconf">Configuring a window</a> or + <a href="#winconf">Registering for event types using event masks</a> + for exemples on how to use these parameters. In addition, as no + events are handled, you have to make a Ctrl-C to interrupt the + program. + </p> + <p> + <b>TODO</b>: one should tell what these functions return and + about the generic error + </p> + <div class="comp"> + <div class="title"> + Comparison Xlib/XCB + </div> + <div class="xlib"> + <ul> + <li>XCreateWindow ()</li> + </ul> + </div> + <div class="xcb"> + <ul> + <li>XCBWINDOWNew ()</li> + <li>XCBCreateWindow ()</li> + </ul> + </div> + </div> + <p></p> + <li class="title"><a name="drawing">Drawing in a window</a></li> + <p> + Drawing in a window can be done using various graphical + functions (drawing pixels, lines, rectangles, etc). In order to + draw in a window, we first need to define various general + drawing parameters (what line width to use, which color to draw + with, etc). This is done using a graphical context. + </p> + <ol> + <li class="subtitle"><a name="allocgc">Allocating a Graphics Context</a></li> + <p> + As we said, a graphical context defines several attributes to + be used with the various drawing functions. For this, we + define a graphical context. We can use more than one graphical + context with a single window, in order to draw in multiple + styles (different colors, different line widths, etc). In XCB, + a Graphics Context is, as a window, characterized by an Id: + </p> + <pre class="code"> +typedef struct { + CARD32 xid; +} XCBGCONTEXT; +</pre> + <p> + We first ask the X server to attribute an Id to our graphic + context with this function: + </p> + <pre class="code"> +XCBGCONTEXT XCBGCONTEXTNew (XCBConnection *c); +</pre> + <p> + Then, we set the attributes of the graphic context with this function: + </p> + <pre class="code"> +XCBVoidCookie XCBCreateGC (XCBConnection *c, + XCBGCONTEXT cid, + XCBDRAWABLE drawable, + CARD32 value_mask, + const CARD32 *value_list); +</pre> + <p> + We give now an example on how to allocate a graphic context + that specifies that each drawing functions that use it will + draw in foreground with a black color. + </p> + <pre class="code"> +#include <X11/XCB/xcb.h> + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + XCBSCREEN *screen; + XCBDRAWABLE win; + XCBGCONTEXT black; + CARD32 mask; + CARD32 value[1]; + + /* Open the connection to the X server and get the first screen */ + c = XCBConnect (NULL, NULL); + screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data; + + /* Create a black graphic context for drawing in the foreground */ + win.window = screen->root; + black = XCBGCONTEXTNew (c); + mask = GCForeground; + value[0] = screen->black_pixel; + XCBCreateGC (c, black, win, mask, value); + + return 1; +} +</pre> + <p> + Note should be taken regarding the role of "value_mask" and + "value_list" in the prototype of <span class="code">XCBCreateGC()</span>. Since a + graphic context has many attributes, and since we often just + want to define a few of them, we need to be able to tell the + <span class="code">XCBCreateGC()</span> which attributes we + want to set. This is what the "value_mask" parameter is + for. We then use the "value_list" parameter to specify actual + values for the attribute we defined in "value_mask". Thus, for + each constant used in "value_list", we will use the matching + constant in "value_mask". In this case, we define a graphic + context with one attribute: when drawing (a point, a line, + etc), the foreground color will be black. The rest of the + attributes of this graphic context will be set to their + default values. + </p> + <p> + See the next Subsection for more details. + </p> + <div class="comp"> + <div class="title"> + Comparison Xlib/XCB + </div> + <div class="xlib"> + <ul> + <li>XCreateGC ()</li> + </ul> + </div> + <div class="xcb"> + <ul> + <li>XCBGCONTEXTNew ()</li> + <li>XCBCreateGC ()</li> + </ul> + </div> + </div> + <p></p> + <li class="subtitle"><a name="changegc">Changing the attributes of a Graphics Context</a></li> + <p> + Once we have allocated a Graphic Context, we may need to + change its attributes (for example, changing the foreground + color we use to draw a line, or changing the attributes of the + font we use to display strings. See Subsections Drawing with a + color and Assigning a Font to a Graphic Context). This is done + by using this function: + </p> + <pre class="code"> +XCBVoidCookie XCBChangeGC (XCBConnection *c, /* The XCB Connection */ + XCBGCONTEXT gc, /* The Graphic Context */ + CARD32 value_mask, /* Components of the Graphic Context that have to be set */ + const CARD32 *value_list); /* Value as specified by value_mask */ +</pre> + <p> + The <span class="code">value_mask</span> parameter could take + these values: + </p> + <ul> + <li>GCFunction</li> + <li>GCPlaneMask</li> + <li>GCForeground</li> + <li>GCBackground</li> + <li>GCLineWidth</li> + <li>GCLineStyle</li> + <li>GCCapStyle</li> + <li>GCJoinStyle</li> + <li>GCFillStyle</li> + <li>GCFillRule</li> + <li>GCTile</li> + <li>GCStipple</li> + <li>GCTileStipXOrigin</li> + <li>GCTileStipYOrigin</li> + <li>GCFont</li> + <li>GCSubwindowMode</li> + <li>GCGraphicsExposures</li> + <li>GCClipXOrigin</li> + <li>GCClipYOrigin</li> + <li>GCClipMask</li> + <li>GCDashOffset</li> + <li>GCDashList</li> + <li>GCArcMode</li> + </ul> + <p> + It is possible to set several attributes at the same + time (for example setting the attributes of a font and the + color which will be used to display a string), by OR'ing these + values in <span class="code">value_mask</span>. Then + <span class="code">value_list</span> has to be an array which + lists the value for the respective attributes. See Subsection + Drawing with a color to have an example. + </p> + <p> + <b>TODO</b>: set the links of the 3 subsections, once they will + be written :) + </p> + <p> + <b>TODO</b>: give an example which sets several attributes. + </p> + <li class="subtitle"><a name="drawingprim">Drawing primitives: point, line, box, circle,...</a></li> + <p> + After we have created a Graphic Context, we can draw on a + window using this Graphic Context, with a set of XCB + functions, collectively called "drawing primitive". Let see + how they are used. + </p> + <p> + To draw a point, or several points, we use + </p> + <pre class="code"> +XCBVoidCookie XCBPolyPoint (XCBConnection *c, /* The connection to the X server */ + BYTE coordinate_mode, /* Coordinate mode, usually set to CoordModeOrigin */ + XCBDRAWABLE drawable, /* The drawable on which we want to draw the point(s) */ + XCBGCONTEXT gc, /* The Graphic Context we use to draw the point(s) */ + CARD32 points_len, /* The number of points */ + const XCBPOINT *points); /* An array of points */ +</pre> + <p> + The <span class="code">coordinate_mode</span> parameter + specifies the coordinate mode. Available values are + </p> + <ul> + <li><span class="code">CoordModeOrigin</span></li> + <li><span class="code">CoordModePrevious</span></li> + </ul> + <p> + The <span class="code">XCBPOINT</span> type is just a + structure with two fields (the coordinates of the point): + </p> + <pre class="code"> +typedef struct { + INT16 x; + INT16 y; +} XCBPOINT; +</pre> + <p> + You could see an example in xpoints.c. <b>TODO</b> Set the link. + </p> + <p> + To draw a line, or a polygonal line, we use + </p> + <pre class="code"> +XCBVoidCookie XCBPolyLine (XCBConnection *c, /* The connection to the X server */ + BYTE coordinate_mode, /* Coordinate mode, usually set to CoordModeOrigin */ + XCBDRAWABLE drawable, /* The drawable on which we want to draw the line(s) */ + XCBGCONTEXT gc, /* The Graphic Context we use to draw the line(s) */ + CARD32 points_len, /* The number of points in the polygonal line */ + const XCBPOINT *points); /* An array of points */ +</pre> + <p> + This function will draw the line between the first and the + second points, then the line between the second and the third + points, and so on. + </p> + <p> + To draw a segment, or several segments, we use + </p> + <pre class="code"> +XCBVoidCookie XCBPolySegment (XCBConnection *c, /* The connection to the X server */ + XCBDRAWABLE drawable, /* The drawable on which we want to draw the segment(s) */ + XCBGCONTEXT gc, /* The Graphic Context we use to draw the segment(s) */ + CARD32 segments_len, /* The number of segments */ + const XCBSEGMENT *segments); /* An array of segments */ +</pre> + <p> + The <span class="code">XCBSEGMENT</span> type is just a + structure with four fields (the coordinates of the two points + that define the segment): + </p> + <pre class="code"> +typedef struct { + INT16 x1; + INT16 y1; + INT16 x2; + INT16 y2; +} XCBSEGMENT; +</pre> + <p> + To draw a rectangle, or several rectangles, we use + </p> + <pre class="code"> +XCBVoidCookie XCBPolyRectangle (XCBConnection *c, /* The connection to the X server */ + XCBDRAWABLE drawable, /* The drawable on which we want to draw the rectangle(s) */ + XCBGCONTEXT gc, /* The Graphic Context we use to draw the rectangle(s) */ + CARD32 rectangles_len, /* The number of rectangles */ + const XCBRECTANGLE *rectangles); /* An array of rectangles */ +</pre> + <p> + The <span class="code">XCBRECTANGLE</span> type is just a + structure with four fields (the coordinates of the top-left + corner of the rectangle, and its width and height): + </p> + <pre class="code"> +typedef struct { + INT16 x; + INT16 y; + CARD16 width; + CARD16 height; +} XCBRECTANGLE; +</pre> + <p> + <b>TODO</b>: there's no coordinate_mode. Is it normal ? + </p> + <p> + To draw an elliptical arc, or several elliptical arcs, we use + </p> + <pre class="code"> +XCBVoidCookie XCBPolyArc (XCBConnection *c, /* The connection to the X server */ + XCBDRAWABLE drawable, /* The drawable on which we want to draw the arc(s) */ + XCBGCONTEXT gc, /* The Graphic Context we use to draw the arc(s) */ + CARD32 arcs_len, /* The number of arcs */ + const XCBARC *arcs); /* An array of arcs */ +</pre> + <p> + The <span class="code">XCBARC</span> type is a structure with + six fields: + </p> + <pre class="code"> +typedef struct { + INT16 x; /* Top left x coordinate of the rectangle surrounding the ellipse */ + INT16 y; /* Top left y coordinate of the rectangle surrounding the ellipse */ + CARD16 width; /* Width of the rectangle surrounding the ellipse */ + CARD16 height; /* Height of the rectangle surrounding the ellipse */ + INT16 angle1; /* Angle at which the arc begins */ + INT16 angle2; /* Angle at which the arc ends */ +} XCBARC; +</pre> + <div class="emph"> + <p> + Note: the angles are expressed in units of 1/64 of a degree, + so to have an angle of 90 degrees, starting at 0, + <span class="code">angle1 = 0</span> and + <span class="code">angle2 = 90 << 6</span>. Positive angles + indicate counterclockwise motion, while negative angles + indicate clockwise motion. + </p> + </div> + <p> + <b>TODO</b>: there's no coordinate_mode. Is it normal ? + </p> + <p> + <b>TODO</b>: I think that (x,y) should be the center of the + ellipse, and (width, height) the radius. It's more logical. + </p> + <p> + The corresponding function which fill inside the geometrical + object are listed below, without further explanation, as they + are used as the above functions. + </p> + <p> + To Fill a polygon defined by the points given as arguments , + we use + </p> + <pre class="code"> +XCBVoidCookie XCBFillPoly (XCBConnection *c, + XCBDRAWABLE drawable, + XCBGCONTEXT gc, + CARD8 shape, + CARD8 coordinate_mode, + CARD32 points_len, + const XCBPOINT *points); +</pre> + <p> + The <span class="code">shape</span> parameter specifies a + shape that helps the server to improve performance. Available + values are + </p> + <ul> + <li><span class="code">Complex</span></li> + <li><span class="code">Convex</span></li> + <li><span class="code">Nonconvex</span></li> + </ul> + <p> + To fill one or several rectangles, we use + </p> + <pre class="code"> +XCBVoidCookie XCBPolyFillRectangle (XCBConnection *c, + XCBDRAWABLE drawable, + XCBGCONTEXT gc, + CARD32 rectangles_len, + const XCBRECTANGLE *rectangles); +</pre> + <p> + To fill one or several arcs, we use + </p> + <pre class="code"> +XCBVoidCookie XCBPolyFillArc (XCBConnection *c, + XCBDRAWABLE drawable, + XCBGCONTEXT gc, + CARD32 arcs_len, + const XCBARC *arcs); +</pre> + <p></p> + <p> + To illustrate these functions, here is an example that draws + four points, a polygonal line, two segments, two rectangles + and two arcs. Remark that we use events for the first time, as + an introduction to the next section. + </p> + <pre class="code"> +#include <stdlib.h> +#include <stdio.h> + +#include <X11/XCB/xcb.h> + +/* Get the depth of the screen. Needed in order to draw something */ +int +get_depth(XCBConnection *c, + XCBSCREEN *root) +{ + XCBDRAWABLE drawable; + XCBGetGeometryRep *geom; + int depth; + + drawable.window = root->root; + geom = XCBGetGeometryReply (c, XCBGetGeometry(c, drawable), 0); + + if(!geom) + { + perror ("GetGeometry(root) failed"); + exit (0); + } + + depth = geom->depth; + free (geom); + + return depth; +} + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + XCBSCREEN *screen; + XCBDRAWABLE win; + XCBGCONTEXT foreground; + XCBGenericEvent *e; + CARD32 mask = 0; + CARD32 values[2]; + + /* geometric objects */ + XCBPOINT points[] = { + {10, 10}, + {10, 20}, + {20, 10}, + {20, 20}}; + + XCBPOINT polyline[] = { + {50, 10}, + {55, 30}, + {80, 10}, + {90, 20}}; + + XCBSEGMENT segments[] = { + {100, 10, 140, 30}, + {110, 25, 130, 60}}; + + XCBRECTANGLE rectangles[] = { + { 10, 50, 40, 20}, + { 80, 50, 10, 40}}; + + XCBARC arcs[] = { + {10, 100, 60, 40, 0, 90 << 6}, + {90, 100, 55, 40, 0, 270 << 6}}; + + /* Open the connection to the X server */ + c = XCBConnect (NULL, NULL); + + /* Get the first screen */ + screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data; + + /* Create black (foregroung) graphic context */ + win.window = screen->root; + + foreground = XCBGCONTEXTNew (c); + mask = GCForeground | GCGraphicsExposures; + values[0] = screen->black_pixel; + values[1] = 0; + XCBCreateGC (c, foreground, win, mask, values); + + /* Ask for our window's Id */ + win.window = XCBWINDOWNew(c); + + /* Create the window */ + mask = XCBCWBackPixel | XCBCWEventMask; + values[0] = screen->white_pixel; + values[1] = ExposureMask; + XCBCreateWindow (c, /* Connection */ + 0, /* depth */ + win.window, /* window Id */ + screen->root, /* parent window */ + 0, 0, /* x, y */ + 150, 150, /* width, height */ + 10, /* border_width */ + InputOutput, /* class */ + screen->root_visual, /* visual */ + mask, values); /* masks */ + + /* Map the window on the screen */ + XCBMapWindow (c, win.window); + + + /* We flush the request */ + XCBSync (c, 0); + + while ((e = XCBWaitEvent (c))) + { + switch (e->response_type) + { + case XCBExpose: + { + /* We draw the points */ + XCBPolyPoint (c, CoordModeOrigin, win, foreground, 4, points); + + /* We draw the polygonal line */ + XCBPolyLine (c, CoordModeOrigin, win, foreground, 4, polyline); + + /* We draw the segements */ + XCBPolySegment (c, win, foreground, 2, segments); + + /* We draw the rectangles */ + XCBPolyRectangle (c, win, foreground, 2, rectangles); + + /* We draw the arcs */ + XCBPolyArc (c, win, foreground, 2, arcs); + + /* We flush the request */ + XCBSync (c, 0); + + break; + } + default: + { + /* Unknown event type, ignore it */ + break; + } + } + /* Free the Generic Event */ + free (e); + } + + return 1; +} +</pre> + </ol> + <li class="title"><a name="xevents">X Events</a></li> + <p> + In an X program, everything is driven by events. Event painting + on the screen is sometimes done as a response to an event (an + <span class="code">Expose</span> event). If part of a program's + window that was hidden, gets exposed (e.g. the window was raised + above other widows), the X server will send an "expose" event to + let the program know it should repaint that part of the + window. User input (key presses, mouse movement, etc) is also + received as a set of events. + </p> + <ol> + <li class="subtitle"><a name="register">Registering for event types using event masks</a></li> + <p> + During the creation of a window, you should give it what kind + of events it wishes to receive. Thus, you may register for + various mouse (also called pointer) events, keyboard events, + expose events, and so on. This is done for optimizing the + server-to-client connection (i.e. why send a program (that + might even be running at the other side of the globe) an event + it is not interested in ?) + </p> + <p> + In XCB, you use the "value_mask" and "value_list" data in the + <span class="code">XCBCreateWindow()</span> function to + register for events. Here is how we register for + <span class="code">Expose</span> event when creating a window: + </p> + <pre class="code"> + mask = XCBCWEventMask; + valwin[0] = ExposureMask; + win.window = XCBWINDOWNew (c); + XCBCreateWindow (c, depth, win.window, root->root, + 0, 0, 150, 150, 10, + InputOutput, root->root_visual, + mask, valwin); +</pre> + <p> + <span class="code">ExposureMask</span> is a constant defined + in the "X.h" header file. If we wanted to register to several + event types, we can logically "or" them, as follows: + </p> + <pre class="code"> + mask = XCBCWEventMask; + valwin[0] = ExposureMask | ButtonPressMask; + win.window = XCBWINDOWNew (c); + XCBCreateWindow (c, depth, win.window, root->root, + 0, 0, 150, 150, 10, + InputOutput, root->root_visual, + mask, valwin); +</pre> + <p> + This registers for <span class="code">Expose</span> events as + well as for mouse button presses insode the created + window. You should note that a mask may represent several + event sub-types. + </p> + <p> + The values that a mask could take are given + by the <span class="code">XCBCW</span> enumeration: + </p> + <pre class="code"> +typedef enum { + XCBCWBackPixmap = 1L<<0, + XCBCWBackPixel = 1L<<1, + XCBCWBorderPixmap = 1L<<2, + XCBCWBorderPixel = 1L<<3, + XCBCWBitGravity = 1L<<4, + XCBCWWinGravity = 1L<<5, + XCBCWBackingStore = 1L<<6, + XCBCWBackingPlanes = 1L<<7, + XCBCWBackingPixel = 1L<<8, + XCBCWOverrideRedirect = 1L<<9, + XCBCWSaveUnder = 1L<<10, + XCBCWEventMask = 1L<<11, + XCBCWDontPropagate = 1L<<12, + XCBCWColormap = 1L<<13, + XCBCWCursor = 1L<<14 +} XCBCW; +</pre> + <div class="emph"> + <p>Note: we must be careful when setting the values of the valwin + parameter, as they have to follow the order the + <span class="code">XCBCW</span> enumeration. Here is an + example: + </p> + </div> + <pre class="code"> + mask = XCBCWEventMask | XCBCWBackPixmap; + valwin[0] = None; /* for XCBCWBackPixmap (whose value is 1) */ + valwin[1] = ExposureMask | ButtonPressMask; /* for XCBCWEventMask, whose value (2048) */ + /* is superior to the one of XCBCWBackPixmap */ +</pre> + <p> + If the window has already been created, we can use the + <span class="code">XCBConfigureWindow()</span> function to set + the events that the window will receive. The subsection + <a href="#winconf">Configuring a window</a> shows its + prototype. As an example, here is a piece of code that + configures the window to receive the + <span class="code">Expose</span> and + <span class="code">ButtonPressMask</span> events: + </p> + <pre class="code"> +const static CARD32 values[] = { ExposureMask | ButtonPressMask }; + +/* The connection c and the window win are supposed to be defined */ + +XCBConfigureWindow (c, win, XCBCWEventMask, values); +</pre> + <div class="emph"> + <p> + Note: A common bug programmers do is adding code to handle new + event types in their program, while forgetting to add the + masks for these events in the creation of the window. Such a + programmer then should sit down for hours debugging his + program, wondering "Why doesn't my program notice that I + released the button?", only to find that they registered for + button press events but not for button release events. + </p> + </div> + <li class="subtitle"><a name="loop">Receiving events: writing the events loop</a></li> + <p> + After we have registered for the event types we are interested + in, we need to enter a loop of receiving events and handling + them. There are two ways to receive events: a blocking way and + a non blocking way: + </p> + <ul> + <li> + <span class="code">XCBWaitEvent (XCBConnection *c)</span> + is the blocking way. It waits (so blocks...) until an event is + queued in the X server. Then it retrieves it into a newly + allocated structure (it dequeues it from the queue) and returns + it. This structure has to be freed. The function returns + <span class="code">NULL</span> if an error occurs. + </li> + <br /> + <li> + <span class="code">XCBPollForEvent (XCBConnection *c, int + *error)</span> is the non blocking way. It looks at the event + queue and returns (and dequeues too) an existing event into + a newly allocated structure. This structure has to be + freed. It returns <span class="code">NULL</span> if there is + no event. If an error occurs, the parameter <span + class="code">error</span> will be filled with the error + status. + </li> + </ul> + <p> + There are various ways to write such a loop. We present two + ways to write such a loop, with the two functions above. The + first one uses <span class="code">XCBWaitEvent</span>, which + is similar to an event Xlib loop using only <span + class="code">XNextEvent</span>: + </p> + <pre class="code"> + XCBGenericEvent *e; + + while ((e = XCBWaitEvent (c))) + { + switch (e->response_type) + { + case XCBExpose: + { + /* Handle the Expose event type */ + XCBExposeEvent *ev = (XCBExposeEvent *)e; + + /* ... */ + + break; + } + case XCBButtonPress: + { + /* Handle the ButtonPress event type */ + XCBButtonPressEvent *ev = (XCBButtonPressEvent *)e; + + /* ... */ + + break; + } + default: + { + /* Unknown event type, ignore it */ + break; + } + } + /* Free the Generic Event */ + free (e); + } +</pre> + <p> + You will certainly want to use <span + class="code">XCBPollForEvent(XCBConnection *c, int + *error)</span> if, in Xlib, you use <span + class="code">XPending</span>: + </p> + <pre class="code"> + while (XPending (display)) + { + XEvent ev; + + XNextEvent(d, &ev); + + /* Manage your event */ + } +</pre> + <p> + Such a loop in XCB looks like: + </p> + <pre class="code"> + XCBGenericEvent *ev; + + while ((ev = XCBPollForEvent (conn, 0))) + { + /* Manage your event */ + } +</pre> + <p> + The events are managed in the same way as with <span + class="code">XCBWaitEvent</span>. + Obviously, we will need to give the user some way of + terminating the program. This is usually done by handling a + special "quit" event, as we will soon see. + </p> + <div class="comp"> + <div class="title"> + Comparison Xlib/XCB + </div> + <div class="xlib"> + <ul> + <li>XNextEvent ()</li> + </ul> + </div> + <div class="xcb"> + <ul> + <li>XCBWaitEvent ()</li> + </ul> + </div> + <div class="xlib"> + <ul> + <li>XPending ()</li> + <li>XNextEvent ()</li> + </ul> + </div> + <div class="xcb"> + <ul> + <li>XCBPollForEvent ()</li> + <br /> + </ul> + </div> + </div> + <p /> + <li class="subtitle"><a name="expose">Expose events</a></li> + <p> + The <span class="code">Expose</span> event is one of the most + basic (and most used) events an application may receive. It + will be sent to us in one of several cases: + <ul> + <li>A window that covered part of our window has moved + away, exposing part (or all) of our window.</li> + <li>Our window was raised above other windows.</li> + <li>Our window mapped for the first time.</li> + <li>Our window was de-iconified.</li> + </ul> + </p> + <p> + You should note the implicit assumption hidden here: the + contents of our window is lost when it is being obscured + (covered) by either windows. One may wonder why the X server + does not save this contents. The answer is: to save + memory. After all, the number of windows on a display at a + given time may be very large, and storing the contents of all + of them might require a lot of memory. Actually, there is a + way to tell the X server to store the contents of a window in + special cases, as we will see later. + </p> + <p> + When we get an <span class="code">Expose</span> event, we + should take the event's data from the members of the following + structure: + </p> + <pre class="code"> +typedef struct { + BYTE response_type; /* The type of the event, here it is XCBExpose */ + CARD8 pad0; + CARD16 sequence; + XCBWINDOW window; /* The Id of the window that receives the event (in case */ + /* our application registered for events on several windows */ + CARD16 x; /* The x coordinate of the top-left part of the window that needs to be redrawn */ + CARD16 y; /* The y coordinate of the top-left part of the window that needs to be redrawn */ + CARD16 width; /* The width of the part of the window that needs to be redrawn */ + CARD16 height; /* The height of the part of the window that needs to be redrawn */ + CARD16 count; +} XCBExposeEvent; +</pre> + <li class="subtitle"><a name="userinput">Getting user input</a></li> + <p> + User input traditionally comes from two sources: the mouse + and the keyboard. Various event types exist to notify us of + user input (a key being presses on the keyboard, a key being + released on the keyboard, the mouse moving over our window, + the mouse entering (or leaving) our window, and so on. + </p> + <ol> + <li class="subsubtitle"><a name="mousepressrelease">Mouse button press and release events</a></li> + <p> + The first event type we will deal with is a mouse + button-press (or button-release) event in our window. In + order to register to such an event type, we should add one + (or more) of the following masks when we create our window: + </p> + <ul> + <li><span class="code">ButtonPressMask</span>: notify us + of any button that was pressed in one of our windows.</li> + <li><span class="code">ButtonReleaseMask</span>: notify us + of any button that was released in one of our windows.</li> + </ul> + <p> + The structure to be checked for in our events loop is the + same for these two events, and is the following: + </p> + <pre class="code"> +typedef struct { + BYTE response_type; /* The type of the event, here it is XCBButtonPressEvent or XCBButtonReleaseEvent */ + XCBBUTTON detail; + CARD16 sequence; + XCBTIMESTAMP time; /* Time, in milliseconds the event took place in */ + XCBWINDOW root; + XCBWINDOW event; + XCBWINDOW child; + INT16 root_x; + INT16 root_y; + INT16 event_x; /* The x coordinate where the mouse has been pressed in the window */ + INT16 event_y; /* The y coordinate where the mouse has been pressed in the window */ + CARD16 state; /* A mask of the buttons (or keys) during the event */ + BOOL same_screen; +} XCBButtonPressEvent; + +typedef XCBButtonPressEvent XCBButtonReleaseEvent; +</pre> + <p> + The <span class="code">time</span> field may be used to calculate "double-click" + situations by an application (e.g. if the mouse button was + clicked two times in a duration shorter than a given amount + of time, assume this was a double click). + </p> + <p> + The <span class="code">state</span> field is a mask of the buttons held down during + the event. It is a bitwise OR of any of the following: + </p> + <ul> + <li><span class="code">Button1Mask</span></li> + <li><span class="code">Button2Mask</span></li> + <li><span class="code">Button3Mask</span></li> + <li><span class="code">Button4Mask</span></li> + <li><span class="code">Button5Mask</span></li> + <li><span class="code">ShiftMask</span></li> + <li><span class="code">LockMask</span></li> + <li><span class="code">ControlMask</span></li> + <li><span class="code">Mod1Mask</span></li> + <li><span class="code">Mod2Mask</span></li> + <li><span class="code">Mod3Mask</span></li> + <li><span class="code">Mod4Mask</span></li> + <li><span class="code">Mod5Mask</span></li> + </ul> + <p> + Their names are self explanatory, where the first 5 refer to + the mouse buttons that are being pressed, while the rest + refer to various "special keys" that are being pressed (Mod1 + is usually the 'Alt' key or the 'Meta' key). + </p> + <p> + <b>TODO:</b> Problem: it seems that the state does not + change when clicking with various buttons. + </p> + <li class="subsubtitle"><a name="mousemvnt">Mouse movement events</a></li> + <p> + Similar to mouse button press and release events, we also + can be notified of various mouse movement events. These can + be split into two families. One is of mouse pointer + movement while no buttons are pressed, and the second is a + mouse pointer motion while one (or more) of the buttons are + pressed (this is sometimes called "a mouse drag operation", + or just "dragging"). The following event masks may be added + during the creation of our window: + </p> + <ul> + <li><span class="code">PointerMotionMask</span>: events of + the pointer moving in one of the windows controlled by our + application, while no mouse button is held pressed.</li> + <li><span class="code">ButtonMotionMask</span>: Events of + the pointer moving while one or more of the mouse buttons + is held pressed.</li> + <li><span class="code">Button1MotionMask</span>: same as + <span class="code">ButtonMotionMask</span>, but only when + the 1st mouse button is held pressed.</li> + <li><span class="code">Button2MotionMask</span>, + <span class="code">Button3MotionMask</span>, + <span class="code">Button4MotionMask</span>, + <span class="code">Button5MotionMask</span>: same as + <span class="code">Button1MotionMask</span>, but + respectively for 2nd, 3rd, 4th and 5th mouse button.</li> + </ul> + <p> + The structure to be checked for in our events loop is the + same for these events, and is the following: + </p> + <pre class="code"> +typedef struct { + BYTE response_type; /* The type of the event */ + BYTE detail; + CARD16 sequence; + XCBTIMESTAMP time; /* Time, in milliseconds the event took place in */ + XCBWINDOW root; + XCBWINDOW event; + XCBWINDOW child; + INT16 root_x; + INT16 root_y; + INT16 event_x; /* The x coordinate of the mouse when the event was generated */ + INT16 event_y; /* The y coordinate of the mouse when the event was generated */ + CARD16 state; /* A mask of the buttons (or keys) during the event */ + BOOL same_screen; +} XCBMotionNotifyEvent; +</pre> + <li class="subsubtitle"><a name="mouseenter">Mouse pointer enter and leave events</a></li> + <p> + Another type of event that applications might be interested + at, is a mouse pointer entering a window the program + controls, or leaving such a window. Some programs use these + events to show the user tht the applications is now in + focus. In order to register for such an event type, we + should add one (or more) of the following masks when we + create our window: + </p> + <ul> + <li><span class="code">EnterWindowMask</span>: notify us + when the mouse pointer enters any of our controlled + windows.</li> + <li><span class="code">LeaveWindowMask</span>: notify us + when the mouse pointer leaves any of our controlled + windows.</li> + </ul> + <p> + The structure to be checked for in our events loop is the + same for these two events, and is the following: + </p> + <pre class="code"> +typedef struct { + BYTE response_type; /* The type of the event */ + BYTE detail; + CARD16 sequence; + XCBTIMESTAMP time; /* Time, in milliseconds the event took place in */ + XCBWINDOW root; + XCBWINDOW event; + XCBWINDOW child; + INT16 root_x; + INT16 root_y; + INT16 event_x; /* The x coordinate of the mouse when the event was generated */ + INT16 event_y; /* The y coordinate of the mouse when the event was generated */ + CARD16 state; /* A mask of the buttons (or keys) during the event */ + BYTE mode; /* The number of mouse button that was clicked */ + BYTE same_screen_focus; +} XCBEnterNotifyEvent; + +typedef XCBEnterNotifyEvent XCBLeaveNotifyEvent; +</pre> + <li class="subsubtitle"><a name="focus">The keyboard focus</a></li> + <p> + There may be many windows on a screen, but only a single + keyboard attached to them. How does the X server then know + which window should be sent a given keyboard input ? This is + done using the keyboard focus. Only a single window on the + screen may have the keyboard focus at a given time. There + is a XCB function that allow a program to set the keyboard + focus to a given window. The user can usually set the + keyboard ficus using the window manager (often by clicking + on the title bar of the desired window). Once our window + has the keyboard focus, every key press or key release will + cause an event to be sent to our program (if it regsitered + for these event types...). + </p> + <li class="subsubtitle"><a name="keypress">Keyboard press and release events</a></li> + <p> + If a window controlled by our program currently holds the + keyboard focus, it can receive key press and key release + events. So, we should add one (or more) of the following + masks when we create our window: + </p> + <ul> + <li><span class="code">KeyPressMask</span>: notify us when + a key was pressed while any of our controlled windows had + the keyboard focus.</li> + <li><span class="code">KeyReleaseMask</span>: notify us + when a key was released while any of our controlled + windows had the keyboard focus.</li> + </ul> + <p> + The structure to be checked for in our events loop is the + same for these two events, and is the following: + </p> + <pre class="code"> +typedef struct { + BYTE response_type; /* The type of the event */ + XCBKEYCODE detail; + CARD16 sequence; + XCBTIMESTAMP time; /* Time, in milliseconds the event took place in */ + XCBWINDOW root; + XCBWINDOW event; + XCBWINDOW child; + INT16 root_x; + INT16 root_y; + INT16 event_x; + INT16 event_y; + CARD16 state; + BOOL same_screen; +} XCBKeyPressEvent; + +typedef XCBKeyPressEvent XCBKeyReleaseEvent; +</pre> + <p> + The <span class="code">detail</span> field refer to the + physical key on the keyboard. + </p> + <p> + <b>TODO:</b> Talk about getting the ASCII code from the key code. + </p> + </ol> + <li class="subtitle"><a name="eventex">X events: a complete example</a></li> + <p> + As an example for handling events, we show a program that + creates a window, enter an events loop and check for all the + events described above, and write on the terminal the relevant + characteristics of the event. With this code, it should be + easy to add drawing operations, like those which have been + described above. + </p> + <pre class="code"> +#include <malloc.h> +#include <stdio.h> + +#include <X11/XCB/xcb.h> + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + XCBSCREEN *screen; + XCBDRAWABLE win; + XCBGenericEvent *e; + CARD32 mask = 0; + CARD32 values[2]; + + /* Open the connection to the X server */ + c = XCBConnect (NULL, NULL); + + /* Get the first screen */ + screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data; + + /* Ask for our window's Id */ + win.window = XCBWINDOWNew(c); + + /* Create the window */ + mask = XCBCWBackPixel | XCBCWEventMask; + values[0] = screen->white_pixel; + values[1] = ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | EnterWindowMask | LeaveWindowMask | + KeyPressMask | KeyReleaseMask; + XCBCreateWindow (c, /* Connection */ + 0, /* depth */ + win.window, /* window Id */ + screen->root, /* parent window */ + 0, 0, /* x, y */ + 150, 150, /* width, height */ + 10, /* border_width */ + InputOutput, /* class */ + screen->root_visual, /* visual */ + mask, values); /* masks */ + + /* Map the window on the screen */ + XCBMapWindow (c, win.window); + + XCBSync (c, 0); + while ((e = XCBWaitEvent (c))) + { + switch (e->response_type) + { + case XCBExpose: + { + XCBExposeEvent *ev = (XCBExposeEvent *)e; + + printf ("Window %ld exposed. Region to be redrawn at location (%d,%d), with dimension (%d,%d)\n", + ev->window.xid, ev->x, ev->y, ev->width, ev->height); + break; + } + case XCBButtonPress: + { + XCBButtonPressEvent *ev = (XCBButtonPressEvent *)e; + int button_num = 0; + + if ((ev->state | Button1Mask) == Button1Mask) + button_num = 1; + if ((ev->state | Button2Mask) == Button2Mask) + button_num = 2; + if ((ev->state | Button3Mask) == Button3Mask) + button_num = 3; + if ((ev->state | Button4Mask) == Button4Mask) + button_num = 4; + if ((ev->state | Button5Mask) == Button5Mask) + button_num = 5; + + switch (ev->detail.id) + { + case 4: + { + printf ("Wheel Button up in window %ld, at coordinates (%d,%d)\n", + ev->event.xid, ev->event_x, ev->event_y); + break; + } + case 5: + { + printf ("Wheel Button down in window %ld, at coordinates (%d,%d)\n", + ev->event.xid, ev->event_x, ev->event_y); + break; + } + default: + printf ("Button %d pressed in window %ld, at coordinates (%d,%d)\n", + ev->detail.id, ev->event.xid, ev->event_x, ev->event_y); + } + break; + } + case XCBButtonRelease: + { + XCBButtonReleaseEvent *ev = (XCBButtonReleaseEvent *)e; + int button_num = 0; + + if ((ev->state | Button1Mask) == Button1Mask) + button_num = 1; + if ((ev->state | Button2Mask) == Button2Mask) + button_num = 2; + if ((ev->state | Button3Mask) == Button3Mask) + button_num = 3; + if ((ev->state | Button4Mask) == Button4Mask) + button_num = 4; + if ((ev->state | Button5Mask) == Button5Mask) + button_num = 5; + + printf ("Button %d released in window %ld, at coordinates (%d,%d)\n", + ev->detail.id, ev->event.xid, ev->event_x, ev->event_y); + break; + } + case XCBMotionNotify: + { + XCBMotionNotifyEvent *ev = (XCBMotionNotifyEvent *)e; + + printf ("Mouse moved in window %ld, at coordinates (%d,%d)\n", + ev->event.xid, ev->event_x, ev->event_y); + break; + } + case XCBEnterNotify: + { + XCBEnterNotifyEvent *ev = (XCBEnterNotifyEvent *)e; + + printf ("Mouse entered window %ld, at coordinates (%d,%d)\n", + ev->event.xid, ev->event_x, ev->event_y); + break; + } + case XCBLeaveNotify: + { + XCBLeaveNotifyEvent *ev = (XCBLeaveNotifyEvent *)e; + + printf ("Mouse leaved window %ld, at coordinates (%d,%d)\n", + ev->event.xid, ev->event_x, ev->event_y); + break; + } + case XCBKeyPress: + { + XCBKeyPressEvent *ev = (XCBKeyPressEvent *)e; + + printf ("Key pressed in window %ld\n", + ev->event.xid); + break; + } + case XCBKeyRelease: + { + XCBKeyReleaseEvent *ev = (XCBKeyReleaseEvent *)e; + + printf ("Key releaseed in window %ld\n", + ev->event.xid); + break; + } + default: + { + /* Unknown event type, ignore it */ + break; + } + } + /* Free the Generic Event */ + free (e); + } + + return 1; +} +</pre> + </ol> + <li class="title"><a name="font">Handling text and fonts</a></li> + <p> + Besides drawing graphics on a window, we often want to draw + text. Text strings have two major properties: the characters to + be drawn and the font with which they are drawn. In order to + draw text, we need to first request the X server to load a + font. We the assign a font to a Graphic Context, and finally, we + draw the text in a window, using the Graphic Context. + </p> + <ol> + <li class="subtitle"><a name="fontstruct">The Font structure</a></li> + <p> + In order to support flexible fonts, a font structure is + defined. You know what ? Its an Id: + </p> + <pre class="code"> +typedef struct { + CARD32 xid; +} XCBFONT; +</pre> + <p> + It is used to contain information about a font, and is passed + to several functions that handle fonts selection and text drawing. + </p> + </ol> + <li class="title"><a name="wm">Interacting with the window manager</a></li> + <p> + After we have seen how to create windows and draw on them, we + take one step back, and look at how our windows are interacting + with their environment (the full screen and the other + windows). First of all, our application needs to interact with + the window manager. The window manager is responsible to + decorating drawn windows (i.e. adding a frame, an iconify + button, a system menu, a title bar, etc), as well as handling + icons shown when windows are being iconified. It also handles + ordering of windows on the screen, and other administrative + tasks. We need to give it various hints as to how we want it to + treat our application's windows. + </p> + <ol> + <li class="subtitle"><a name="wmprop">Window properties</a></li> + <p> + Many of the parameters communicated to the window manager are + passed using data called "properties". These properties are + attached by the X server to different windows, and are stores + in a format that makes it possible to read them from different + machines that may use different architectures (remember that + an X client program may run on a remote machine). + </p> + <p> + The property and its type (a string, an integer, etc) are + Id. Their type are <span class="code">XCBATOM</span>: + </p> + <pre class="code"> +typedef struct { + CARD32 xid; +} XCBATOM; +</pre> + <p> + To change the property of a window, we use the following + function: + </p> + <pre class="code"> +XCBVoidCookie XCBChangeProperty (XCBConnection *c, /* Connection to the X server */ + CARD8 mode, /* Property mode */ + XCBWINDOW window, /* Window */ + XCBATOM property, /* Property to change */ + XCBATOM type, /* Type of the property */ + CARD8 format, /* Format of the property (8, 16, 32) */ + CARD32 data_len, /* Length of the data parameter */ + const void *data); /* Data */ +</pre> + <p> + The <span class="code">mode</span> parameter coud be one of + the following value (defined in the X.h header file): + </p> + <ul> + <li>PropModeReplace</li> + <li>PropModePrepend</li> + <li>PropModeAppend</li> + </ul> + <p></p> + <li class="subtitle"><a name="wmname">Setting the window name and icon name</a></li> + <p> + The firt thing we want to do would be to set the name for our + window. This is done using the + <span class="code">XCBChangeProperty()</span> function. This + name may be used by the window manager as the title of the + window (in the title bar), in a task list, etc. The property + atom to use to set the name of a window is + <span class="code">WM_NAME</span> (and + <span class="code">WM_ICON_NAME</span> for the iconified + window) and its type is <span class="code">STRING</span>. Here + is an example of utilization: + </p> + <pre class="code"> +#include <string.h> + +#include <X11/XCB/xcb.h> +#include <X11/XCB/xcb_atom.h> + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + XCBSCREEN *screen; + XCBDRAWABLE win; + char *title = "Hello World !"; + char *title_icon = "Hello World ! (iconified)"; + + + + /* Open the connection to the X server */ + c = XCBConnect (NULL, NULL); + + /* Get the first screen */ + screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data; + + /* Ask for our window's Id */ + win.window = XCBWINDOWNew(c); + + /* Create the window */ + XCBCreateWindow (c, /* Connection */ + 0, /* depth */ + win.window, /* window Id */ + screen->root, /* parent window */ + 0, 0, /* x, y */ + 250, 150, /* width, height */ + 10, /* border_width */ + InputOutput, /* class */ + screen->root_visual, /* visual */ + 0, NULL); /* masks, not used */ + + /* Set the title of the window */ + XCBChangeProperty(c, PropModeReplace, win.window, + WM_NAME, STRING, 8, + strlen(title), title); + + /* Set the title of the window icon */ + XCBChangeProperty(c, PropModeReplace, win.window, + WM_ICON_NAME, STRING, 8, + strlen(title_icon), title_icon); + + /* Map the window on the screen */ + XCBMapWindow (c, win.window); + + XCBSync (c, 0); + + while (1) {} + + return 1; +} +</pre> + <div class="emph"> + <p>Note: the use of the atoms needs our program to be compiled + and linked against xcb_atom, so that we have to use + </p> + </div> + <pre class="text"> +gcc prog.c -o prog `pkg-config --cflags --libs xcb_atom` +</pre> + <div class="emph"> + <p> + for the program to compile fine. + </p> + </div> + </ol> + <li class="title"><a name="winop">Simple window operations</a></li> + <p> + One more thing we can do to our window is manipulate them on the + screen (resize them, move them, raise or lower them, iconify + them, and so on). Some window operations functions are supplied + by XCB for this purpose. + </p> + <ol> + <li class="subtitle"><a name="winmap">Mapping and un-mapping a window</a></li> + <p> + The first pair of operations we can apply on a window is + mapping it, or un-mapping it. Mapping a window causes the + window to appear on the screen, as we have seen in our simple + window program example. Un-mapping it causes it to be removed + from the screen (although the window as a logical entity still + exists). This gives the effect of making a window hidden + (unmapped) and shown again (mapped). For example, if we have a + dialog box window in our program, instead of creating it every + time the user asks to open it, we can create the window once, + in an un-mapped mode, and when the user asks to open it, we + simply map the window on the screen. When the user clicked the + 'OK' or 'Cancel' button, we simply un-map the window. This is + much faster than creating and destroying the window, however, + the cost is wasted resources, both on the client side, and on + the X server side. + </p> + <p> + To map a window, you use the following function: + </p> + <pre class="code"> +XCBVoidCookie XCBMapWindow(XCBConnection *c, XCBWINDOW window); +</pre> + <p> + To have a simple example, see the <a href="#helloworld">example</a> + above. The mapping operation will cause an + <span class="code">Expose</span> event to be sent to our + application, unless the window is completely covered by other + windows. + </p> + <p> + Un-mapping a window is also simple. You use the function + </p> + <pre class="code"> +XCBVoidCookie XCBUnmapWindow(XCBConnection *c, XCBWINDOW window); +</pre> + <p> + The utilization of this function is the same as + <span class="code">XCBMapWindow()</span>. + </p> + <li class="subtitle"><a name="winconf">Configuring a window</a></li> + <p> + As we have seen when we have created our first window, in the + X Events subsection, we can set some attributes to the window + (that is, the position, the size, the events the window will + receive, etc). If we want to modify them, but the window is + already created, we can change them by using hte following + function: + </p> + <pre class="code"> +XCBVoidCookie XCBConfigureWindow (XCBConnection *c, /* The connection to the X server*/ + XCBWINDOW window, /* The window to configure */ + CARD16 value_mask, /* The mask */ + const CARD32 *value_list); /* The values to set */ +</pre> + <p> + We set the <span class="code">value_mask</span> to one or + several mask values that are in the X.h header: + <ul> + <li><span class="code">CWX</span>: new x coordinate of the window's top left corner</li> + <li><span class="code">CWY</span>: new y coordinate of the window's top left corner</li> + <li><span class="code">CWWidth</span>: new width of the window</li> + <li><span class="code">CWHeight</span>: new height of the window</li> + <li><span class="code">CWBorderWidth</span>: new width of the border of the window</li> + <li><span class="code">CWSibling</span></li> + <li><span class="code">CWStackMode</span>: the new stacking order</li> + </ul> + </p> + <p> + We then give to <span class="code">value_mask</span> the new + value. We now describe how to use + <span class="code">XCBConfigureWindow</span> in some useful + situations. + </p> + <li class="subtitle"><a name="winmove">Moving a window around the screen</a></li> + <p> + An operation we might want to do with windows is to move them + to a different location. This can be done like this: + </p> + <pre class="code"> +const static CARD32 values[] = { 10, 20 }; + +/* The connection c and the window win are supposed to be defined */ + +/* Move the window to coordinates x = 10 and y = 20 */ +XCBConfigureWindow (c, win, CWX | CWY, values); +</pre> + <p> + Note that when the window is moved, it might get partially + exposed or partially hidden by other windows, and thus we + might get <span class="code">Expose</span> events due to this + operation. + </p> + <li class="subtitle"><a name="winsize">Resizing a window</a></li> + <p> + Yet another operation we can do is to change the size of a + window. This is done using the following code: + </p> + <pre class="code"> +const static CARD32 values[] = { 200, 300 }; + +/* The connection c and the window win are supposed to be defined */ + +/* Resize the window to width = 10 and height = 20 */ +XCBConfigureWindow (c, win, CWWidth | CWHeight, values); +</pre> + <p> + We can also combine the move and resize operations using one + single call to <span class="code">XCBConfigureWindow</span>: + </p> + <pre class="code"> +const static CARD32 values[] = { 10, 20, 200, 300 }; + +/* The connection c and the window win are supposed to be defined */ + +/* Move the window to coordinates x = 10 and y = 20 */ +/* and resize the window to width = 10 and height = 20 */ +XCBConfigureWindow (c, win, CWX | CWY | CWWidth | CWHeight, values); +</pre> + <li class="subtitle"><a name="winstack">Changing windows stacking order: raise and lower</a></li> + <p> + Until now, we changed properties of a single window. We'll see + that there are properties that relate to the window and other + windows. One of hem is the stacking order. That is, the order + in which the windows are layered on top of each other. The + front-most window is said to be on the top of the stack, while + the back-most window is at the bottom of the stack. Here is + how to manipulate our windows stack order: + </p> + <pre class="code"> +const static CARD32 values[] = { Above }; + +/* The connection c and the window win are supposed to be defined */ + +/* Move the window on the top of the stack */ +XCBConfigureWindow (c, win, CWStackMode, values); +</pre> + <pre class="code"> +const static CARD32 values[] = { Below }; + +/* The connection c and the window win are supposed to be defined */ + +/* Move the window on the bottom of the stack */ +XCBConfigureWindow (c, win, CWStackMode, values); +</pre> + <li class="subtitle"><a name="wingetinfo">Getting information about a window</a></li> + <p> + Just like we can set various attributes of our windows, we can + also ask the X server supply the current values of these + attributes. For example, we can chewk where a window is + located on the screen, what is its current size, wheter it is + mapped or not, etc. The structure that contains some of this + information is + </p> + <pre class="code"> +typedef struct { + BYTE response_type; + CARD8 depth; /* depth of the window */ + CARD16 sequence; + CARD32 length; + XCBWINDOW root; /* Id of the root window *> + INT16 x; /* X coordinate of the window's location */ + INT16 y; /* Y coordinate of the window's location */ + CARD16 width; /* Width of the window */ + CARD16 height; /* Height of the window */ + CARD16 border_width; /* Width of the window's border */ +} XCBGetGeometryRep; +</pre> + <p> + XCB fill this structure with two functions: + </p> + <pre class="code"> +XCBGetGeometryCookie XCBGetGeometry (XCBConnection *c, + XCBDRAWABLE drawable); +XCBGetGeometryRep *XCBGetGeometryReply (XCBConnection *c, + XCBGetGeometryCookie cookie, + XCBGenericError **e); +</pre> + <p> + You use them as follows: + </p> + <pre class="code"> + XCBConnection *c; + XCBDRAWABLE win; + XCBGetGeometryRep *geom; + + /* You initialize c and win */ + + geom = XCBGetGeometryReply (c, XCBGetGeometry (c, win), 0); + + /* Do something with the fields of geom */ + + free (geom); +</pre> + <p> + Remark that you have to free the structure, as + <span class="code">XCBGetGeometryReply</span> allocates a + newly one. + </p> + <p> + One problem is that the returned location of the window is + relative to its parent window. This makes these coordinates + rather useless for any window manipulation functions, like + moving it on the screen. In order to overcome this problem, we + need to take a two-step operation. First, we find out the Id + of the parent window of our window. We then translate the + above relative coordinates to the screen coordinates. + </p> + <p> + To get the Id of the parent window, we need this structure: + </p> + <pre class="code"> +typedef struct { + BYTE response_type; + CARD8 pad0; + CARD16 sequence; + CARD32 length; + XCBWINDOW root; + XCBWINDOW parent; /* Id of the parent window */ + CARD16 children_len; + CARD8 pad1[14]; +} XCBQueryTreeRep; +</pre> + <p> + To fill this structure, we use these two functions: + </p> + <pre class="code"> +XCBQueryTreeCookie XCBQueryTree (XCBConnection *c, + XCBWINDOW window); +XCBQueryTreeRep *XCBQueryTreeReply (XCBConnection *c, + XCBQueryTreeCookie cookie, + XCBGenericError **e); +</pre> + <p> + The translated coordinates will be found in this structure: + </p> + <pre class="code"> +typedef struct { + BYTE response_type; + BOOL same_screen; + CARD16 sequence; + CARD32 length; + XCBWINDOW child; + CARD16 dst_x; /* Translated x coordinate */ + CARD16 dst_y; /* Translated y coordinate */ +} XCBTranslateCoordinatesRep; +</pre> + <p> + As usual, we need two functions to fill this structure: + </p> + <pre class="code"> +XCBTranslateCoordinatesCookie XCBTranslateCoordinates (XCBConnection *c, + XCBWINDOW src_window, + XCBWINDOW dst_window, + INT16 src_x, + INT16 src_y); +XCBTranslateCoordinatesRep *XCBTranslateCoordinatesReply (XCBConnection *c, + XCBTranslateCoordinatesCookie cookie, + XCBGenericError **e); +</pre> + <p> + We use them as follows: + </p> + <pre class="code"> + XCBConnection *c; + XCBDRAWABLE win; + XCBGetGeometryRep *geom; + XCBQueryTreeRep *tree; + XCBTranslateCoordinatesRep *trans; + + /* You initialize c and win */ + + geom = XCBGetGeometryReply (c, XCBGetGeometry (c, win), 0); + if (!geom) + return 0; + + tree = XCBQueryTreeReply (c, XCBQueryTree (c, win), 0); + if (!tree) + return 0; + + trans = XCBTranslateCoordinatesReply (c, + XCBTranslateCoordinates (c, + win, + tree->parent, + geom->x, geom->y), + 0); + if (!trans) + return 0; + + /* the translated coordinates are in trans->dst_x and trans->dst_y */ + + free (trans); + free (tree); + free (geom); +</pre> + <p> + Of course, as for <span class="code">geom</span>, + <span class="code">tree</span> and + <span class="code">trans</span> have to be freed. + </p> + <p> + The work is a bit hard, but XCB is a very low-level library. + </p> + <p> + <b>TODO:</b> the utilization of these functions should be a + prog, which displays the coordinates of the window. + </p> + <p> + There is another structure that gives informations about our window: + </p> + <pre class="code"> +typedef struct { + BYTE response_type; + CARD8 backing_store; + CARD16 sequence; + CARD32 length; + XCBVISUALID visual; /* Visual of the window */ + CARD16 _class; + CARD8 bit_gravity; + CARD8 win_gravity; + CARD32 backing_planes; + CARD32 backing_pixel; + BOOL save_under; + BOOL map_is_installed; + CARD8 map_state; /* Map state of the window */ + BOOL override_redirect; + XCBCOLORMAP colormap; /* Colormap of the window */ + CARD32 all_event_masks; + CARD32 your_event_mask; + CARD16 do_not_propagate_mask; +} XCBGetWindowAttributesRep; +</pre> + <p> + XCB supplies these two functions to fill it: + </p> + <pre class="code"> +XCBGetWindowAttributesCookie XCBGetWindowAttributes (XCBConnection *c, + XCBWINDOW window); +XCBGetWindowAttributesRep *XCBGetWindowAttributesReply (XCBConnection *c, + XCBGetWindowAttributesCookie cookie, + XCBGenericError **e); +</pre> + <p> + You use them as follows: + </p> + <pre class="code"> + XCBConnection *c; + XCBDRAWABLE win; + XCBGetWindowAttributesRep *attr; + + /* You initialize c and win */ + + attr = XCBGetWindowAttributesReply (c, XCBGetWindowAttributes (c, win), 0); + + if (!attr) + return 0; + + /* Do something with the fields of attr */ + + free (attr); +</pre> + <p> + As for <span class="code">geom</span>, + <span class="code">attr</span> has to be freed. + </p> + </ol> + <li class="title"><a name="usecolor">Using colors to paint the rainbow</a></li> + <p> + Up until now, all our painting operation were done using black + and white. We will (finally) see now how to draw using colors. + </p> + <ol> + <li class="subtitle"><a name="colormap">Color maps</a></li> + <p> + In the beginning, there were not enough colors. Screen + controllers could only support a limited number of colors + simultaneously (initially 2, then 4, 16 and 256). Because of + this, an application could not just ask to draw in a "light + purple-red" color, and expect that color to be available. Each + application allocated the colors it needed, and when all the + color entries (4, 16, 256 colors) were in use, the next color + allocation would fail. + </p> + <p> + Thus, the notion of "a color map" was introduced. A color map + is a table whose size is the same as the number of + simultaneous colors a given screen controller. Each entry + contained the RGB (Red, Green and Blue) values of a different + color (all colors can be drawn using some combination of red, + green and blue). When an application wants to draw on the + screen, it does not specify which color to use. Rather, it + specifies which color entry of some color map to be used + during this drawing. Change the value in this color map entry + and the drawing will use a different color. + </p> + <p> + In order to be able to draw using colors that got something to + do with what the programmer intended, color map allocation + functions are supplied. You could ask to allocate entry for a + color with a set of RGB values. If one already existed, you + would get its index in the table. If none existed, and the + table was not full, a new cell would be allocated to contain + the given RGB values, and its index returned. If the table was + full, the procedure would fail. You could then ask to get a + color map entry with a color that is closest to the one you + were asking for. This would mean that the actual drawing on + the screen would be done using colors similar to what you + wanted, but not the same. + </p> + <p> + On today's more modern screens where one runs an X server with + support for 16 million colors, this limitation looks a little + silly, but remember that there are still older computers with + older graphics cards out there. Using color map, support for + these screen becomes transparent to you. On a display + supporting 16 million colors, any color entry allocation + request would succeed. On a display supporting a limited + number of colors, some color allocation requests would return + similar colors. It won't look as good, but your application + would still work. + </p> + <li class="subtitle"><a name="colormapalloc">Allocating and freeing Color Maps</a></li> + <p> + When you draw using XCB, you can choose to use the standard + color map of the screen your window is displayed on, or you + can allocate a new color map and apply it to a window. In the + latter case, each time the mouse moves onto your window, the + screen color map will be replaced by your window's color map, + and you'll see all the other windows on screen change their + colors into something quite bizzare. In fact, this is the + effect you get with X applications that use the "-install" + command line option. + </p> + <p> + In XCB, a color map is (as often in X) an Id: + </p> + <pre class="code"> +typedef struct { + CARD32 xid; +} XCBCOLORMAP; +</pre> + <p> + In order to access the screen's default color map, you just + have to retrieve the <span class="code">default_colormap</span> + field of the <span class="code">XCBSCREEN</span> structure + (see Section + <a href="#screen">Checking basic information about a connection</a>): + </p> + <pre class="code"> +#include <stdio.h> + +#include <X11/XCB/xcb.h> + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + XCBSCREEN *screen; + XCBCOLORMAP colormap; + + /* Open the connection to the X server and get the first screen */ + c = XCBConnect (NULL, NULL); + screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data; + + colormap = screen->default_colormap; + + return 1; +} +</pre> + <p> + This will return the color map used by default on the first + screen (again, remember that an X server may support several + different screens, each of which might have its own resources). + </p> + <p> + The other option, that of allocating a new colormap, works as + follows. We first ask the X server to give an Id to our color + map, with this function: + </p> + <pre class="code"> +XCBCOLORMAP XCBCOLORMAPNew (XCBConnection *c); +</pre> + <p> + Then, we create the color map with + </p> + <pre class="code"> +XCBVoidCookie XCBCreateColormap (XCBConnection *c, /* Pointer to the XCBConnection structure */ + BYTE alloc, /* Colormap entries to be allocated (AllocNone or AllocAll) */ + XCBCOLORMAP mid, /* Id of the color map */ + XCBWINDOW window, /* Window on whose screen the colormap will be created */ + XCBVISUALID visual); /* Id of the visual supported by the screen */ +</pre> + <p> + Here is an example of creation of a new color map: + </p> + <pre class="code"> +#include <X11/XCB/xcb.h> + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + XCBSCREEN *screen; + XCBWINDOW win; + XCBCOLORMAP cmap + + /* Open the connection to the X server and get the first screen */ + c = XCBConnect (NULL, NULL); + screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data; + + /* We create the window win here*/ + + cmap = XCBCOLORMAPNew (c); + XCBCreateColormap (c, AllocNone, cmap, win, screen->root_visual); + + return 1; +} +</pre> + <p> + Note that the window parameter is only used to allow the X + server to create the color map for the given screen. We can + then use this color map for any window drawn on the same screen. + </p> + <p> + To free a color map, it suffices to use this function: + </p> + <pre class="code"> +XCBVoidCookie XCBFreeColormap (XCBConnection *c, /* The connection */ + XCBCOLORMAP cmap); /* The color map */ +</pre> + <div class="comp"> + <div class="title"> + Comparison Xlib/XCB + </div> + <div class="xlib"> + <ul> + <li>XCreateColormap ()</li> + </ul> + </div> + <div class="xcb"> + <ul> + <li>XCBCOLORMAPNew ()</li> + <li>XCBCreateColormap ()</li> + </ul> + </div> + <div class="xlib"> + <ul> + <li>XFreeColormap ()</li> + </ul> + </div> + <div class="xcb"> + <ul> + <li>XCBFreeColormap ()</li> + </ul> + </div> + </div> + <p></p> + <li class="subtitle"><a name="alloccolor">Allocating and freeing a color entry</a></li> + <p> + Once we got access to some color map, we can strat allocating + colors. The informations related to a color are stored in the + following structure: + </p> + <pre class="code"> +typedef struct { + BYTE response_type; + CARD8 pad0; + CARD16 sequence; + CARD32 length; + CARD16 red; /* The red component */ + CARD16 green; /* The green component */ + CARD16 blue; /* The blue component */ + CARD8 pad1[2]; + CARD32 pixel; /* The entry in the color map, supplied by the X server */ +} XCBAllocColorRep; +</pre> + <p> + XCB supplies these two functions to fill it: + </p> + <pre class="code"> +XCBAllocColorCookie XCBAllocColor (XCBConnection *c, + XCBCOLORMAP cmap, + CARD16 red, + CARD16 green, + CARD16 blue); +XCBAllocColorRep *XCBAllocColorReply (XCBConnection *c, + XCBAllocColorCookie cookie, + XCBGenericError **e); +</pre> + <p> + The fuction <span class="code">XCBAllocColor()</span> takes the + 3 RGB components as parameters (red, green and blue). Here is an + example of using these functions: + </p> + <pre class="code"> +#include <malloc.h> + +#include <X11/XCB/xcb.h> + +int +main (int argc, char *argv[]) +{ + XCBConnection *c; + XCBSCREEN *screen; + XCBWINDOW win; + XCBCOLORMAP cmap; + XCBAllocColorRep *rep; + + /* Open the connection to the X server and get the first screen */ + c = XCBConnect (NULL, NULL); + screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data; + + /* We create the window win here*/ + + cmap = XCBCOLORMAPNew (c); + XCBCreateColormap (c, AllocNone, cmap, win, screen->root_visual); + + rep = XCBAllocColorReply (c, XCBAllocColor (c, cmap, 65535, 0, 0), 0); + + if (!rep) + return 0; + + /* Do something with r->pixel or the components */ + + free (rep); + + return 1; +} +</pre> + <p> + As <span class="code">XCBAllocColorReply()</span> allocates + memory, you have to free <span class="code">rep</span>. + </p> + <p> + <b>TODO</b>: Talk about freeing colors. + </p> + </ol> + <li class="title"><a name="pixmaps">X Bitmaps and Pixmaps</a></li> + <p> + One thing many so-called "Multi-Media" applications need to od, + is display images. In the X world, this is done using bitmaps + and pixmaps. We have already seen some usage of them when + setting an icon for our application. Lets study them further, + and see how to draw these images inside a window, along side the + simple graphics and text we have seen so far. + </p> + <p> + One thing to note before delving further, is that XCB (nor Xlib) + supplies no means of manipulating popular image formats, such as + gif, png, jpeg or tiff. It is up to the programmer (or to higher + level graphics libraries) to translate these image formats into + formats that the X server is familiar with (x bitmaps and x + pixmaps). + </p> + <ol> + <li class="subtitle"><a name="pixmapswhat">What is a X Bitmap ? An X Pixmap ?</a></li> + <p> + An X bitmap is a two-color image stored in a format specific + to the X window system. When stored in a file, the bitmap data + looks like a C source file. It contains variables defining the + width and the height of the bitmap, an array containing the + bit values of the bitmap (the size of the array is + weight*height), and an optional hot-spot location (that will + be explained later, when discussing mouse cursors). + </p> + <p> + An X pixmap is a format used to stored images in the memory of + an X server. This format can store both black and white images + (such as x bitmaps) as well as color images. It is the only + image format supported by the X protocol, and any image to be + drawn on screen, should be first translated into this format. + </p> + <p> + In actuality, an X pixmap can be thought of as a window that + does not appear on the screen. Many graphics operations that + work on windows, will also work on pixmaps. Indeed, the type + of X pixmap in XCB is an Id like a window: + </p> + <pre class="code"> +typedef struct { + CARD32 xid; +} XCBPIXMAP; +</pre> + <p> + In order to make the difference between a window and a pixmap, + XCB introduces a drawable type, which is a <b>union</b> + </p> + <pre class="code"> +typedef union { + XCBWINDOW window; + XCBPIXMAP pixmap; +} XCBDRAWABLE; +</pre> + <p> + in order to avoid confusion between a window and a pixmap.The + operations that will work indifferently on a window or a pixmap + will require a <span class="code">XCBDRAWABLE</span> + </p> + <div class="emph"> + <p> + Remark: In Xlib, there is no specific difference between a + <span class="code">Drawable</span>, a + <span class="code">Pixmap</span> or a + <span class="code">Window</span>: all are 32 bit long + integer. + </p> + </div> + <li class="subtitle"><a name="pixmapscreate">Creating a pixmap</a></li> + <p> + Sometimes we want to create an un-initialized pixmap, so we + can later draw into it. This is useful for image drawing + programs (creating a new empty canvas will cause the creation + of a new pixmap on which the drawing can be stored). It is + also useful when reading various image formats: we load the + image data into memory, create a pixmap on the server, and + then draw the decoded image data onto that pixmap. + </p> + <p> + To create a new pixmap, we first ask the X server to give an + Id to our pixmap, with this function: + </p> + <pre class="code"> +XCBPIXMAP XCBPIXMAPNew (XCBConnection *c); +</pre> + <p> + Then, XCB supplies the following function to create new pixmaps: + </p> + <pre class="code"> +XCBVoidCookie XCBCreatePixmap (XCBConnection *c, /* Pointer to the XCBConnection structure */ + CARD8 depth, /* Depth of the screen */ + XCBPIXMAP pid, /* Id of the pixmap */ + XCBDRAWABLE drawable, + CARD16 width, /* Width of the window (in pixels) */ + CARD16 height); /* Height of the window (in pixels) */ +</pre> + <p> + <b>TODO</b>: Explain the drawable parameter, and give an + example (like xpoints.c) + </p> + <li class="subtitle"><a name="pixmapsdraw"></a>Drawing a pixmap in a window</li> + <p> + Once we got a handle to a pixmap, we can draw it on some + window, using the following function: + </p> + <pre class="code"> +XCBVoidCookie XCBCopyArea (XCBConnection *c, /* Pointer to the XCBConnection structure */ + XCBDRAWABLE src_drawable, /* The Drawable we want to paste */ + XCBDRAWABLE dst_drawable, /* The Drawable on which we copy the previous Drawable */ + XCBGCONTEXT gc, /* A Graphic Context */ + INT16 src_x, /* Top left x coordinate of the region we want to copy */ + INT16 src_y, /* Top left y coordinate of the region we want to copy */ + INT16 dst_x, /* Top left x coordinate of the region where we want to copy */ + INT16 dst_y, /* Top left y coordinate of the region where we want to copy */ + CARD16 width, /* Width of the region we want to copy */ + CARD16 height); /* Height of the region we want to copy */ +</pre> + <p> + As you can see, we could copy the whole pixmap, as well as + only a given rectangle of the pixmap. This is useful to + optimize the drawing speed: we could copy only what we have + modified in the pixmap. + </p> + <p> + <b>One important note should be made</b>: it is possible to + create pixmaps with different depths on the same screen. When + we perform copy operations (a pixmaap onto a window, etc), we + should make sure that both source and target have the same + depth. If they have a different depth, the operation would + fail. The exception to this is if we copy a specific bit plane + of the source pixmap using the + <span class="code">XCBCopyPlane</span> function. In such an + event, we can copy a specific plain to the target window (in + actuality, setting a specific bit in the color of each pixel + copied). This can be used to generate strange graphic effects + in widow, but beyond the scope of this tutorial. + </p> + <li class="subtitle"><a name="pixmapsfree"></a>Freeing a pixmap</li> + <p> + Finally, when we are done using a given pixmap, we should free + it, in order to free resources of the X server. This is done + using this function: + </p> + <pre class="code"> +XCBVoidCookie XCBFreePixmap (XCBConnection *c, /* Pointer to the XCBConnection structure */ + XCBPIXMAP pixmap); /* A given pixmap */ +</pre> + <p> + Of course, after having freed it, we must not try accessing + the pixmap again. + </p> + <p> + <b>TODO</b>: Give an example, or a link to xpoints.c + </p> + </ol> + <li class="title"><a name="translation">Translation of basic Xlib functions and macros</a></li> + <p> + The problem when you want to port an Xlib program to XCB is that + you don't know if the Xlib function that you want to "translate" + is a X Window one or an Xlib macro. In that section, we describe + a way to translate the usual functions or macros that Xlib + provides. It's usually just a member of a structure. + </p> + <ol> + <li class="subtitle"><a name="displaystructure">Members of the Display structure</a></li> + In this section, we look at how to translate the macros that + returns some members of the <span class="code">Display</span> + structure. They are obtain by using a function that requires a + <span class="code">XCBConnection *</span> or a member of the + <span class="code">XCBConnSetupSuccessRep</span> structure + (via the function <span class="code">XCBGetSetup</span>), or + a function that requires that structure. + <ol> + <li class="subtitle"><a name="ConnectionNumber">ConnectionNumber</a></li> + <p> + This number is the file descriptor that connects the client + to the server. You just have to use that function: + </p> + <pre class="code"> +int XCBGetFileDescriptor(XCBConnection *c); +</pre> + <li class="subtitle"><a name="DefaultScreen"></a>DefaultScreen</li> + <p> + That number is not stored by XCB. It is returned in the + second parameter of the function <span class="code"><a href="#openconn">XCBConnect</a></span>. + Hence, you have to store it yourself if you want to use + it. Then, to get the <span class="code">XCBSCREEN</span> + structure, you have to iterate on the screens. + The equivalent function of the Xlib's + <span class="code">ScreenOfDisplay</span> function can be + found <a href="#ScreenOfDisplay">below</a>. OK, here is the + small piece of code to get that number: + </p> + <pre class="code"> +XCBConnection *c; +int screen_default_nbr; + +/* you pass the name of the display you want to XCBConnect */ + +c = XCBConnect (display_name, &screen_default_nbr); + +/* screen_default_nbr contains now the number of the default screen */ +</pre> + <li class="subtitle"><a name="QLength"></a>QLength</li> + <p> + Not documented yet. + </p> + <li class="subtitle"><a name="ScreenCount"></a>ScreenCount</li> + <p> + You get the count of screens with the functions + <span class="code">XCBGetSetup</span> + and + <span class="code">XCBConnSetupSuccessRepRootsIter</span> + (if you need to iterate): + </p> + <pre class="code"> +XCBConnection *c; +int screen_count; + +/* you init the connection */ + +screen_count = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).rem; + +/* screen_count contains now the count of screens */ +</pre> + <p> + If you don't want to iterate over the screens, a better way + to get that number is to use + <span class="code">XCBConnSetupSuccessRepRootsLength</span>: + </p> + <pre class="code"> +XCBConnection *c; +int screen_count; + +/* you init the connection */ + +screen_count = XCBConnSetupSuccessRepRootsLength (XCBGetSetup (c)); + +/* screen_count contains now the count of screens */ +</pre> + <li class="subtitle"><a name="ServerVendor"></a>ServerVendor</li> + <p> + You get the name of the vendor of the server hardware with + the functions <span class="code">XCBGetSetup</span> + and + <span + class="code">XCBConnSetupSuccessRepVendor</span>. Beware + that, unlike Xlib, the string returned by XCB is not + necessarily null-terminaled: + </p> + <pre class="code"> +XCBConnection *c; +char *vendor = NULL; +int length; + +/* you init the connection */ +length = XCBConnSetupSuccessRepVendorLength (XCBGetSetup (c)); +vendor = (char *)malloc (length + 1); +if (vendor) +memcpy (vendor, XCBConnSetupSuccessRepVendor (XCBGetSetup (c)), length); +vendor[length] = '\0'; + +/* vendor contains now the name of the vendor. Must be freed when not used anymore */ +</pre> + <li class="subtitle"><a name="ProtocolVersion"></a>ProtocolVersion</li> + <p> + You get the major version of the protocol in the + <span class="code">XCBConnSetupSuccessRep</span> + structure, with the function <span class="code">XCBGetSetup</span>: + </p> + <pre class="code"> +XCBConnection *c; +CARD16 protocol_major_version; + +/* you init the connection */ + +protocol_major_version = XCBGetSetup (c)->protocol_major_version; + +/* protocol_major_version contains now the major version of the protocol */ +</pre> + <li class="subtitle"><a name="ProtocolRevision"></a>ProtocolRevision</li> + <p> + You get the minor version of the protocol in the + <span class="code">XCBConnSetupSuccessRep</span> + structure, with the function <span class="code">XCBGetSetup</span>: + </p> + <pre class="code"> +XCBConnection *c; +CARD16 protocol_minor_version; + +/* you init the connection */ + +protocol_minor_version = XCBGetSetup (c)->protocol_minor_version; + +/* protocol_minor_version contains now the minor version of the protocol */ +</pre> + <li class="subtitle"><a name="VendorRelease"></a>VendorRelease</li> + <p> + You get the number of the release of the server hardware in the + <span class="code">XCBConnSetupSuccessRep</span> + structure, with the function <span class="code">XCBGetSetup</span>: + </p> + <pre class="code"> +XCBConnection *c; +CARD32 release_number; + +/* you init the connection */ + +release_number = XCBGetSetup (c)->release_number; + +/* release_number contains now the number of the release of the server hardware */ +</pre> + <li class="subtitle"><a name="DisplayString"></a>DisplayString</li> + <p> + The name of the display is not stored in XCB. You have to + store it by yourself. + </p> + <li class="subtitle"><a name="BitmapUnit"></a>BitmapUnit</li> + <p> + You get the bitmap scanline unit in the + <span class="code">XCBConnSetupSuccessRep</span> + structure, with the function <span class="code">XCBGetSetup</span>: + </p> + <pre class="code"> +XCBConnection *c; +CARD8 bitmap_format_scanline_unit; + +/* you init the connection */ + +bitmap_format_scanline_unit = XCBGetSetup (c)->bitmap_format_scanline_unit; + +/* bitmap_format_scanline_unit contains now the bitmap scanline unit */ +</pre> + <li class="subtitle"><a name="BitmapBitOrder"></a>BitmapBitOrder</li> + <p> + You get the bitmap bit order in the + <span class="code">XCBConnSetupSuccessRep</span> + structure, with the function <span class="code">XCBGetSetup</span>: + </p> + <pre class="code"> +XCBConnection *c; +CARD8 bitmap_format_bit_order; + +/* you init the connection */ + +bitmap_format_bit_order = XCBGetSetup (c)->bitmap_format_bit_order; + +/* bitmap_format_bit_order contains now the bitmap bit order */ +</pre> + <li class="subtitle"><a name="BitmapPad"></a>BitmapPad</li> + <p> + You get the bitmap scanline pad in the + <span class="code">XCBConnSetupSuccessRep</span> + structure, with the function <span class="code">XCBGetSetup</span>: + </p> + <pre class="code"> +XCBConnection *c; +CARD8 bitmap_format_scanline_pad; + +/* you init the connection */ + +bitmap_format_scanline_pad = XCBGetSetup (c)->bitmap_format_scanline_pad; + +/* bitmap_format_scanline_pad contains now the bitmap scanline pad */ +</pre> + <li class="subtitle"><a name="ImageByteOrder"></a>ImageByteOrder</li> + <p> + You get the image byte order in the + <span class="code">XCBConnSetupSuccessRep</span> + structure, with the function <span class="code">XCBGetSetup</span>: + </p> + <pre class="code"> +XCBConnection *c; +CARD8 image_byte_order; + +/* you init the connection */ + +image_byte_order = XCBGetSetup (c)->image_byte_order; + +/* image_byte_order contains now the image byte order */ +</pre> + </ol> + <li class="subtitle"><a name="screenofdisplay">ScreenOfDisplay related functions</a></li> + <p> + in Xlib, <span class="code">ScreenOfDisplay</span> returns a + <span class="code">Screen</span> structure that contains + several characteristics of your screen. XCB has a similar + structure (<span class="code">XCBSCREEN</span>), + but the way to obtain it is a bit different. With + Xlib, you just provide the number of the screen and you grab it + from an array. With XCB, you iterate over all the screens to + obtain the one you want. The complexity of this operation is + O(n). So the best is to store this structure if you often use + it. See <a href="#ScreenOfDisplay">ScreenOfDisplay</a> just below. + </p> + <p> + Xlib provides generally two functions to obtain the characteristics + related to the screen. One with the display and the number of + the screen, which calls <span class="code">ScreenOfDisplay</span>, + and the other that uses the <span class="code">Screen</span> structure. + This might be a bit confusing. As mentioned above, with XCB, it + is better to store the <span class="code">XCBSCREEN</span> + structure. Then, you have to read the members of this + structure. That's why the Xlib functions are put by pairs (or + more) as, with XCB, you will use the same code. + </p> + <ol> + <li class="subtitle"><a name="ScreenOfDisplay">ScreenOfDisplay</a></li> + <p> + This function returns the Xlib <span class="code">Screen</span> + structure. With XCB, you iterate over all thee screens and + once you get the one you want, you return it: + </p> + <pre class="code"><a name="ScreenOfDisplay"></a> +XCBSCREEN *ScreenOfDisplay (XCBConnection *c, + int screen) +{ + XCBSCREENIter iter; + + iter = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)); + for (; iter.rem; --screen, XCBSCREENNext (&iter)) + if (screen == 0) + return iter.data; + + return NULL; +} +</pre> + <p> + As mentioned above, you might want to store the value + returned by this function. + </p> + <p> + All the functions below will use the result of that + fonction, as they just grab a specific member of the + <span class="code">XCBSCREEN</span> structure. + </p> + <li class="subtitle"><a name="DefaultScreenOfDisplay"></a>DefaultScreenOfDisplay</li> + <p> + It is the default screen that you obtain when you connect to + the X server. It suffices to call the <a href="#ScreenOfDisplay">ScreenOfDisplay</a> + function above with the connection and the number of the + default screen. + </p> + <pre class="code"> +XCBConnection *c; +int screen_default_nbr; +XCBSCREEN *default_screen; /* the returned default screen */ + +/* you pass the name of the display you want to XCBConnect */ + +c = XCBConnect (display_name, &screen_default_nbr); +default_screen = ScreenOfDisplay (c, screen_default_nbr); + +/* default_screen contains now the default root window, or a NULL window if no screen is found */ +</pre> + <li class="subtitle"><a name="RootWindow">RootWindow / RootWindowOfScreen</a></li> + <p> + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +XCBWINDOW root_window = { 0 }; /* the returned window */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + root_window = screen->root; + +/* root_window contains now the root window, or a NULL window if no screen is found */ +</pre> + <li class="subtitle"><a name="DefaultRootWindow">DefaultRootWindow</a></li> + <p> + It is the root window of the default screen. So, you call + <a name="ScreenOfDisplay">ScreenOfDisplay</a> with the + default screen number and you get the + <a href="#RootWindow">root window</a> as above: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_default_nbr; +XCBWINDOW root_window = { 0 }; /* the returned root window */ + +/* you pass the name of the display you want to XCBConnect */ + +c = XCBConnect (display_name, &screen_default_nbr); +screen = ScreenOfDisplay (c, screen_default_nbr); +if (screen) + root_window = screen->root; + +/* root_window contains now the default root window, or a NULL window if no screen is found */ +</pre> + <li class="subtitle"><a name="DefaultVisual">DefaultVisual / DefaultVisualOfScreen</a></li> + <p> + While a Visual is, in Xlib, a structure, in XCB, there are + two types: <span class="code">XCBVISUALID</span>, which is + the Id of the visual, and <span class="code">XCBVISUALTYPE</span>, + which corresponds to the Xlib Visual. To get the Id of the + visual of a screen, just get the + <span class="code">root_visual</span> + member of a <span class="code">XCBSCREEN</span>: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +XCBVISUALID root_visual = { 0 }; /* the returned visual Id */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + root_visual = screen->root_visual; + +/* root_visual contains now the value of the Id of the visual, or a NULL visual if no screen is found */ +</pre> + <p> + To get the <span class="code">XCBVISUALTYPE</span> + structure, it's a bit less easier. You have to get the + <span class="code">XCBSCREEN</span> structure that you want, + get its <span class="code">root_visual</span> member, + then iterate on the <span class="code">XCBDEPTH</span>s + and the <span class="code">XCBVISUALTYPE</span>s, and compare + the <span class="code">XCBVISUALID</span> of these <span class="code">XCBVISUALTYPE</span>s: + with <span class="code">root_visual</span>: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +XCBVISUALID root_visual = { 0 }; +XCBVISUATYPE *visual_type = NULL; /* the returned visual type */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + { + XCBDEPTHIter depth_iter; + + depth_iter = XCBSCREENAllowedDepthsIter (screen); + for (; depth_iter.rem; XCBDEPTHNext (&depth_iter)) + { + XCBVISUALTYPEIter visual_iter; + + visual_iter = XCBDEPTHVisualsIter (depth_iter.data); + for (; visual_iter.rem; XCBVISUALTYPENext (&visual_iter)) + { + if (screen->root_visual.id == visual_iter.data->visual_id.id) + { + visual_type = visual_iter.data; + break; + } + } + } + } + +/* visual_type contains now the visual structure, or a NULL visual structure if no screen is found */ +</pre> + <li class="subtitle"><a name="DefaultGC">DefaultGC / DefaultGCOfScreen</a></li> + <p> + This default Graphic Context is just a newly created Graphic + Context, associated to the root window of a + <span class="code">XCBSCREEN</span>, + using the black white pixels of that screen: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +XCBGCONTEXT gc = { 0 }; /* the returned default graphic context */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + { + XCBDRAWABLE draw; + CARD32 mask; + CARD32 values[2]; + + gc = XCBGCONTEXTNew (c); + draw.window = screen->root; + mask = GCForeground | GCBackground; + values[0] = screen->black_pixel; + values[1] = screen->white_pixel; + XCBCreateGC (c, gc, draw, mask, values); + } + +/* gc contains now the default graphic context */ +</pre> + <li class="subtitle"><a name="BlackPixel">BlackPixel / BlackPixelOfScreen</a></li> + <p> + It is the Id of the black pixel, which is in the structure + of an <span class="code">XCBSCREEN</span>. + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD32 black_pixel = 0; /* the returned black pixel */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + black_pixel = screen->black_pixel; + +/* black_pixel contains now the value of the black pixel, or 0 if no screen is found */ +</pre> + <li class="subtitle"><a name="WhitePixel">WhitePixel / WhitePixelOfScreen</a></li> + <p> + It is the Id of the white pixel, which is in the structure + of an <span class="code">XCBSCREEN</span>. + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD32 white_pixel = 0; /* the returned white pixel */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + white_pixel = screen->white_pixel; + +/* white_pixel contains now the value of the white pixel, or 0 if no screen is found */ +</pre> + <li class="subtitle"><a name="DisplayWidth">DisplayWidth / WidthOfScreen</a></li> + <p> + It is the width in pixels of the screen that you want, and + which is in the structure of the corresponding + <span class="code">XCBSCREEN</span>. + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD32 width_in_pixels = 0; /* the returned width in pixels */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + width_in_pixels = screen->width_in_pixels; + +/* width_in_pixels contains now the width in pixels, or 0 if no screen is found */ +</pre> + <li class="subtitle"><a name="DisplayHeight">DisplayHeight / HeightOfScreen</a></li> + <p> + It is the height in pixels of the screen that you want, and + which is in the structure of the corresponding + <span class="code">XCBSCREEN</span>. + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD32 height_in_pixels = 0; /* the returned height in pixels */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + height_in_pixels = screen->height_in_pixels; + +/* height_in_pixels contains now the height in pixels, or 0 if no screen is found */ +</pre> + <li class="subtitle"><a name="DisplayWidthMM">DisplayWidthMM / WidthMMOfScreen</a></li> + <p> + It is the width in millimeters of the screen that you want, and + which is in the structure of the corresponding + <span class="code">XCBSCREEN</span>. + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD32 width_in_millimeters = 0; /* the returned width in millimeters */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + width_in_millimeters = screen->width_in_millimeters; + +/* width_in_millimeters contains now the width in millimeters, or 0 if no screen is found */ +</pre> + <li class="subtitle"><a name="DisplayHeightMM">DisplayHeightMM / HeightMMOfScreen</a></li> + <p> + It is the height in millimeters of the screen that you want, and + which is in the structure of the corresponding + <span class="code">XCBSCREEN</span>. + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD32 height_in_millimeters = 0; /* the returned height in millimeters */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + height_in_millimeters = screen->height_in_millimeters; + +/* height_in_millimeters contains now the height in millimeters, or 0 if no screen is found */ +</pre> + <li class="subtitle"><a name="DisplayPlanes">DisplayPlanes / DefaultDepth / DefaultDepthOfScreen / PlanesOfScreen</a></li> + <p> + It is the depth (in bits) of the root window of the + screen. You get it from the <span class="code">XCBSCREEN</span> structure. + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD8 root_depth = 0; /* the returned depth of the root window */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + root_depth = screen->root_depth; + +/* root_depth contains now the depth of the root window, or 0 if no screen is found */ +</pre> + <li class="subtitle"><a name="DefaultColormap">DefaultColormap / DefaultColormapOfScreen</a></li> + <p> + This is the default colormap of the screen (and not the + (default) colormap of the default screen !). As usual, you + get it from the <span class="code">XCBSCREEN</span> structure: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +XCBCOLORMAP default_colormap = { 0 }; /* the returned default colormap */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + default_colormap = screen->default_colormap; + +/* default_colormap contains now the default colormap, or a NULL colormap if no screen is found */ +</pre> + <li class="subtitle"><a name="MinCmapsOfScreen"></a>MinCmapsOfScreen</li> + <p> + You get the minimum installed colormaps in the <span class="code">XCBSCREEN</span> structure: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD16 min_installed_maps = 0; /* the returned minimum installed colormaps */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + min_installed_maps = screen->min_installed_maps; + +/* min_installed_maps contains now the minimum installed colormaps, or 0 if no screen is found */ +</pre> + <li class="subtitle"><a name="MaxCmapsOfScreen"></a>MaxCmapsOfScreen</li> + <p> + You get the maximum installed colormaps in the <span class="code">XCBSCREEN</span> structure: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD16 max_installed_maps = 0; /* the returned maximum installed colormaps */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + max_installed_maps = screen->max_installed_maps; + +/* max_installed_maps contains now the maximum installed colormaps, or 0 if no screen is found */ +</pre> + <li class="subtitle"><a name="DoesSaveUnders"></a>DoesSaveUnders</li> + <p> + You know if <span class="code">save_unders</span> is set, + by looking in the <span class="code">XCBSCREEN</span> structure: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +BOOL save_unders = 0; /* the returned value of save_unders */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + save_unders = screen->save_unders; + +/* save_unders contains now the value of save_unders, or FALSE if no screen is found */ +</pre> + <li class="subtitle"><a name="DoesBackingStore"></a>DoesBackingStore</li> + <p> + You know the value of <span class="code">backing_stores</span>, + by looking in the <span class="code">XCBSCREEN</span> structure: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +BYTE backing_stores = 0; /* the returned value of backing_stores */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + backing_stores = screen->backing_stores; + +/* backing_stores contains now the value of backing_stores, or FALSE if no screen is found */ +</pre> + <li class="subtitle"><a name="EventMaskOfScreen"></a>EventMaskOfScreen</li> + <p> + To get the current input masks, + you look in the <span class="code">XCBSCREEN</span> structure: + </p> + <pre class="code"> +XCBConnection *c; +XCBSCREEN *screen; +int screen_nbr; +CARD32 current_input_masks = 0; /* the returned value of current input masks */ + +/* you init the connection and screen_nbr */ + +screen = ScreenOfDisplay (c, screen_nbr); +if (screen) + current_input_masks = screen->current_input_masks; + +/* current_input_masks contains now the value of the current input masks, or FALSE if no screen is found */ +</pre> + </ol> + <li class="subtitle"><a name="misc">Miscellaneous macros</a></li> + <ol> + <li class="subtitle"><a name="DisplayOfScreen"></a>DisplayOfScreen</li> + <p> + in Xlib, the <span class="code">Screen</span> structure + stores its associated <span class="code">Display</span> + structure. This is not the case in the X Window protocol, + hence, it's also not the case in XCB. So you have to store + it by yourself. + </p> + <li class="subtitle"><a name="DisplayCells"></a>DisplayCells / CellsOfScreen</li> + <p> + To get the colormap entries, + you look in the <span class="code">XCBVISUALTYPE</span> + structure, that you grab like <a class="subsection" href="#DefaultVisual">here</a>: + </p> + <pre class="code"> +XCBConnection *c; +XCBVISUALTYPE *visual_type; +CARD16 colormap_entries = 0; /* the returned value of the colormap entries */ + +/* you init the connection and visual_type */ + +if (visual_type) + colormap_entries = visual_type->colormap_entries; + +/* colormap_entries contains now the value of the colormap entries, or FALSE if no screen is found */ +</pre> + </ol> + </ol> + </ol> + </div> +</body> + +</html> |