diff options
-rw-r--r-- | Makefile.am | 6 | ||||
-rw-r--r-- | NEWS | 57 | ||||
-rw-r--r-- | README | 9 | ||||
-rw-r--r-- | acinclude.m4 | 7 | ||||
-rwxr-xr-x | autogen.sh | 11 | ||||
-rw-r--r-- | configure.ac | 34 | ||||
-rw-r--r-- | doc/tutorial/index.html | 903 | ||||
-rw-r--r-- | doc/tutorial/xcb.css | 10 | ||||
-rw-r--r-- | src/c-client.xsl | 94 | ||||
-rw-r--r-- | src/xcb_conn.c | 36 | ||||
-rw-r--r-- | src/xcb_in.c | 3 | ||||
-rw-r--r-- | src/xcb_out.c | 4 | ||||
-rw-r--r-- | src/xcb_util.c | 98 | ||||
-rw-r--r-- | src/xcb_xlib.c | 38 | ||||
-rw-r--r-- | src/xcbint.h | 2 | ||||
-rw-r--r-- | tests/check_public.c | 24 |
16 files changed, 1133 insertions, 203 deletions
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 @@ -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 <jamey@minilop.net>, with agreement from +Josh Triplett <josh@freedesktop.org>. + + 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:<screen> 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) ======================== @@ -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 @@ -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 @@ <li><a class="section" href="#font">Handling text and fonts</a> <ol> <li><a class="subsection" href="#fontstruct">The Font structure</a> - <li>Loading a Font - <li>Assigning a Font to a Graphic Context - <li>Drawing text in a window + <li><a class="subsection" href="#openingfont">Opening a Font</a> + <li><a class="subsection" href="#assigningfont">Assigning a Font to a Graphic Context</a> + <li><a class="subsection" href="#drawingtext">Drawing text in a drawable</a> + <li><a class="subsection" href="#fontcompleteexample">Complete example</a> </ol> <li>Windows hierarchy <ol> @@ -177,8 +178,9 @@ level GUI toolkit like 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>, or use + <a href="http://www.trolltech.com">QT</a>, + <a href="http://www.enlightenment.org">EWL</a>, + <a href="http://www.enlightenment.org">ETK</a>, or use <a href="http://cairographics.org">Cairo</a>. 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. </p> <pre class="code"> -<type>xcb_connection_t</type> *xcb_connect (<keyword>const</keyword> <type>char</type> *displayname, - <type>int</type> *screenp); +<span class="type">xcb_connection_t</span> *xcb_connect (<span class="keyword">const</span> <span class="type">char</span> *displayname, + <span class="type">int</span> *screenp); </pre> <p> 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: </p> <pre class="code"> -#<include>include</include> <string><X11/XCB/xcb.h></string> +#<span class="include">include</span> <span class="string"><xcb/xcb.h></span> -<type>int</type> -<function>main</function> () +<span class="type">int</span> +<span class="function">main</span> () { - <type>xcb_connection_t</type> *c; + <span class="type">xcb_connection_t</span> *c; /* Open the connection to the X server. Use the DISPLAY environment variable as the default display name */ c = xcb_connect (NULL, NULL); - <keyword>return</keyword> 0; + <span class="keyword">return</span> 0; } </pre> <p> To close a connection, it suffices to use: </p> <pre class="code"> -<type>void</type> xcb_disconnect (<type>xcb_connection_t</type> *c); +<span class="type">void</span> xcb_disconnect (<span class="type">xcb_connection_t</span> *c); </pre> <div class="comp"> <div class="title"> @@ -640,8 +642,7 @@ gcc -Wall prog.c -o prog `pkg-config --cflags --libs xcb` </ul> </div> </div> - <p> - </p> + <br> <li class="title"><a name="screen">Checking basic information about a connection</a> <p> 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); <pre class="code"> #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: </p> <pre class="code"> -typedef struct { - uint32_t xid; -} xcb_window_t; +typedef uint32_t xcb_window_t; </pre> <p> We first ask for a new Id for our window, with this function: </p> <pre class="code"> -xcb_window_t xcb_window_new(xcb_connection_t *c); +xcb_window_t xcb_generate_id(xcb_connection_t *c); </pre> <p> 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, <pre class="code"> #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. </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, + 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 <span class="code">xcb_create_window()</span>, which are not described yet. See the subsections @@ -862,7 +861,7 @@ int xcb_aux_sync (xcb_connection_t *c); </div> <div class="xcb"> <ul> - <li>xcb_window_new () + <li>xcb_generate_id () <li>xcb_create_window () </ul> </div> @@ -887,16 +886,14 @@ int xcb_aux_sync (xcb_connection_t *c); a Graphics Context is, as a window, characterized by an Id: </p> <pre class="code"> -typedef struct { - uint32_t xid; -} xcb_gcontext_t; +typedef uint32_t xcb_gcontext_t; </pre> <p> We first ask the X server to attribute an Id to our graphic context with this function: </p> <pre class="code"> -xcb_gcontext_t xcb_gcontext_new (xcb_connection_t *c); +xcb_gcontext_t xcb_generate_id (xcb_connection_t *c); </pre> <p> 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. </p> <pre class="code"> -#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 () </div> <div class="xcb"> <ul> - <li>xcb_gcontext_new () + <li>xcb_generate_id () <li>xcb_create_gc () </ul> </div> @@ -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 + <a href="#assigningfont">Assigning a Font to a Graphic Context</a>). + This is done by using this function: </p> <pre class="code"> 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 () <pre class="code"> 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 () <pre class="code"> 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 () <ol> <li class="subtitle"><a name="fontstruct">The Font structure</a> <p> - 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: </p> <pre class="code"> -typedef struct { - uint32_t xid; -} xcb_font_t; +typedef uint32_t xcb_font_t; </pre> <p> 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: </p> + <pre class="code"> +xcb_font_t xcb_generate_id (xcb_connection_t *c); +</pre> + <br> + <li class="subtitle"><a name="openingfont">Opening a Font</a> <p> - <b>TODO:</b> 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: </p> + <pre class="code"> +xcb_void_cookie_t xcb_open_font (xcb_connection_t *c, + xcb_font_t fid, + uint16_t name_len, + const char *name); +</pre> + <p> + The <span class="code">fid</span> parameter is the font Id + defined by <span class="code">xcb_generate_id()</span> (see + above). The <span class="code">name</span> parameter is the + name of the font you want to open. Use the command + <span class="code">xlsfonts</span> in a terminal to know which + are the fonts available on your computer. The parameter + <span class="code">name_len</span> is the length of the name + of the font (given by <span class="code">strlen()</span>). + </p> + <li class="subtitle"><a name="assigningfont">Assigning a Font to a Graphic Context</a> + <p> + 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: + </p> + <pre class="code"> + /* + * 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); +</pre> + <li class="subtitle"><a name="drawingtext">Drawing text in a drawable</a> + <p> + To draw a text in a drawable, we use the following function: + </p> + <pre class="code"> +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); +</pre> + <p> + The <span class="code">string</span> parameter is the text to + draw. The location of the drawing is given by the parameters + <span class="code">x</span> and <span class="code">y</span>. + The base line of the text is exactly the parameter + <span class="code">y</span>. + </p> + <li class="subtitle"><a name="fontcompleteexample">Complete example</a> + <p> + 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. + </p> + <pre class="code"> +#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; +} +</pre> </ol> <li class="title"><a name="wm">Interacting with the window manager</a> <p> @@ -2097,9 +2387,7 @@ typedef struct { Id. Their type are <span class="code">xcb_atom_t</span>: </p> <pre class="code"> -typedef struct { - uint32_t xid; -} xcb_atom_t; +typedef uint32_t xcb_atom_t; </pre> <p> 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 <pre class="code"> #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: </p> <pre class="code"> -typedef struct { - uint32_t xid; -} xcb_colormap_t; +typedef uint32_t xcb_colormap_t; </pre> <p> In order to access the screen's default color map, you just @@ -2673,7 +2959,7 @@ typedef struct { <pre class="code"> #include <stdio.h> -#include <X11/XCB/xcb.h> +#include <xcb/xcb.h> int main () @@ -2702,7 +2988,7 @@ main () map, with this function: </p> <pre class="code"> -xcb_colormap_t xcb_colormap_new (xcb_connection_t *c); +xcb_colormap_t xcb_generate_id (xcb_connection_t *c); </pre> <p> 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: </p> <pre class="code"> -#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 */ </div> <div class="xcb"> <ul> - <li>xcb_colormap_new () + <li>xcb_generate_id () <li>xcb_create_colormap () </ul> </div> @@ -2819,7 +3105,7 @@ xcb_alloc_color_reply_t *xcb_alloc_color_reply (xcb_connection_t *c, <pre class="code"> #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: </p> <pre class="code"> -typedef struct { - uint32_t xid; -} xcb_pixmap_t; +typedef uint32_t xcb_pixmap_t; </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> + Like Xlib, there is no difference between a Drawable, a Window + or a Pixmap: </p> <pre class="code"> -typedef union { - xcb_window_t window; - xcb_pixmap_t pixmap; -} xcb_drawable_t; +typedef uint32_t xcb_drawable_t; </pre> <p> 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: </p> <pre class="code"> -xcb_pixmap_t xcb_pixmap_new (xcb_connection_t *c); +xcb_pixmap_t xcb_generate_id (xcb_connection_t *c); </pre> <p> 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 <span class="code">xcb_create_glyph_cursor</span>: </p> <pre class="code"> -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 */ </pre> <p> <b>TODO</b>: Describe <span class="code">source_char</span> @@ -3061,7 +3342,7 @@ xcb_void_cookie_t xcb_create_glyph_cursor_checked (xcb_connection_t *c, <p> So we first open that font (see <a href="#loadfont">Loading a Font</a>) and create the new cursor. As for every X ressource, we have to - ask for an X id with <span class="code">xcb_cursor_new</span> + ask for an X id with <span class="code">xcb_generate_id</span> first: </p> <pre class="code"> @@ -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); </pre> <p> @@ -3124,8 +3405,391 @@ xcb_change_window_attributes (conn, window, mask, &value_list); </p> <li class="subtitle"><a name="mousecursorexample">Complete example</a> <p> - <b>TODO</b>: 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. </p> + <pre class="code"> +#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; +} +</pre> </ol> <li class="title"><a name="translation">Translation of basic Xlib functions and macros</a> <p> @@ -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 */ </pre> <li class="subtitle"><a name="RootWindow">RootWindow / RootWindowOfScreen</a> - <p> - </p> + <br> <pre class="code"> 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. <xsl:param name="name" /> <func:result> <xsl:text>xcb</xsl:text> - <xsl:choose> - <xsl:when test="/xcb/@extension-name = 'RandR'"> - <xsl:text>_randr</xsl:text> - </xsl:when> - <xsl:when test="/xcb/@extension-name = 'ScreenSaver'"> - <xsl:text>_screensaver</xsl:text> - </xsl:when> - <xsl:when test="/xcb/@extension-name = 'XF86Dri'"> - <xsl:text>_xf86dri</xsl:text> - </xsl:when> - <xsl:when test="/xcb/@extension-name = 'XFixes'"> - <xsl:text>_xfixes</xsl:text> - </xsl:when> - <xsl:when test="/xcb/@extension-name = 'XvMC'"> - <xsl:text>_xvmc</xsl:text> - </xsl:when> - <xsl:when test="/xcb/@extension-name"> - <xsl:text>_</xsl:text> - <xsl:call-template name="camelcase-to-underscore"> - <xsl:with-param name="camelcase" select="/xcb/@extension-name" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - </xsl:otherwise> - </xsl:choose> + <xsl:if test="/xcb/@extension-name"> + <xsl:text>_</xsl:text> + <xsl:choose> + <xsl:when test="/xcb/@extension-multiword = 'true' or /xcb/@extension-multiword = '1'"> + <xsl:call-template name="camelcase-to-underscore"> + <xsl:with-param name="camelcase" select="/xcb/@extension-name" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="translate(/xcb/@extension-name, $ucase, $lcase)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:if> <xsl:if test="$name"> <xsl:text>_</xsl:text> <xsl:call-template name="camelcase-to-underscore"> @@ -342,6 +330,24 @@ authorization from the authors. <xsl:with-param name="request" select="$req" /> </xsl:call-template> </xsl:attribute> + <doc>/**</doc> + <doc> * Delivers a request to the X server</doc> + <doc> * @param c The connection</doc> + <doc> * @return A cookie</doc> + <doc> *</doc> + <doc> * Delivers a request to the X server.</doc> + <doc> * </doc> + <xsl:if test="$checked='true' and not($req/reply)"> + <doc> * This form can be used only if the request will not cause</doc> + <doc> * a reply to be generated. Any returned error will be</doc> + <doc> * saved for handling by xcb_request_check().</doc> + </xsl:if> + <xsl:if test="$checked='false' and $req/reply"> + <doc> * This form can be used only if the request will cause</doc> + <doc> * a reply to be generated. Any returned error will be</doc> + <doc> * placed in the event queue.</doc> + </xsl:if> + <doc> */</doc> <field type="xcb_connection_t *" name="c" /> <xsl:apply-templates select="$req/*[not(self::reply)]" mode="param" /> <do-request ref="{xcb:xcb-prefix($req/@name)}_request_t" opcode="{translate(xcb:xcb-prefix($req/@name), $lcase, $ucase)}" @@ -390,6 +396,18 @@ authorization from the authors. </struct> <iterator-functions ref="{xcb:xcb-prefix(@name)}" kind="_reply" /> <function type="{xcb:xcb-prefix(@name)}_reply_t *" name="{xcb:xcb-prefix(@name)}_reply"> + <doc>/**</doc> + <doc> * Return the reply</doc> + <doc> * @param c The connection</doc> + <doc> * @param cookie The cookie</doc> + <doc> * @param e The xcb_generic_error_t supplied</doc> + <doc> *</doc> + <doc> * Returns the reply of the request asked by</doc> + <doc> * </doc> + <doc> * The parameter @p e supplied to this function must be NULL if</doc> + <doc> * <xsl:value-of select="xcb:xcb-prefix(@name)" />_unchecked(). is used.</doc> + <doc> * Otherwise, it stores the error if any.</doc> + <doc> */</doc> <field type="xcb_connection_t *" name="c" /> <field name="cookie"> <xsl:attribute name="type"> @@ -924,6 +942,14 @@ authorization from the authors. </xsl:for-each> <xsl:if test="not($kind)"> <function type="void" name="{$ref}_next"> + <doc>/**</doc> + <doc> * Get the next element of the iterator</doc> + <doc> * @param i Pointer to a <xsl:value-of select="$ref" />_iterator_t</doc> + <doc> *</doc> + <doc> * Get the next element in the iterator. The member rem is</doc> + <doc> * decreased by one. The member data points to the next</doc> + <doc> * element. The member index is increased by sizeof(<xsl:value-of select="$ref" />_t)</doc> + <doc> */</doc> <field type="{$ref}_iterator_t *" name="i" /> <xsl:choose> <xsl:when test="$struct/list[not(@fixed)]"> @@ -942,6 +968,15 @@ authorization from the authors. </xsl:choose> </function> <function type="xcb_generic_iterator_t" name="{$ref}_end"> + <doc>/**</doc> + <doc> * Return the iterator pointing to the last element</doc> + <doc> * @param i An <xsl:value-of select="$ref" />_iterator_t</doc> + <doc> * @return The iterator pointing to the last element</doc> + <doc> *</doc> + <doc> * Set the current element in the iterator to the last element.</doc> + <doc> * The member rem is set to 0. The member data points to the</doc> + <doc> * last element.</doc> + <doc> */</doc> <field type="{$ref}_iterator_t" name="i" /> <l>xcb_generic_iterator_t ret;</l> <xsl:choose> @@ -1178,6 +1213,10 @@ authorization from the authors. </xsl:call-template> </xsl:variable> <!-- Doxygen for functions in header. --> + <xsl:if test="$h"> + <xsl:apply-templates select="doc" mode="function-doc"> + </xsl:apply-templates> + </xsl:if> /***************************************************************************** ** ** <xsl:value-of select="@type" /> @@ -1242,6 +1281,11 @@ authorization from the authors. </xsl:if> </xsl:template> + <xsl:template match="doc" mode="function-doc"> + <xsl:value-of select="." /><xsl:text> +</xsl:text> + </xsl:template> + <xsl:template match="l" mode="function-body"> <xsl:param name="indent" /> <xsl:value-of select="concat($indent, .)" /><xsl:text> 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 <assert.h> +#ifdef HAVE_BACKTRACE +#include <execinfo.h> +#include <stdio.h> +#include <stdlib.h> +#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 <stdlib.h> #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; } |