diff --git a/Makefile.am b/Makefile.am index e399ae0..2dce719 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,4 +48,8 @@ xcb-xfixes.pc.in \ xcb-xprint.pc.in \ xcb-xtest.pc.in \ xcb-xv.pc.in \ -xcb-xvmc.pc.in +xcb-xvmc.pc.in \ +tools/README \ +tools/api_conv.pl \ +tools/constants \ +autogen.sh diff --git a/NEWS b/NEWS index 91e7348..a0260cb 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,60 @@ +Release 1.1 (2007-11-04) +======================== + +This release requires xcb-proto 1.1, due to the addition of the +extension-multiword attribute to the XML schema. + +This release contains several important bug fixes, summarized below. It +also contains a patch much like Novell's libxcb-sloppy-lock.diff. +Rationale from the commit message follows. The patch and this rationale +were authored by Jamey Sharp , with agreement from +Josh Triplett . + + I strongly opposed proposals like this one for a long time. + Originally I had a very good reason: libX11, when compiled to use + XCB, would crash soon after a locking correctness violation, so it + was better to have an informative assert failure than a mystifying + crash soon after. + + It took some time for me to realize that I'd changed the libX11 + implementation (for unrelated reasons) so that it could survive most + invalid locking situations, as long as it wasn't actually being used + from multiple threads concurrently. + + The other thing that has changed is that most of the code with + incorrect locking has now been fixed. The value of the assert is + accordingly lower. + + However, remaining broken callers do need to be fixed. That's why + libXCB will still noisily print a stacktrace (if possible) on each + assertion failure, even when assert isn't actually invoked to + abort() the program; and that's why aborting is still default. This + environment variable is provided only for use as a temporary + workaround for broken applications. + +Enhancements: +* Print a backtrace, if possible, on locking assertion failures. +* Skip abort() on locking assertions if LIBXCB_ALLOW_SLOPPY_LOCK is set. +* xcb_poll_for_event: Return already-read events before reading again. +* Output a configuration summary at the end of ./configure. + +Bug fixes: +* Don't hold the xlib-xcb lock while sleeping: that allows deadlock. +* Allow unix: style display names again. +* Bug #9119: test xcb_popcount +* Fix unit tests for FreeBSD +* NetBSD doesn't have AI_ADDRCONFIG: use it only if it's available. +* Require libXau >= 0.99.2; earlier versions have a broken .pc file +* Use substitition variables in xcb-xinerama.pc.in +* Update autogen.sh to one that does objdir != srcdir +* Add tools/* and autogen.sh to EXTRA_DIST. +* Doxygen can now be fully disabled if desired. + +Documentation improvements: +* Many fixes and updates to the tutorial. +* Iterators, requests, and replies get partial Doxygen documentation. + + Release 1.0 (2006-11-23) ======================== diff --git a/README b/README index 5629fe9..167c8ac 100644 --- a/README +++ b/README @@ -1,11 +1,12 @@ About libxcb ============ -libxcb provides an interface to the X Window System protocol, which replaces -the current Xlib interface. It has several advantages over Xlib, including: -- size: small library and lower memory footprint +libxcb provides an interface to the X Window System protocol, which +replaces the current Xlib interface. It has several advantages over +Xlib, including: +- size: small, simple library, and lower memory footprint - latency hiding: batch several requests and wait for the replies later -- direct protocol access: one-to-one mapping between interface and protocol +- direct protocol access: interface and protocol correspond exactly - proven thread support: transparently access XCB from multiple threads - easy extension implementation: interfaces auto-generated from XML-XCB diff --git a/acinclude.m4 b/acinclude.m4 index 186873c..8b240ad 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -44,12 +44,16 @@ AC_DEFUN([AM_CHECK_DOXYGEN], AC_HELP_STRING( [--disable-build-docs], [Disable the build of the documentation]), - [if test "${disable_build_docs}" = "yes" ; then + [if test x"$enableval" != x"yes" ; then enable_build_docs="no" else enable_build_docs="yes" fi], [enable_build_docs="yes"]) + + if test "$enable_build_docs" = "no" ; then + BUILD_DOCS=no + else dnl dnl Get the prefix where doxygen is installed. dnl @@ -93,6 +97,7 @@ AC_DEFUN([AM_CHECK_DOXYGEN], AC_MSG_WARN( [Warning: no doxygen detected. Documentation will not be built]) fi]) + fi AC_MSG_CHECKING([whether documentation is built]) AC_MSG_RESULT([${BUILD_DOCS}]) dnl diff --git a/autogen.sh b/autogen.sh index d68a142..904cd67 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,3 +1,12 @@ #! /bin/sh + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir + autoreconf -v --install || exit 1 -./configure "$@" +cd $ORIGDIR || exit $? + +$srcdir/configure --enable-maintainer-mode "$@" diff --git a/configure.ac b/configure.ac index b400f03..df554e6 100644 --- a/configure.ac +++ b/configure.ac @@ -3,13 +3,13 @@ AC_PREREQ(2.57) AC_INIT([libxcb], - 1.0, + 1.1, [xcb@lists.freedesktop.org]) AC_CONFIG_SRCDIR([xcb.pc.in]) AM_INIT_AUTOMAKE([foreign dist-bzip2]) -PKG_CHECK_MODULES(CHECK, [check >= 0.9.4], [HAVE_CHECK=true], [HAVE_CHECK=false]) -AM_CONDITIONAL(HAVE_CHECK, test x$HAVE_CHECK = xtrue) +PKG_CHECK_MODULES(CHECK, [check >= 0.9.4], [HAVE_CHECK=yes], [HAVE_CHECK=no]) +AM_CONDITIONAL(HAVE_CHECK, test x$HAVE_CHECK = xyes) AC_CONFIG_HEADERS([src/config.h]) @@ -22,7 +22,7 @@ if test "$XSLTPROC" = "no"; then fi HTML_CHECK_RESULT=false -if test x"$HAVE_CHECK" = xtrue; then +if test x"$HAVE_CHECK" = xyes; then if test x"$XSLTPROC" != xno; then HTML_CHECK_RESULT=true fi @@ -30,15 +30,17 @@ fi AC_SUBST(HTML_CHECK_RESULT) # Checks for pkg-config packages -PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.0) -NEEDED="xau pthread-stubs" +PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.1) +NEEDED="pthread-stubs xau >= 0.99.2" PKG_CHECK_MODULES(NEEDED, $NEEDED) +have_xdmcp="no" PKG_CHECK_MODULES(XDMCP, xdmcp, AC_CHECK_LIB(Xdmcp, XdmcpWrap, [ AC_DEFINE(HASXDMAUTH,1,[Has Wraphelp.c needed for XDM AUTH protocols]) NEEDED="$NEEDED xdmcp" + have_xdmcp="yes" ], [ XDMCP_CFLAGS= @@ -46,6 +48,8 @@ PKG_CHECK_MODULES(XDMCP, xdmcp, ], [$XDMCP_LIBS]), [AC_MSG_RESULT(no)]) +AC_CHECK_HEADER([execinfo.h], [AC_DEFINE(HAVE_BACKTRACE,1,[Has backtrace*() needed for retrieving stack traces])]) + AC_SUBST(NEEDED) # Find the xcb-proto protocol descriptions @@ -87,3 +91,21 @@ AC_CONFIG_FILES([xcb.pc xcb-xlib.pc xcb-composite.pc xcb-damage.pc xcb-dpms.pc x AC_CONFIG_FILES([doc/xcb.doxygen]) AC_OUTPUT + +dnl Configuration output + +echo "" +echo " Package: ${PACKAGE_NAME} ${PACKAGE_VERSION}" +echo "" +echo " Configuration" +echo " XDM support.........: ${have_xdmcp}" +echo " Build unit tests....: ${HAVE_CHECK}" +echo "" +echo " Used CFLAGS:" +echo " CPPFLAGS............: ${CPPFLAGS}" +echo " CFLAGS..............: ${CFLAGS}" +echo " Warning CFLAGS......: ${CWARNFLAGS}" +echo "" +echo " Installation:" +echo " Prefix..............: ${prefix}" +echo "" diff --git a/doc/tutorial/index.html b/doc/tutorial/index.html index ea53305..c540426 100644 --- a/doc/tutorial/index.html +++ b/doc/tutorial/index.html @@ -59,9 +59,10 @@
  • Handling text and fonts
    1. The Font structure -
    2. Loading a Font -
    3. Assigning a Font to a Graphic Context -
    4. Drawing text in a window +
    5. Opening a Font +
    6. Assigning a Font to a Graphic Context +
    7. Drawing text in a drawable +
    8. Complete example
  • Windows hierarchy
      @@ -177,8 +178,9 @@ level GUI toolkit like Motif, LessTiff, GTK, - QT or - EWL, or use + QT, + EWL, + ETK, or use Cairo. However, we need to start somewhere. More than this, knowing how things @@ -386,7 +388,7 @@ #include <string.h> #include <sys/time.h> -#include <X11/XCB/xcb.h> +#include <xcb/xcb.h> #include <X11/Xlib.h> @@ -587,8 +589,8 @@ gcc -Wall prog.c -o prog `pkg-config --cflags --libs xcb` will be the one in the environment variable DISPLAY.

      -xcb_connection_t *xcb_connect (const char *displayname,
      -                               int        *screenp);
      +xcb_connection_t *xcb_connect (const char *displayname,
      +                               int        *screenp);
       

      The second parameter returns the screen number used for the @@ -596,24 +598,24 @@ gcc -Wall prog.c -o prog `pkg-config --cflags --libs xcb` and is opaque. Here is how the connection can be opened:

      -#include <X11/XCB/xcb.h>
      +#include <xcb/xcb.h>
       
      -int
      -main ()
      +int
      +main ()
       {
      -  xcb_connection_t *c;
      +  xcb_connection_t *c;
       
         /* Open the connection to the X server. Use the DISPLAY environment variable as the default display name */
         c = xcb_connect (NULL, NULL);
       
      -  return 0;
      +  return 0;
       }
       

      To close a connection, it suffices to use:

      -void xcb_disconnect (xcb_connection_t *c);
      +void xcb_disconnect (xcb_connection_t *c);
       
      @@ -640,8 +642,7 @@ gcc -Wall prog.c -o prog `pkg-config --cflags --libs xcb`
      -

      -

      +
    1. Checking basic information about a connection

      Once we have opened a connection to an X server, we should check some @@ -684,7 +685,7 @@ xcb_screen_iterator_t xcb_setup_roots_iterator (xcb_setup_t *R);

       #include <stdio.h>
       
      -#include <X11/XCB/xcb.h>
      +#include <xcb/xcb.h>
       
       int
       main ()
      @@ -706,7 +707,7 @@ main ()
           }
       
         printf ("\n");
      -  printf ("Informations of screen %ld:\n", screen->root.xid);
      +  printf ("Informations of screen %ld:\n", screen->root);
         printf ("  width.........: %d\n", screen->width_in_pixels);
         printf ("  height........: %d\n", screen->height_in_pixels);
         printf ("  white pixel...: %ld\n", screen->white_pixel);
      @@ -723,15 +724,13 @@ main ()
             characterized by an Id. So, in XCB, a window is of type:
             

      -typedef struct {
      -    uint32_t xid;
      -} xcb_window_t;
      +typedef uint32_t xcb_window_t;
       

      We first ask for a new Id for our window, with this function:

      -xcb_window_t xcb_window_new(xcb_connection_t *c);
      +xcb_window_t xcb_generate_id(xcb_connection_t *c);
       

      Then, XCB supplies the following function to create new windows: @@ -769,14 +768,14 @@ xcb_void_cookie_t xcb_map_window (xcb_connection_t *c,

       #include <unistd.h>      /* pause() */
       
      -#include <X11/XCB/xcb.h>
      +#include <xcb/xcb.h>
       
       int
       main ()
       {
         xcb_connection_t *c;
         xcb_screen_t     *screen;
      -  xcb_drawable_t    win;
      +  xcb_window_t      win;
       
         /* Open the connection to the X server */
         c = xcb_connect (NULL, NULL);
      @@ -785,12 +784,12 @@ main ()
         screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
       
         /* Ask for our window's Id */
      -  win.window = xcb_window_new(c);
      +  win = xcb_generate_id(c);
       
         /* Create the window */
         xcb_create_window (c,                             /* Connection          */
                            XCB_COPY_FROM_PARENT,          /* depth (same as root)*/
      -                     win.window,                    /* window Id           */
      +                     win,                           /* window Id           */
                            screen->root,                  /* parent window       */
                            0, 0,                          /* x, y                */
                            150, 150,                      /* width, height       */
      @@ -800,7 +799,7 @@ main ()
                            0, NULL);                      /* masks, not used yet */
       
         /* Map the window on the screen */
      -  xcb_map_window (c, win.window);
      +  xcb_map_window (c, win);
       
         /* Make sure commands are sent before we pause, so window is shown */
         xcb_flush (c);
      @@ -836,8 +835,8 @@ int xcb_aux_sync (xcb_connection_t *c);
             now, we put it there.
             

      - The window that is created by the above code has a default - background (gray). This one can be set to a specific color, + The window that is created by the above code has a non defined + background. This one can be set to a specific color, thanks to the two last parameters of xcb_create_window(), which are not described yet. See the subsections @@ -862,7 +861,7 @@ int xcb_aux_sync (xcb_connection_t *c);

        -
      • xcb_window_new () +
      • xcb_generate_id ()
      • xcb_create_window ()
      @@ -887,16 +886,14 @@ int xcb_aux_sync (xcb_connection_t *c); a Graphics Context is, as a window, characterized by an Id:

      -typedef struct {
      -    uint32_t xid;
      -} xcb_gcontext_t;
      +typedef uint32_t xcb_gcontext_t;
       

      We first ask the X server to attribute an Id to our graphic context with this function:

      -xcb_gcontext_t xcb_gcontext_new (xcb_connection_t *c);
      +xcb_gcontext_t xcb_generate_id (xcb_connection_t *c);
       

      Then, we set the attributes of the graphic context with this function: @@ -914,7 +911,7 @@ xcb_void_cookie_t xcb_create_gc (xcb_connection_t *c, draw in foreground with a black color.

      -#include <X11/XCB/xcb.h>
      +#include <xcb/xcb.h>
       
       int
       main ()
      @@ -931,8 +928,8 @@ main ()
         screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
       
         /* Create a black graphic context for drawing in the foreground */
      -  win.window = screen->root;
      -  black = xcb_gcontext_new (c);
      +  win = screen->root;
      +  black = xcb_generate_id (c);
         mask = XCB_GC_FOREGROUND;
         value[0] = screen->black_pixel;
         xcb_create_gc (c, black, win, mask, value);
      @@ -970,7 +967,7 @@ main ()
                 
                 
        -
      • xcb_gcontext_new () +
      • xcb_generate_id ()
      • xcb_create_gc ()
      @@ -982,8 +979,9 @@ main () 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: + color and + Assigning a Font to a Graphic Context). + This is done by using this function:

       xcb_void_cookie_t xcb_change_gc (xcb_connection_t *c,           /* The XCB Connection */
      @@ -1246,7 +1244,7 @@ xcb_void_cookie_t xcb_poly_fill_arc (xcb_connection_t *c,
       #include <stdlib.h>
       #include <stdio.h>
       
      -#include <X11/XCB/xcb.h>
      +#include <xcb/xcb.h>
       
       int
       main ()
      @@ -1291,16 +1289,16 @@ main ()
         screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
       
         /* Create black (foreground) graphic context */
      -  win.window = screen->root;
      +  win = screen->root;
       
      -  foreground = xcb_gcontext_new (c);
      +  foreground = xcb_generate_id (c);
         mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
         values[0] = screen->black_pixel;
         values[1] = 0;
         xcb_create_gc (c, foreground, win, mask, values);
       
         /* Ask for our window's Id */
      -  win.window = xcb_window_new(c);
      +  win = xcb_generate_id(c);
       
         /* Create the window */
         mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
      @@ -1308,7 +1306,7 @@ main ()
         values[1] = XCB_EVENT_MASK_EXPOSURE;
         xcb_create_window (c,                             /* Connection          */
                            XCB_COPY_FROM_PARENT,          /* depth               */
      -                     win.window,                    /* window Id           */
      +                     win,                           /* window Id           */
                            screen->root,                  /* parent window       */
                            0, 0,                          /* x, y                */
                            150, 150,                      /* width, height       */
      @@ -1318,7 +1316,7 @@ main ()
                            mask, values);                 /* masks */
       
         /* Map the window on the screen */
      -  xcb_map_window (c, win.window);
      +  xcb_map_window (c, win);
       
       
         /* We flush the request */
      @@ -1391,8 +1389,8 @@ main ()
               
         mask = XCB_CW_EVENT_MASK;
         valwin[0] = XCB_EVENT_MASK_EXPOSURE;
      -  win.window = xcb_window_new (c);
      -  xcb_create_window (c, depth, win.window, root->root,
      +  win = xcb_generate_id (c);
      +  xcb_create_window (c, depth, win, root->root,
                            0, 0, 150, 150, 10,
                            XCB_WINDOW_CLASS_INPUT_OUTPUT, root->root_visual,
                            mask, valwin);
      @@ -1405,8 +1403,8 @@ main ()
               
         mask = XCB_CW_EVENT_MASK;
         valwin[0] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS;
      -  win.window = xcb_window_new (c);
      -  xcb_create_window (c, depth, win.window, root->root,
      +  win = xcb_generate_id (c);
      +  xcb_create_window (c, depth, win, root->root,
                            0, 0, 150, 150, 10,
                            XCB_WINDOW_CLASS_INPUT_OUTPUT, root->root_visual,
                            mask, valwin);
      @@ -1894,7 +1892,7 @@ typedef xcb_key_press_event_t xcb_key_release_event_t;
       #include <stdlib.h>
       #include <stdio.h>
       
      -#include <X11/XCB/xcb.h>
      +#include <xcb/xcb.h>
       
       void
       print_modifiers (uint32_t mask)
      @@ -1916,7 +1914,7 @@ main ()
       {
         xcb_connection_t    *c;
         xcb_screen_t        *screen;
      -  xcb_drawable_t       win;
      +  xcb_window_t         win;
         xcb_generic_event_t *e;
         uint32_t             mask = 0;
         uint32_t             values[2];
      @@ -1928,7 +1926,7 @@ main ()
         screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
       
         /* Ask for our window's Id */
      -  win.window = xcb_window_new (c);
      +  win = xcb_generate_id (c);
       
         /* Create the window */
         mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
      @@ -1939,7 +1937,7 @@ main ()
                     XCB_EVENT_MASK_KEY_PRESS      | XCB_EVENT_MASK_KEY_RELEASE;
         xcb_create_window (c,                             /* Connection          */
                            0,                             /* depth               */
      -                     win.window,                    /* window Id           */
      +                     win,                           /* window Id           */
                            screen->root,                  /* parent window       */
                            0, 0,                          /* x, y                */
                            150, 150,                      /* width, height       */
      @@ -1949,7 +1947,7 @@ main ()
                            mask, values);                 /* masks */
       
         /* Map the window on the screen */
      -  xcb_map_window (c, win.window);
      +  xcb_map_window (c, win);
       
         xcb_flush (c);
       
      @@ -1959,25 +1957,25 @@ main ()
             xcb_expose_event_t *ev = (xcb_expose_event_t *)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);
      +              ev->window, ev->x, ev->y, ev->width, ev->height);
             break;
           }
           case XCB_BUTTON_PRESS: {
             xcb_button_press_event_t *ev = (xcb_button_press_event_t *)e;
             print_modifiers(ev->state);
       
      -      switch (ev->detail.id) {
      +      switch (ev->detail) {
             case 4:
               printf ("Wheel Button up in window %ld, at coordinates (%d,%d)\n",
      -                ev->event.xid, ev->event_x, ev->event_y);
      +                ev->event, 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);
      +                ev->event, 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);
      +                ev->detail, ev->event, ev->event_x, ev->event_y);
             }
             break;
           }
      @@ -1986,28 +1984,28 @@ main ()
             print_modifiers(ev->state);
       
             printf ("Button %d released in window %ld, at coordinates (%d,%d)\n",
      -              ev->detail.id, ev->event.xid, ev->event_x, ev->event_y);
      +              ev->detail, ev->event, ev->event_x, ev->event_y);
             break;
           }
           case XCB_MOTION_NOTIFY: {
             xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)e;
       
             printf ("Mouse moved in window %ld, at coordinates (%d,%d)\n",
      -              ev->event.xid, ev->event_x, ev->event_y);
      +              ev->event, ev->event_x, ev->event_y);
             break;
           }
           case XCB_ENTER_NOTIFY: {
             xcb_enter_notify_event_t *ev = (xcb_enter_notify_event_t *)e;
       
             printf ("Mouse entered window %ld, at coordinates (%d,%d)\n",
      -              ev->event.xid, ev->event_x, ev->event_y);
      +              ev->event, ev->event_x, ev->event_y);
             break;
           }
           case XCB_LEAVE_NOTIFY: {
             xcb_leave_notify_event_t *ev = (xcb_leave_notify_event_t *)e;
       
             printf ("Mouse left window %ld, at coordinates (%d,%d)\n",
      -              ev->event.xid, ev->event_x, ev->event_y);
      +              ev->event, ev->event_x, ev->event_y);
             break;
           }
           case XCB_KEY_PRESS: {
      @@ -2015,7 +2013,7 @@ main ()
             print_modifiers(ev->state);
       
             printf ("Key pressed in window %ld\n",
      -              ev->event.xid);
      +              ev->event);
             break;
           }
           case XCB_KEY_RELEASE: {
      @@ -2023,7 +2021,7 @@ main ()
             print_modifiers(ev->state);
       
             printf ("Key released in window %ld\n",
      -              ev->event.xid);
      +              ev->event);
             break;
           }
           default:
      @@ -2051,22 +2049,314 @@ main ()
             
      1. The Font structure

        - In order to support flexible fonts, a font structure is + In order to support flexible fonts, a font type is defined. You know what ? It's an Id:

        -typedef struct {
        -    uint32_t xid;
        -} xcb_font_t;
        +typedef uint32_t xcb_font_t;
         

        It is used to contain information about a font, and is passed to several functions that handle fonts selection and text drawing. + We ask the X server to attribute an Id to our font with the + function:

        +
        +xcb_font_t xcb_generate_id (xcb_connection_t *c);
        +
        +
        +
      2. Opening a Font

        - TODO: example for picking a font and displaying some text. - Even better, also demonstrate translating keypresses to text. + To open a font, we use the following function:

        +
        +xcb_void_cookie_t xcb_open_font (xcb_connection_t *c,
        +                                 xcb_font_t        fid,
        +                                 uint16_t          name_len,
        +                                 const char       *name);
        +
        +

        + The fid parameter is the font Id + defined by xcb_generate_id() (see + above). The name parameter is the + name of the font you want to open. Use the command + xlsfonts in a terminal to know which + are the fonts available on your computer. The parameter + name_len is the length of the name + of the font (given by strlen()). +

        +
      3. Assigning a Font to a Graphic Context +

        + Once a font is opened, you have to create a Graphic Context + that will contain the informations about the color of the + foreground and the background used when you draw a text in a + Drawable. Here is an exemple of a Graphic Context that will + allow us to draw an opened font with a black foreground and a + white background: +

        +
        +  /*
        +   * c is the connection
        +   * screen is the screen where the window is displayed
        +   * window is the window in which we will draw the text
        +   * font is the opened font
        +   */
        +
        +  uint32_t             value_list[3];
        +  xcb_gcontext_t       gc;
        +  uint32_t             mask;
        +
        +  gc = xcb_generate_id (c);
        +  mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
        +  value_list[0] = screen->black_pixel;
        +  value_list[1] = screen->white_pixel;
        +  value_list[2] = font;
        +  xcb_create_gc (c, gc, window, mask, value_list);
        +
        +  /* The font is not needed anymore, so we close it */
        +  xcb_close_font (c, font);
        +
        +
      4. Drawing text in a drawable +

        + To draw a text in a drawable, we use the following function: +

        +
        +xcb_void_cookie_t xcb_image_text_8 (xcb_connection_t *c,
        +                                    uint8_t           string_len,
        +                                    xcb_drawable_t    drawable,
        +                                    xcb_gcontext_t    gc,
        +                                    int16_t           x,
        +                                    int16_t           y,
        +                                    const char       *string);
        +
        +

        + The string parameter is the text to + draw. The location of the drawing is given by the parameters + x and y. + The base line of the text is exactly the parameter + y. +

        +
      5. Complete example +

        + This example draw a text at 10 pixels (for the base line) of + the bottom of a window. Pressing the Esc key exits the program. +

        +
        +#include <stdlib.h>
        +#include <stdio.h>
        +#include <string.h>
        +
        +#include <xcb/xcb.h>
        +
        +#define WIDTH 300
        +#define HEIGHT 100
        +
        +
        +
        +static xcb_gc_t gc_font_get (xcb_connection_t *c,
        +                             xcb_screen_t     *screen,
        +                             xcb_window_t      window,
        +                             const char       *font_name);
        +
        +static void text_draw (xcb_connection_t *c,
        +                       xcb_screen_t     *screen,
        +                       xcb_window_t      window,
        +                       int16_t           x1,
        +                       int16_t           y1,
        +                       const char       *label);
        +
        +static void
        +text_draw (xcb_connection_t *c,
        +           xcb_screen_t     *screen,
        +           xcb_window_t      window,
        +           int16_t           x1,
        +           int16_t           y1,
        +           const char       *label)
        +{
        +  xcb_void_cookie_t    cookie_gc;
        +  xcb_void_cookie_t    cookie_text;
        +  xcb_generic_error_t *error;
        +  xcb_gcontext_t       gc;
        +  uint8_t              length;
        +
        +  length = strlen (label);
        +
        +  gc = gc_font_get(c, screen, window, "7x13");
        +
        +  cookie_text = xcb_image_text_8_checked (c, length, window, gc,
        +                                          x1,
        +                                          y1, label);
        +  error = xcb_request_check (c, cookie_text);
        +  if (error) {
        +    fprintf (stderr, "ERROR: can't paste text : %d\n", error->error_code);
        +    xcb_disconnect (c);
        +    exit (-1);
        +  }
        +
        +  cookie_gc = xcb_free_gc (c, gc);
        +  error = xcb_request_check (c, cookie_gc);
        +  if (error) {
        +    fprintf (stderr, "ERROR: can't free gc : %d\n", error->error_code);
        +    xcb_disconnect (c);
        +    exit (-1);
        +  }
        +}
        +
        +static xcb_gc_t
        +gc_font_get (xcb_connection_t *c,
        +             xcb_screen_t     *screen,
        +             xcb_window_t      window,
        +             const char       *font_name)
        +{
        +  uint32_t             value_list[3];
        +  xcb_void_cookie_t    cookie_font;
        +  xcb_void_cookie_t    cookie_gc;
        +  xcb_generic_error_t *error;
        +  xcb_font_t           font;
        +  xcb_gcontext_t       gc;
        +  uint32_t             mask;
        +
        +  font = xcb_generate_id (c);
        +  cookie_font = xcb_open_font_checked (c, font,
        +                                       strlen (font_name),
        +                                       font_name);
        +
        +  error = xcb_request_check (c, cookie_font);
        +  if (error) {
        +    fprintf (stderr, "ERROR: can't open font : %d\n", error->error_code);
        +    xcb_disconnect (c);
        +    return -1;
        +  }
        +
        +  gc = xcb_generate_id (c);
        +  mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
        +  value_list[0] = screen->black_pixel;
        +  value_list[1] = screen->white_pixel;
        +  value_list[2] = font;
        +  cookie_gc = xcb_create_gc_checked (c, gc, window, mask, value_list);
        +  error = xcb_request_check (c, cookie_gc);
        +  if (error) {
        +    fprintf (stderr, "ERROR: can't create gc : %d\n", error->error_code);
        +    xcb_disconnect (c);
        +    exit (-1);
        +  }
        +
        +  cookie_font = xcb_close_font_checked (c, font);
        +  error = xcb_request_check (c, cookie_font);
        +  if (error) {
        +    fprintf (stderr, "ERROR: can't close font : %d\n", error->error_code);
        +    xcb_disconnect (c);
        +    exit (-1);
        +  }
        +
        +  return gc;
        +}
        +
        +int main ()
        +{
        +  xcb_screen_iterator_t screen_iter;
        +  xcb_connection_t     *c;
        +  const xcb_setup_t    *setup;
        +  xcb_screen_t         *screen;
        +  xcb_generic_event_t  *e;
        +  xcb_generic_error_t  *error;
        +  xcb_void_cookie_t     cookie_window;
        +  xcb_void_cookie_t     cookie_map;
        +  xcb_window_t          window;
        +  uint32_t              mask;
        +  uint32_t              values[2];
        +  int                   screen_number;
        +
        +  /* getting the connection */
        +  c = xcb_connect (NULL, &screen_number);
        +  if (!c) {
        +    fprintf (stderr, "ERROR: can't connect to an X server\n");
        +    return -1;
        +  }
        +
        +  /* getting the current screen */
        +  setup = xcb_get_setup (c);
        +
        +  screen = NULL;
        +  screen_iter = xcb_setup_roots_iterator (setup);
        +  for (; screen_iter.rem != 0; --screen_number, xcb_screen_next (&screen_iter))
        +    if (screen_number == 0)
        +      {
        +        screen = screen_iter.data;
        +        break;
        +      }
        +  if (!screen) {
        +    fprintf (stderr, "ERROR: can't get the current screen\n");
        +    xcb_disconnect (c);
        +    return -1;
        +  }
        +
        +  /* creating the window */
        +  window = xcb_generate_id (c);
        +  mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
        +  values[0] = screen->white_pixel;
        +  values[1] =
        +    XCB_EVENT_MASK_KEY_RELEASE |
        +    XCB_EVENT_MASK_BUTTON_PRESS |
        +    XCB_EVENT_MASK_EXPOSURE |
        +    XCB_EVENT_MASK_POINTER_MOTION;
        +  cookie_window = xcb_create_window_checked (c,
        +                                             screen->root_depth,
        +                                             window, screen->root,
        +                                             20, 200, WIDTH, HEIGHT,
        +                                             0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
        +                                             screen->root_visual,
        +                                             mask, values);
        +  cookie_map = xcb_map_window_checked (c, window);
        +
        +  /* error managing */
        +  error = xcb_request_check (c, cookie_window);
        +  if (error) {
        +    fprintf (stderr, "ERROR: can't create window : %d\n", error->error_code);
        +    xcb_disconnect (c);
        +    return -1;
        +  }
        +  error = xcb_request_check (c, cookie_map);
        +  if (error) {
        +    fprintf (stderr, "ERROR: can't map window : %d\n", error->error_code);
        +    xcb_disconnect (c);
        +    return -1;
        +  }
        +
        +  xcb_flush(c);
        +
        +  while (1) {
        +    e = xcb_poll_for_event(c);
        +    if (e) {
        +      switch (e->response_type & ~0x80) {
        +      case XCB_EXPOSE: {
        +        char *text;
        +
        +        text = "Press ESC key to exit...";
        +        text_draw (c, screen, window, 10, HEIGHT - 10, text);
        +        break;
        +      }
        +      case XCB_KEY_RELEASE: {
        +        xcb_key_release_event_t *ev;
        +
        +        ev = (xcb_key_release_event_t *)e;
        +
        +        switch (ev->detail) {
        +          /* ESC */
        +        case 9:
        +          free (e);
        +          xcb_disconnect (c);
        +          return 0;
        +        }
        +      }
        +      }
        +      free (e);
        +    }
        +  }
        +
        +  return 0;
        +}
        +
    2. Interacting with the window manager

      @@ -2097,9 +2387,7 @@ typedef struct { Id. Their type are xcb_atom_t:

      -typedef struct {
      -    uint32_t xid;
      -} xcb_atom_t;
      +typedef uint32_t xcb_atom_t;
       

      To change the property of a window, we use the following @@ -2142,8 +2430,8 @@ xcb_void_cookie_t xcb_change_property (xcb_connection_t *c, /* Connection

       #include <string.h>
       
      -#include <X11/XCB/xcb.h>
      -#include <X11/XCB/xcb_atom.h>
      +#include <xcb/xcb.h>
      +#include <xcb/xcb_atom.h>
       
       int
       main ()
      @@ -2163,7 +2451,7 @@ main ()
         screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
       
         /* Ask for our window's Id */
      -  win = xcb_window_new (c);
      +  win = xcb_generate_id (c);
       
         /* Create the window */
         xcb_create_window (c,                             /* Connection          */
      @@ -2659,9 +2947,7 @@ xcb_get_window_attributes_reply_t *xcb_get_window_attributes_reply (xcb_connecti
               In XCB, a color map is (as often in X) an Id:
               

      -typedef struct {
      -    uint32_t xid;
      -} xcb_colormap_t;
      +typedef uint32_t xcb_colormap_t;
       

      In order to access the screen's default color map, you just @@ -2673,7 +2959,7 @@ typedef struct {

       #include <stdio.h>
       
      -#include <X11/XCB/xcb.h>
      +#include <xcb/xcb.h>
       
       int
       main ()
      @@ -2702,7 +2988,7 @@ main ()
               map, with this function:
               

      -xcb_colormap_t xcb_colormap_new (xcb_connection_t *c);
      +xcb_colormap_t xcb_generate_id (xcb_connection_t *c);
       

      Then, we create the color map with @@ -2718,7 +3004,7 @@ xcb_void_cookie_t xcb_create_colormap (xcb_connection_t *c, /* Pointer to Here is an example of creation of a new color map:

      -#include <X11/XCB/xcb.h>
      +#include <xcb/xcb.h>
       
       int
       main ()
      @@ -2734,7 +3020,7 @@ main ()
       
         /* We create the window win here*/
       
      -  cmap = xcb_colormap_new (c);
      +  cmap = xcb_generate_id (c);
         xcb_create_colormap (c, XCB_COLORMAP_ALLOC_NONE, cmap, win, screen->root_visual);
       
         return 0;
      @@ -2763,7 +3049,7 @@ xcb_void_cookie_t xcb_free_colormap (xcb_connection_t *c,   /* The connection */
                 
                 
        -
      • xcb_colormap_new () +
      • xcb_generate_id ()
      • xcb_create_colormap ()
      @@ -2819,7 +3105,7 @@ xcb_alloc_color_reply_t *xcb_alloc_color_reply (xcb_connection_t *c,
       #include <malloc.h>
       
      -#include <X11/XCB/xcb.h>
      +#include <xcb/xcb.h>
       
       int
       main ()
      @@ -2836,7 +3122,7 @@ main ()
       
         /* We create the window win here*/
       
      -  cmap = xcb_colormap_new (c);
      +  cmap = xcb_generate_id (c);
         xcb_create_colormap (c, XCB_COLORMAP_ALLOC_NONE, cmap, win, screen->root_visual);
       
         rep = xcb_alloc_color_reply (c, xcb_alloc_color (c, cmap, 65535, 0, 0), NULL);
      @@ -2902,19 +3188,14 @@ main ()
               of X pixmap in XCB is an Id like a window:
               

      -typedef struct {
      -    uint32_t xid;
      -} xcb_pixmap_t;
      +typedef uint32_t xcb_pixmap_t;
       

      - In order to make the difference between a window and a pixmap, - XCB introduces a drawable type, which is a union + Like Xlib, there is no difference between a Drawable, a Window + or a Pixmap:

      -typedef union {
      -    xcb_window_t window;
      -    xcb_pixmap_t pixmap;
      -} xcb_drawable_t;
      +typedef uint32_t xcb_drawable_t;
       

      in order to avoid confusion between a window and a pixmap. The @@ -2946,7 +3227,7 @@ typedef union { Id to our pixmap, with this function:

      -xcb_pixmap_t xcb_pixmap_new (xcb_connection_t *c);
      +xcb_pixmap_t xcb_generate_id (xcb_connection_t *c);
       

      Then, XCB supplies the following function to create new pixmaps: @@ -3039,18 +3320,18 @@ xcb_void_cookie_t xcb_free_pixmap (xcb_connection_t *c, /* Pointer to the the function xcb_create_glyph_cursor:

      -xcb_void_cookie_t xcb_create_glyph_cursor_checked (xcb_connection_t *c,
      -                                                   xcb_cursor_t      cid,
      -                                                   xcb_font_t        source_font, /* font for the source glyph */
      -                                                   xcb_font_t        mask_font,   /* font for the mask glyph or XCB_NONE */
      -                                                   uint16_t          source_char, /* character glyph for the source */
      -                                                   uint16_t          mask_char,   /* character glyph for the mask */
      -                                                   uint16_t          fore_red,    /* red value for the foreground of the source */
      -                                                   uint16_t          fore_green,  /* green value for the foreground of the source */
      -                                                   uint16_t          fore_blue,   /* blue value for the foreground of the source */
      -                                                   uint16_t          back_red,    /* red value for the background of the source */
      -                                                   uint16_t          back_green,  /* green value for the background of the source */
      -                                                   uint16_t          back_blue)   /* blue value for the background of the source */
      +xcb_void_cookie_t xcb_create_glyph_cursor (xcb_connection_t *c,
      +                                           xcb_cursor_t      cid,
      +                                           xcb_font_t        source_font, /* font for the source glyph */
      +                                           xcb_font_t        mask_font,   /* font for the mask glyph or XCB_NONE */
      +                                           uint16_t          source_char, /* character glyph for the source */
      +                                           uint16_t          mask_char,   /* character glyph for the mask */
      +                                           uint16_t          fore_red,    /* red value for the foreground of the source */
      +                                           uint16_t          fore_green,  /* green value for the foreground of the source */
      +                                           uint16_t          fore_blue,   /* blue value for the foreground of the source */
      +                                           uint16_t          back_red,    /* red value for the background of the source */
      +                                           uint16_t          back_green,  /* green value for the background of the source */
      +                                           uint16_t          back_blue)   /* blue value for the background of the source */
       

      TODO: Describe source_char @@ -3061,7 +3342,7 @@ xcb_void_cookie_t xcb_create_glyph_cursor_checked (xcb_connection_t *c,

      So we first open that font (see Loading a Font) and create the new cursor. As for every X ressource, we have to - ask for an X id with xcb_cursor_new + ask for an X id with xcb_generate_id first:

      @@ -3070,10 +3351,10 @@ xcb_cursor_t         cursor;
       
       /* The connection is set */
       
      -font = xcb_font_new (conn);
      +font = xcb_generate_id (conn);
       xcb_open_font (conn, font, strlen ("cursor"), "cursor");
       
      -cursor = xcb_cursor_new (conn);
      +cursor = xcb_generate_id (conn);
       xcb_create_glyph_cursor (conn, cursor, font, font,
                                58, 58 + 1,
                                0, 0, 0,
      @@ -3116,7 +3397,7 @@ uint32_t value_list;
       /* The cursor is already created */
       
       mask = XCB_CWCURSOR;
      -value_list = cursor.xid;
      +value_list = cursor;
       xcb_change_window_attributes (conn, window, mask, &value_list);
       

      @@ -3124,8 +3405,391 @@ xcb_change_window_attributes (conn, window, mask, &value_list);

    3. Complete example

      - TODO: to do... + The following example displays a window with a + button. When entering the window, the window cursor is changed + to an arrow. When clicking once on the button, the cursor is + changed to a hand. When clicking again on the button, the + cursor window gets back to the arrow. The Esc key exits the + application.

      +
      +#include <stdlib.h>
      +#include <stdio.h>
      +#include <string.h>
      +
      +#include <xcb/xcb.h>
      +
      +#define WIDTH 300
      +#define HEIGHT 150
      +
      +
      +
      +static xcb_gc_t gc_font_get (xcb_connection_t *c,
      +                             xcb_screen_t     *screen,
      +                             xcb_window_t      window,
      +                             const char       *font_name);
      +
      +static void button_draw (xcb_connection_t *c,
      +                         xcb_screen_t     *screen,
      +                         xcb_window_t      window,
      +                         int16_t           x1,
      +                         int16_t           y1,
      +                         const char       *label);
      +
      +static void text_draw (xcb_connection_t *c,
      +                       xcb_screen_t     *screen,
      +                       xcb_window_t      window,
      +                       int16_t           x1,
      +                       int16_t           y1,
      +                       const char       *label);
      +
      +static void cursor_set (xcb_connection_t *c,
      +                        xcb_screen_t     *screen,
      +                        xcb_window_t      window,
      +                        int               cursor_id);
      +
      +
      +static void
      +button_draw (xcb_connection_t *c,
      +             xcb_screen_t     *screen,
      +             xcb_window_t      window,
      +             int16_t           x1,
      +             int16_t           y1,
      +             const char       *label)
      +{
      +  xcb_point_t          points[5];
      +  xcb_void_cookie_t    cookie_gc;
      +  xcb_void_cookie_t    cookie_line;
      +  xcb_void_cookie_t    cookie_text;
      +  xcb_generic_error_t *error;
      +  xcb_gcontext_t       gc;
      +  int16_t              width;
      +  int16_t              height;
      +  uint8_t              length;
      +  int16_t              inset;
      +
      +  length = strlen (label);
      +  inset = 2;
      +
      +  gc = gc_font_get(c, screen, window, "7x13");
      +
      +  width = 7 * length + 2 * (inset + 1);
      +  height = 13 + 2 * (inset + 1);
      +  points[0].x = x1;
      +  points[0].y = y1;
      +  points[1].x = x1 + width;
      +  points[1].y = y1;
      +  points[2].x = x1 + width;
      +  points[2].y = y1 - height;
      +  points[3].x = x1;
      +  points[3].y = y1 - height;
      +  points[4].x = x1;
      +  points[4].y = y1;
      +  cookie_line = xcb_poly_line_checked (c, XCB_COORD_MODE_ORIGIN,
      +                                       window, gc, 5, points);
      +
      +  error = xcb_request_check (c, cookie_line);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't draw lines : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +
      +  cookie_text = xcb_image_text_8_checked (c, length, window, gc,
      +                                          x1 + inset + 1,
      +                                          y1 - inset - 1, label);
      +  error = xcb_request_check (c, cookie_text);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't paste text : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +
      +  cookie_gc = xcb_free_gc (c, gc);
      +  error = xcb_request_check (c, cookie_gc);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't free gc : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +}
      +
      +static void
      +text_draw (xcb_connection_t *c,
      +           xcb_screen_t     *screen,
      +           xcb_window_t      window,
      +           int16_t           x1,
      +           int16_t           y1,
      +           const char       *label)
      +{
      +  xcb_void_cookie_t    cookie_gc;
      +  xcb_void_cookie_t    cookie_text;
      +  xcb_generic_error_t *error;
      +  xcb_gcontext_t       gc;
      +  uint8_t              length;
      +
      +  length = strlen (label);
      +
      +  gc = gc_font_get(c, screen, window, "7x13");
      +
      +  cookie_text = xcb_image_text_8_checked (c, length, window, gc,
      +                                          x1,
      +                                          y1, label);
      +  error = xcb_request_check (c, cookie_text);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't paste text : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +
      +  cookie_gc = xcb_free_gc (c, gc);
      +  error = xcb_request_check (c, cookie_gc);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't free gc : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +}
      +
      +static xcb_gc_t
      +gc_font_get (xcb_connection_t *c,
      +             xcb_screen_t     *screen,
      +             xcb_window_t      window,
      +             const char       *font_name)
      +{
      +  uint32_t             value_list[3];
      +  xcb_void_cookie_t    cookie_font;
      +  xcb_void_cookie_t    cookie_gc;
      +  xcb_generic_error_t *error;
      +  xcb_font_t           font;
      +  xcb_gcontext_t       gc;
      +  uint32_t             mask;
      +
      +  font = xcb_generate_id (c);
      +  cookie_font = xcb_open_font_checked (c, font,
      +                                       strlen (font_name),
      +                                       font_name);
      +
      +  error = xcb_request_check (c, cookie_font);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't open font : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    return -1;
      +  }
      +
      +  gc = xcb_generate_id (c);
      +  mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
      +  value_list[0] = screen->black_pixel;
      +  value_list[1] = screen->white_pixel;
      +  value_list[2] = font;
      +  cookie_gc = xcb_create_gc_checked (c, gc, window, mask, value_list);
      +  error = xcb_request_check (c, cookie_gc);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't create gc : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +
      +  cookie_font = xcb_close_font_checked (c, font);
      +  error = xcb_request_check (c, cookie_font);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't close font : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +
      +  return gc;
      +}
      +
      +static void
      +cursor_set (xcb_connection_t *c,
      +            xcb_screen_t     *screen,
      +            xcb_window_t      window,
      +            int               cursor_id)
      +{
      +  uint32_t             values_list[3];
      +  xcb_void_cookie_t    cookie_font;
      +  xcb_void_cookie_t    cookie_gc;
      +  xcb_generic_error_t *error;
      +  xcb_font_t           font;
      +  xcb_cursor_t         cursor;
      +  xcb_gcontext_t       gc;
      +  uint32_t             mask;
      +  uint32_t             value_list;
      +
      +  font = xcb_generate_id (c);
      +  cookie_font = xcb_open_font_checked (c, font,
      +                                       strlen ("cursor"),
      +                                       "cursor");
      +  error = xcb_request_check (c, cookie_font);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't open font : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +
      +  cursor = xcb_generate_id (c);
      +  xcb_create_glyph_cursor (c, cursor, font, font,
      +                           cursor_id, cursor_id + 1,
      +                           0, 0, 0,
      +                           0, 0, 0);
      +
      +  gc = xcb_generate_id (c);
      +  mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
      +  values_list[0] = screen->black_pixel;
      +  values_list[1] = screen->white_pixel;
      +  values_list[2] = font;
      +  cookie_gc = xcb_create_gc_checked (c, gc, window, mask, values_list);
      +  error = xcb_request_check (c, cookie_gc);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't create gc : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +
      +  mask = XCB_CW_CURSOR;
      +  value_list = cursor;
      +  xcb_change_window_attributes (c, window, mask, &value_list);
      +
      +  xcb_free_cursor (c, cursor);
      +
      +  cookie_font = xcb_close_font_checked (c, font);
      +  error = xcb_request_check (c, cookie_font);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't close font : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    exit (-1);
      +  }
      +}
      +
      +int main ()
      +{
      +  xcb_screen_iterator_t screen_iter;
      +  xcb_connection_t     *c;
      +  const xcb_setup_t    *setup;
      +  xcb_screen_t         *screen;
      +  xcb_generic_event_t  *e;
      +  xcb_generic_error_t  *error;
      +  xcb_void_cookie_t     cookie_window;
      +  xcb_void_cookie_t     cookie_map;
      +  xcb_window_t          window;
      +  uint32_t              mask;
      +  uint32_t              values[2];
      +  int                   screen_number;
      +  uint8_t               is_hand = 0;
      +
      +  /* getting the connection */
      +  c = xcb_connect (NULL, &screen_number);
      +  if (!c) {
      +    fprintf (stderr, "ERROR: can't connect to an X server\n");
      +    return -1;
      +  }
      +
      +  /* getting the current screen */
      +  setup = xcb_get_setup (c);
      +
      +  screen = NULL;
      +  screen_iter = xcb_setup_roots_iterator (setup);
      +  for (; screen_iter.rem != 0; --screen_number, xcb_screen_next (&screen_iter))
      +    if (screen_number == 0)
      +      {
      +        screen = screen_iter.data;
      +        break;
      +      }
      +  if (!screen) {
      +    fprintf (stderr, "ERROR: can't get the current screen\n");
      +    xcb_disconnect (c);
      +    return -1;
      +  }
      +
      +  /* creating the window */
      +  window = xcb_generate_id (c);
      +  mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
      +  values[0] = screen->white_pixel;
      +  values[1] =
      +    XCB_EVENT_MASK_KEY_RELEASE |
      +    XCB_EVENT_MASK_BUTTON_PRESS |
      +    XCB_EVENT_MASK_EXPOSURE |
      +    XCB_EVENT_MASK_POINTER_MOTION;
      +  cookie_window = xcb_create_window_checked (c,
      +                                             screen->root_depth,
      +                                             window, screen->root,
      +                                             20, 200, WIDTH, HEIGHT,
      +                                             0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
      +                                             screen->root_visual,
      +                                             mask, values);
      +  cookie_map = xcb_map_window_checked (c, window);
      +
      +  /* error managing */
      +  error = xcb_request_check (c, cookie_window);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't create window : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    return -1;
      +  }
      +  error = xcb_request_check (c, cookie_map);
      +  if (error) {
      +    fprintf (stderr, "ERROR: can't map window : %d\n", error->error_code);
      +    xcb_disconnect (c);
      +    return -1;
      +  }
      +
      +  cursor_set (c, screen, window, 68);
      +
      +  xcb_flush(c);
      +
      +  while (1) {
      +    e = xcb_poll_for_event(c);
      +    if (e) {
      +      switch (e->response_type & ~0x80) {
      +      case XCB_EXPOSE: {
      +        char *text;
      +
      +        text = "click here to change cursor";
      +        button_draw (c, screen, window,
      +                     (WIDTH - 7 * strlen(text)) / 2,
      +                     (HEIGHT - 16) / 2, text);
      +
      +        text = "Press ESC key to exit...";
      +        text_draw (c, screen, window, 10, HEIGHT - 10, text);
      +        break;
      +      }
      +      case XCB_BUTTON_PRESS: {
      +        xcb_button_press_event_t *ev;
      +        int                       length;
      +
      +        ev = (xcb_button_press_event_t *)e;
      +        length = strlen ("click here to change cursor");
      +
      +        if ((ev->event_x >= (WIDTH - 7 * length) / 2) &&
      +            (ev->event_x <= ((WIDTH - 7 * length) / 2 + 7 * length + 6)) &&
      +            (ev->event_y >= (HEIGHT - 16) / 2 - 19) &&
      +            (ev->event_y <= ((HEIGHT - 16) / 2)))
      +          is_hand = 1 - is_hand;
      +
      +        is_hand ? cursor_set (c, screen, window, 58) : cursor_set (c, screen, window, 68);
      +      }
      +      case XCB_KEY_RELEASE: {
      +        xcb_key_release_event_t *ev;
      +
      +        ev = (xcb_key_release_event_t *)e;
      +
      +        switch (ev->detail) {
      +          /* ESC */
      +        case 9:
      +          free (e);
      +          xcb_disconnect (c);
      +          return 0;
      +        }
      +      }
      +      }
      +      free (e);
      +    }
      +  }
      +
      +  return 0;
      +}
      +
  • Translation of basic Xlib functions and macros

    @@ -3438,8 +4102,7 @@ default_screen = screen_of_display (c, screen_default_nbr); /* default_screen contains now the default root window, or a NULL window if no screen is found */

  • RootWindow / RootWindowOfScreen -

    -

    +
     xcb_connection_t *c;
     xcb_screen_t     *screen;
    @@ -3529,7 +4192,7 @@ if (screen) {
     
         visual_iter = xcb_depth_visuals_iterator (depth_iter.data);
         for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
    -      if (screen->root_visual.id == visual_iter.data->visual_id.id) {
    +      if (screen->root_visual == visual_iter.data->visual_id) {
             visual_type = visual_iter.data;
             break;
           }
    @@ -3560,8 +4223,8 @@ if (screen) {
       uint32_t       mask;
       uint32_t       values[2];
     
    -  gc = xcb_gcontext_new (c);
    -  draw.window = screen->root;
    +  gc = xcb_generate_id (c);
    +  draw = screen->root;
       mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
       values[0] = screen->black_pixel;
       values[1] = screen->white_pixel;
    diff --git a/doc/tutorial/xcb.css b/doc/tutorial/xcb.css
    index d2ab886..e059b3b 100644
    --- a/doc/tutorial/xcb.css
    +++ b/doc/tutorial/xcb.css
    @@ -101,23 +101,23 @@ span.code
       font-family: monospace;
       font-size: 12px;
     }
    -pre.code type
    +pre.code .type
     {
       color: #44bb44;
     }
    -pre.code function
    +pre.code .function
     {
       color: #449fb7;
     }
    -pre.code include
    +pre.code .include
     {
       color: #7d93ae;
     }
    -pre.code string
    +pre.code .string
     {
       color: #ef6e4b;
     }
    -pre.code keyword
    +pre.code .keyword
     {
       color: #00bbbb;
     }
    diff --git a/src/c-client.xsl b/src/c-client.xsl
    index 5df5762..be6aa30 100644
    --- a/src/c-client.xsl
    +++ b/src/c-client.xsl
    @@ -97,31 +97,19 @@ authorization from the authors.
         
         
           xcb
    -      
    -        
    -          _randr
    -        
    -        
    -          _screensaver
    -        
    -        
    -          _xf86dri
    -        
    -        
    -          _xfixes
    -        
    -        
    -          _xvmc
    -        
    -        
    -          _
    -          
    -            
    -          
    -        
    -        
    -        
    -      
    +      
    +	_
    +	
    +	  
    +	    
    +	      
    +	    
    +	  
    +	  
    +	    
    +	  
    +	
    +      
           
             _
             
    @@ -342,6 +330,24 @@ authorization from the authors.
               
             
           
    +      /**
    +       * Delivers a request to the X server
    +       * @param c The connection
    +       * @return A cookie
    +       *
    +       * Delivers a request to the X server.
    +       * 
    +      
    +         * This form can be used only if the request will not cause
    +         * a reply to be generated. Any returned error will be
    +         * saved for handling by xcb_request_check().
    +      
    +      
    +         * This form can be used only if the request will cause
    +         * a reply to be generated. Any returned error will be
    +         * placed in the event queue.
    +      
    +       */
           
           
           
           
           
    +        /**
    +         * Return the reply
    +         * @param c      The connection
    +         * @param cookie The cookie
    +         * @param e      The xcb_generic_error_t supplied
    +         *
    +         * Returns the reply of the request asked by
    +         * 
    +         * The parameter @p e supplied to this function must be NULL if
    +         * _unchecked(). is used.
    +         * Otherwise, it stores the error if any.
    +         */
             
             
               
    @@ -924,6 +942,14 @@ authorization from the authors.
         
         
           
    +        /**
    +         * Get the next element of the iterator
    +         * @param i Pointer to a _iterator_t
    +         *
    +         * Get the next element in the iterator. The member rem is
    +         * decreased by one. The member data points to the next
    +         * element. The member index is increased by sizeof(_t)
    +         */
             
             
               
    @@ -942,6 +968,15 @@ authorization from the authors.
             
           
           
    +        /**
    +         * Return the iterator pointing to the last element
    +         * @param i An _iterator_t
    +         * @return  The iterator pointing to the last element
    +         *
    +         * Set the current element in the iterator to the last element.
    +         * The member rem is set to 0. The member data points to the
    +         * last element.
    +         */
             
             xcb_generic_iterator_t ret;
             
    @@ -1178,6 +1213,10 @@ authorization from the authors.
           
       
       
    +    
    +      
    +      
    +    
     /*****************************************************************************
      **
      ** 
    @@ -1242,6 +1281,11 @@ authorization from the authors.
         
       
     
    +  
    +    
    +
    +  
    +
       
         
         
    diff --git a/src/xcb_conn.c b/src/xcb_conn.c
    index 3b315bc..e7856c3 100644
    --- a/src/xcb_conn.c
    +++ b/src/xcb_conn.c
    @@ -62,6 +62,9 @@ static int set_fd_flags(const int fd)
     static int _xcb_xlib_init(_xcb_xlib *xlib)
     {
         xlib->lock = 0;
    +#ifndef NDEBUG
    +    xlib->sloppy_lock = (getenv("LIBXCB_ALLOW_SLOPPY_LOCK") != 0);
    +#endif
         pthread_cond_init(&xlib->cond, 0);
         return 1;
     }
    @@ -285,15 +288,33 @@ void _xcb_unlock_io(xcb_connection_t *c)
         pthread_mutex_unlock(&c->iolock);
     }
     
    +void _xcb_wait_io(xcb_connection_t *c, pthread_cond_t *cond)
    +{
    +    int xlib_locked = c->xlib.lock;
    +    if(xlib_locked)
    +    {
    +        c->xlib.lock = 0;
    +        pthread_cond_broadcast(&c->xlib.cond);
    +    }
    +    pthread_cond_wait(cond, &c->iolock);
    +    if(xlib_locked)
    +    {
    +        while(c->xlib.lock)
    +            pthread_cond_wait(&c->xlib.cond, &c->iolock);
    +        c->xlib.lock = 1;
    +        c->xlib.thread = pthread_self();
    +    }
    +}
    +
     int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count)
     {
    -    int ret;
    +    int ret, xlib_locked;
         fd_set rfds, wfds;
     
         /* If the thing I should be doing is already being done, wait for it. */
         if(count ? c->out.writing : c->in.reading)
         {
    -        pthread_cond_wait(cond, &c->iolock);
    +        _xcb_wait_io(c, cond);
             return 1;
         }
     
    @@ -308,6 +329,12 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
             ++c->out.writing;
         }
     
    +    xlib_locked = c->xlib.lock;
    +    if(xlib_locked)
    +    {
    +        c->xlib.lock = 0;
    +        pthread_cond_broadcast(&c->xlib.cond);
    +    }
         _xcb_unlock_io(c);
         do {
     	ret = select(c->fd + 1, &rfds, &wfds, 0, 0);
    @@ -318,6 +345,11 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
     	ret = 0;
         }
         _xcb_lock_io(c);
    +    if(xlib_locked)
    +    {
    +        c->xlib.lock = 1;
    +        c->xlib.thread = pthread_self();
    +    }
     
         if(ret)
         {
    diff --git a/src/xcb_in.c b/src/xcb_in.c
    index 1cb6b69..2997de4 100644
    --- a/src/xcb_in.c
    +++ b/src/xcb_in.c
    @@ -403,7 +403,8 @@ xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c)
         {
             _xcb_lock_io(c);
             /* FIXME: follow X meets Z architecture changes. */
    -        if(_xcb_in_read(c)) /* _xcb_in_read shuts down the connection on error */
    +        ret = get_event(c);
    +        if(!ret && _xcb_in_read(c)) /* _xcb_in_read shuts down the connection on error */
                 ret = get_event(c);
             _xcb_unlock_io(c);
         }
    diff --git a/src/xcb_out.c b/src/xcb_out.c
    index caf8ef5..60226e5 100644
    --- a/src/xcb_out.c
    +++ b/src/xcb_out.c
    @@ -190,7 +190,7 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
         _xcb_lock_io(c);
         /* wait for other writing threads to get out of my way. */
         while(c->out.writing)
    -        pthread_cond_wait(&c->out.cond, &c->iolock);
    +        _xcb_wait_io(c, &c->out.cond);
     
         request = ++c->out.request;
         /* send GetInputFocus (sync) when 64k-2 requests have been sent without
    @@ -297,7 +297,7 @@ int _xcb_out_flush_to(xcb_connection_t *c, unsigned int request)
             return _xcb_out_send(c, &vec_ptr, &count);
         }
         while(c->out.writing)
    -        pthread_cond_wait(&c->out.cond, &c->iolock);
    +        _xcb_wait_io(c, &c->out.cond);
         assert(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request));
         return 1;
     }
    diff --git a/src/xcb_util.c b/src/xcb_util.c
    index eeee1dd..dd2305a 100644
    --- a/src/xcb_util.c
    +++ b/src/xcb_util.c
    @@ -55,14 +55,30 @@ int xcb_popcount(uint32_t mask)
         return ((y + (y >> 3)) & 030707070707) % 077;
     }
     
    -int xcb_parse_display(const char *name, char **host, int *displayp, int *screenp)
    +static int _xcb_parse_display(const char *name, char **host, char **protocol,
    +                      int *displayp, int *screenp)
     {
         int len, display, screen;
    -    char *colon, *dot, *end;
    +    char *slash, *colon, *dot, *end;
         if(!name || !*name)
             name = getenv("DISPLAY");
         if(!name)
             return 0;
    +    slash = strrchr(name, '/');
    +    if (slash) {
    +        len = slash - name;
    +        if (protocol) {
    +            *protocol = malloc(len + 1);
    +            if(!*protocol)
    +                return 0;
    +            memcpy(*protocol, name, len);
    +            (*protocol)[len] = '\0';
    +        }
    +        name = slash + 1;
    +    } else
    +        if (protocol)
    +            *protocol = NULL;
    +
         colon = strrchr(name, ':');
         if(!colon)
             return 0;
    @@ -96,51 +112,58 @@ int xcb_parse_display(const char *name, char **host, int *displayp, int *screenp
         return 1;
     }
     
    -static int _xcb_open_tcp(char *host, const unsigned short port);
    -static int _xcb_open_unix(const char *file);
    +int xcb_parse_display(const char *name, char **host, int *displayp,
    +                             int *screenp)
    +{
    +    return _xcb_parse_display(name, host, NULL, displayp, screenp);
    +}
    +
    +static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port);
    +static int _xcb_open_unix(char *protocol, const char *file);
     #ifdef DNETCONN
    -static int _xcb_open_decnet(const char *host, const unsigned short port);
    +static int _xcb_open_decnet(const char *host, char *protocol, const unsigned short port);
     #endif
     
    -static int _xcb_open(char *host, const int display)
    +static int _xcb_open(char *host, char *protocol, const int display)
     {
         int fd;
    +    static const char base[] = "/tmp/.X11-unix/X";
    +    char file[sizeof(base) + 20];
     
         if(*host)
         {
     #ifdef DNETCONN
    -        /* DECnet displays have two colons, so xcb_parse_display will have left
    -           one at the end.  However, an IPv6 address can end with *two* colons,
    -           so only treat this as a DECnet display if host ends with exactly one
    -           colon. */
    +        /* DECnet displays have two colons, so _xcb_parse_display will have
    +           left one at the end.  However, an IPv6 address can end with *two*
    +           colons, so only treat this as a DECnet display if host ends with
    +           exactly one colon. */
             char *colon = strchr(host, ':');
             if(colon && *(colon+1) == '\0')
             {
                 *colon = '\0';
    -            fd = _xcb_open_decnet(host, display);
    +            return _xcb_open_decnet(host, protocol, display);
             }
             else
     #endif
    -        {
    -            /* display specifies TCP */
    -            unsigned short port = X_TCP_PORT + display;
    -            fd = _xcb_open_tcp(host, port);
    -        }
    -    }
    -    else
    -    {
    -        /* display specifies Unix socket */
    -        static const char base[] = "/tmp/.X11-unix/X";
    -        char file[sizeof(base) + 20];
    -        snprintf(file, sizeof(file), "%s%d", base, display);
    -        fd = _xcb_open_unix(file);
    +            if (protocol
    +                || strcmp("unix",host)) { /* follow the old unix: rule */
    +
    +                /* display specifies TCP */
    +                unsigned short port = X_TCP_PORT + display;
    +                return _xcb_open_tcp(host, protocol, port);
    +            }
         }
     
    +    /* display specifies Unix socket */
    +    snprintf(file, sizeof(file), "%s%d", base, display);
    +    return  _xcb_open_unix(protocol, file);
    +
    +
         return fd;
     }
     
     #ifdef DNETCONN
    -static int _xcb_open_decnet(const char *host, const unsigned short port)
    +static int _xcb_open_decnet(const char *host, const char *protocol, const unsigned short port)
     {
         int fd;
         struct sockaddr_dn addr;
    @@ -149,6 +172,8 @@ static int _xcb_open_decnet(const char *host, const unsigned short port)
     
         if(!nodeaddr)
             return -1;
    +    if (protocol && strcmp("dnet",protocol))
    +        return -1;
         addr.sdn_family = AF_DECnet;
     
         addr.sdn_add.a_len = nodeaddr->n_length;
    @@ -173,7 +198,7 @@ static int _xcb_open_decnet(const char *host, const unsigned short port)
     }
     #endif
     
    -static int _xcb_open_tcp(char *host, const unsigned short port)
    +static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
     {
         int fd = -1;
         struct addrinfo hints = { 0
    @@ -187,7 +212,10 @@ static int _xcb_open_tcp(char *host, const unsigned short port)
         char service[6]; /* "65535" with the trailing '\0' */
         struct addrinfo *results, *addr;
         char *bracket;
    -    
    +
    +    if (protocol && strcmp("tcp",protocol))
    +        return -1;
    +
         /* Allow IPv6 addresses enclosed in brackets. */
         if(host[0] == '[' && (bracket = strrchr(host, ']')) && bracket[1] == '\0')
         {
    @@ -213,10 +241,14 @@ static int _xcb_open_tcp(char *host, const unsigned short port)
         return fd;
     }
     
    -static int _xcb_open_unix(const char *file)
    +static int _xcb_open_unix(char *protocol, const char *file)
     {
         int fd;
         struct sockaddr_un addr = { AF_UNIX };
    +
    +    if (protocol && strcmp("unix",protocol))
    +        return -1;
    +
         strcpy(addr.sun_path, file);
     
         fd = socket(AF_UNIX, SOCK_STREAM, 0);
    @@ -231,12 +263,13 @@ xcb_connection_t *xcb_connect(const char *displayname, int *screenp)
     {
         int fd, display = 0;
         char *host;
    +    char *protocol;
         xcb_connection_t *c;
         xcb_auth_info_t auth;
     
    -    if(!xcb_parse_display(displayname, &host, &display, screenp))
    +    if(!_xcb_parse_display(displayname, &host, &protocol, &display, screenp))
             return (xcb_connection_t *) &error_connection;
    -    fd = _xcb_open(host, display);
    +    fd = _xcb_open(host, protocol, display);
         free(host);
         if(fd == -1)
             return (xcb_connection_t *) &error_connection;
    @@ -256,10 +289,11 @@ xcb_connection_t *xcb_connect_to_display_with_auth_info(const char *displayname,
     {
         int fd, display = 0;
         char *host;
    +    char *protocol;
     
    -    if(!xcb_parse_display(displayname, &host, &display, screenp))
    +    if(!_xcb_parse_display(displayname, &host, &protocol, &display, screenp))
             return (xcb_connection_t *) &error_connection;
    -    fd = _xcb_open(host, display);
    +    fd = _xcb_open(host, protocol, display);
         free(host);
         if(fd == -1)
             return (xcb_connection_t *) &error_connection;
    diff --git a/src/xcb_xlib.c b/src/xcb_xlib.c
    index 59f972c..1b573e8 100644
    --- a/src/xcb_xlib.c
    +++ b/src/xcb_xlib.c
    @@ -28,6 +28,38 @@
     
     #include 
     
    +#ifdef HAVE_BACKTRACE
    +#include 
    +#include 
    +#include 
    +#endif
    +
    +static void xcb_xlib_printbt(void)
    +{
    +#ifdef HAVE_BACKTRACE
    +	void *array[20];
    +	int size;
    +	char **strings;
    +	int i;
    +
    +	size = backtrace(array, 20);
    +	strings = backtrace_symbols(array, size);
    +
    +	fprintf(stderr, "Locking assertion failure.  Backtrace:\n");
    +
    +	for (i = 0; i < size; ++i)
    +		fprintf(stderr, "#%i %s\n", i, strings[i]);
    +
    +	free(strings);
    +#endif
    +}
    +
    +#ifndef NDEBUG
    +#define xcb_assert(c,x) do { if (!(x)) { xcb_xlib_printbt(); if (!(c)->xlib.sloppy_lock) assert(x); } } while(0)
    +#else
    +#define xcb_assert(c,x)
    +#endif
    +
     unsigned int xcb_get_request_sent(xcb_connection_t *c)
     {
         if(c->has_error)
    @@ -38,7 +70,7 @@ unsigned int xcb_get_request_sent(xcb_connection_t *c)
     void xcb_xlib_lock(xcb_connection_t *c)
     {
         _xcb_lock_io(c);
    -    assert(!c->xlib.lock);
    +    xcb_assert(c, !c->xlib.lock);
         c->xlib.lock = 1;
         c->xlib.thread = pthread_self();
         _xcb_unlock_io(c);
    @@ -47,8 +79,8 @@ void xcb_xlib_lock(xcb_connection_t *c)
     void xcb_xlib_unlock(xcb_connection_t *c)
     {
         _xcb_lock_io(c);
    -    assert(c->xlib.lock);
    -    assert(pthread_equal(c->xlib.thread, pthread_self()));
    +    xcb_assert(c, c->xlib.lock);
    +    xcb_assert(c, pthread_equal(c->xlib.thread, pthread_self()));
         c->xlib.lock = 0;
         pthread_cond_broadcast(&c->xlib.cond);
         _xcb_unlock_io(c);
    diff --git a/src/xcbint.h b/src/xcbint.h
    index a8e167c..ab0264f 100644
    --- a/src/xcbint.h
    +++ b/src/xcbint.h
    @@ -130,6 +130,7 @@ int _xcb_in_read_block(xcb_connection_t *c, void *buf, int nread);
     
     typedef struct _xcb_xlib {
         int lock;
    +    int sloppy_lock;
         pthread_t thread;
         pthread_cond_t cond;
     } _xcb_xlib;
    @@ -182,6 +183,7 @@ struct xcb_connection_t {
     };
     
     void _xcb_conn_shutdown(xcb_connection_t *c);
    +void _xcb_wait_io(xcb_connection_t *c, pthread_cond_t *cond);
     int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count);
     
     
    diff --git a/tests/check_public.c b/tests/check_public.c
    index e2ebba6..2094bfe 100644
    --- a/tests/check_public.c
    +++ b/tests/check_public.c
    @@ -3,6 +3,7 @@
     #include 
     #include "check_suites.h"
     #include "xcb.h"
    +#include "xcbext.h"
     
     /* xcb_parse_display tests {{{ */
     
    @@ -180,6 +181,28 @@ END_TEST
     
     /* }}} */
     
    +static void popcount_eq(uint32_t bits, int count)
    +{
    +	fail_unless(xcb_popcount(bits) == count, "unexpected popcount(%08x) != %d", bits, count);
    +}
    +
    +START_TEST(popcount)
    +{
    +	uint32_t mask;
    +	int count;
    +
    +	for (mask = 0xffffffff, count = 32; count >= 0; mask >>= 1, --count) {
    +		popcount_eq(mask, count);
    +	}
    +	for (mask = 0x80000000; mask; mask >>= 1) {
    +		popcount_eq(mask, 1);
    +	}
    +	for (mask = 0x80000000; mask > 1; mask >>= 1) {
    +		popcount_eq(mask | 1, 2);
    +	}
    +}
    +END_TEST
    +
     Suite *public_suite(void)
     {
     	Suite *s = suite_create("Public API");
    @@ -190,5 +213,6 @@ Suite *public_suite(void)
     	suite_add_test(s, parse_display_ipv6, "xcb_parse_display ipv6");
     	suite_add_test(s, parse_display_decnet, "xcb_parse_display decnet");
     	suite_add_test(s, parse_display_negative, "xcb_parse_display negative");
    +	suite_add_test(s, popcount, "xcb_popcount");
     	return s;
     }