summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am6
-rw-r--r--NEWS57
-rw-r--r--README9
-rw-r--r--acinclude.m47
-rwxr-xr-xautogen.sh11
-rw-r--r--configure.ac34
-rw-r--r--doc/tutorial/index.html903
-rw-r--r--doc/tutorial/xcb.css10
-rw-r--r--src/c-client.xsl94
-rw-r--r--src/xcb_conn.c36
-rw-r--r--src/xcb_in.c3
-rw-r--r--src/xcb_out.c4
-rw-r--r--src/xcb_util.c98
-rw-r--r--src/xcb_xlib.c38
-rw-r--r--src/xcbint.h2
-rw-r--r--tests/check_public.c24
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
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 <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)
========================
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 @@
<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 &lt;string.h&gt;
#include &lt;sys/time.h&gt;
-#include &lt;X11/XCB/xcb.h&gt;
+#include &lt;xcb/xcb.h&gt;
#include &lt;X11/Xlib.h&gt;
@@ -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>&lt;X11/XCB/xcb.h&gt;</string>
+#<span class="include">include</span> <span class="string">&lt;xcb/xcb.h&gt;</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 &lt;stdio.h&gt;
-#include &lt;X11/XCB/xcb.h&gt;
+#include &lt;xcb/xcb.h&gt;
int
main ()
@@ -706,7 +707,7 @@ main ()
}
printf ("\n");
- printf ("Informations of screen %ld:\n", screen-&gt;root.xid);
+ printf ("Informations of screen %ld:\n", screen-&gt;root);
printf (" width.........: %d\n", screen-&gt;width_in_pixels);
printf (" height........: %d\n", screen-&gt;height_in_pixels);
printf (" white pixel...: %ld\n", screen-&gt;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 &lt;unistd.h&gt; /* pause() */
-#include &lt;X11/XCB/xcb.h&gt;
+#include &lt;xcb/xcb.h&gt;
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-&gt;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 &lt;X11/XCB/xcb.h&gt;
+#include &lt;xcb/xcb.h&gt;
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-&gt;root;
- black = xcb_gcontext_new (c);
+ win = screen-&gt;root;
+ black = xcb_generate_id (c);
mask = XCB_GC_FOREGROUND;
value[0] = screen-&gt;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 &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
-#include &lt;X11/XCB/xcb.h&gt;
+#include &lt;xcb/xcb.h&gt;
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-&gt;root;
+ win = screen-&gt;root;
- foreground = xcb_gcontext_new (c);
+ foreground = xcb_generate_id (c);
mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
values[0] = screen-&gt;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-&gt;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-&gt;root,
+ win = xcb_generate_id (c);
+ xcb_create_window (c, depth, win, root-&gt;root,
0, 0, 150, 150, 10,
XCB_WINDOW_CLASS_INPUT_OUTPUT, root-&gt;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-&gt;root,
+ win = xcb_generate_id (c);
+ xcb_create_window (c, depth, win, root-&gt;root,
0, 0, 150, 150, 10,
XCB_WINDOW_CLASS_INPUT_OUTPUT, root-&gt;root_visual,
mask, valwin);
@@ -1894,7 +1892,7 @@ typedef xcb_key_press_event_t xcb_key_release_event_t;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
-#include &lt;X11/XCB/xcb.h&gt;
+#include &lt;xcb/xcb.h&gt;
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-&gt;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-&gt;window.xid, ev-&gt;x, ev-&gt;y, ev-&gt;width, ev-&gt;height);
+ ev-&gt;window, ev-&gt;x, ev-&gt;y, ev-&gt;width, ev-&gt;height);
break;
}
case XCB_BUTTON_PRESS: {
xcb_button_press_event_t *ev = (xcb_button_press_event_t *)e;
print_modifiers(ev-&gt;state);
- switch (ev-&gt;detail.id) {
+ switch (ev-&gt;detail) {
case 4:
printf ("Wheel Button up in window %ld, at coordinates (%d,%d)\n",
- ev-&gt;event.xid, ev-&gt;event_x, ev-&gt;event_y);
+ ev-&gt;event, ev-&gt;event_x, ev-&gt;event_y);
break;
case 5:
printf ("Wheel Button down in window %ld, at coordinates (%d,%d)\n",
- ev-&gt;event.xid, ev-&gt;event_x, ev-&gt;event_y);
+ ev-&gt;event, ev-&gt;event_x, ev-&gt;event_y);
break;
default:
printf ("Button %d pressed in window %ld, at coordinates (%d,%d)\n",
- ev-&gt;detail.id, ev-&gt;event.xid, ev-&gt;event_x, ev-&gt;event_y);
+ ev-&gt;detail, ev-&gt;event, ev-&gt;event_x, ev-&gt;event_y);
}
break;
}
@@ -1986,28 +1984,28 @@ main ()
print_modifiers(ev-&gt;state);
printf ("Button %d released in window %ld, at coordinates (%d,%d)\n",
- ev-&gt;detail.id, ev-&gt;event.xid, ev-&gt;event_x, ev-&gt;event_y);
+ ev-&gt;detail, ev-&gt;event, ev-&gt;event_x, ev-&gt;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-&gt;event.xid, ev-&gt;event_x, ev-&gt;event_y);
+ ev-&gt;event, ev-&gt;event_x, ev-&gt;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-&gt;event.xid, ev-&gt;event_x, ev-&gt;event_y);
+ ev-&gt;event, ev-&gt;event_x, ev-&gt;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-&gt;event.xid, ev-&gt;event_x, ev-&gt;event_y);
+ ev-&gt;event, ev-&gt;event_x, ev-&gt;event_y);
break;
}
case XCB_KEY_PRESS: {
@@ -2015,7 +2013,7 @@ main ()
print_modifiers(ev-&gt;state);
printf ("Key pressed in window %ld\n",
- ev-&gt;event.xid);
+ ev-&gt;event);
break;
}
case XCB_KEY_RELEASE: {
@@ -2023,7 +2021,7 @@ main ()
print_modifiers(ev-&gt;state);
printf ("Key released in window %ld\n",
- ev-&gt;event.xid);
+ ev-&gt;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 &lt;stdlib.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+
+#include &lt;xcb/xcb.h&gt;
+
+#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, &amp;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 (&amp;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 &amp; ~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 &lt;string.h&gt;
-#include &lt;X11/XCB/xcb.h&gt;
-#include &lt;X11/XCB/xcb_atom.h&gt;
+#include &lt;xcb/xcb.h&gt;
+#include &lt;xcb/xcb_atom.h&gt;
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 &lt;stdio.h&gt;
-#include &lt;X11/XCB/xcb.h&gt;
+#include &lt;xcb/xcb.h&gt;
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 &lt;X11/XCB/xcb.h&gt;
+#include &lt;xcb/xcb.h&gt;
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-&gt;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 &lt;malloc.h&gt;
-#include &lt;X11/XCB/xcb.h&gt;
+#include &lt;xcb/xcb.h&gt;
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-&gt;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, &amp;value_list);
</pre>
<p>
@@ -3124,8 +3405,391 @@ xcb_change_window_attributes (conn, window, mask, &amp;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 &lt;stdlib.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+
+#include &lt;xcb/xcb.h&gt;
+
+#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, &amp;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, &amp;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 (&amp;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 &amp; ~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 &gt;= (WIDTH - 7 * length) / 2) &amp;&amp;
+ (ev->event_x &lt;= ((WIDTH - 7 * length) / 2 + 7 * length + 6)) &amp;&amp;
+ (ev->event_y &gt;= (HEIGHT - 16) / 2 - 19) &amp;&amp;
+ (ev->event_y &lt;= ((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 (&amp;visual_iter)) {
- if (screen-&gt;root_visual.id == visual_iter.data-&gt;visual_id.id) {
+ if (screen-&gt;root_visual == visual_iter.data-&gt;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-&gt;root;
+ gc = xcb_generate_id (c);
+ draw = screen-&gt;root;
mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
values[0] = screen-&gt;black_pixel;
values[1] = screen-&gt;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;
}