XCB
- 8 min read
- 5 chapters
Related on Lably
Through Library (computing) and Python (programming language)
Overview
XCB was designed as a smaller, modernized replacement for Xlib, previously the primary C library for communicating with the X window system, coinciding with a more complete overhaul of the X implementation that took place during the early 2000s. The main goals of XCB are to:
- reduce library size and complexity
- provide direct access to the X11 protocol
The required size reduction is achieved primarily by restricting XCB's scope to handling the X protocol and omitting Xlib functionality such as its extensive utility library, much of which saw little use by applications. This results in a factor thirty reduction of the compiled library size (as of 2004). Secondary goals include making the C interface asynchronous, facilitating better multithreading and making it easier to implement extensions (via XML protocol descriptions).
The core and extension protocol descriptions are in XML, with a program written in Python creating the C bindings. (Previous versions used XSLT and M4.)
A further goal is to be able to use these protocol descriptions to create protocol documentation, more language bindings, and server-side stubs.
Massey and others have worked to prove key portions of XCB formally correct using Z notation. (Xlib has long been known to contain errors.)
Xlib compatibility
Xlib/XCB provides application binary interface compatibility with both Xlib and XCB, providing an incremental porting path. Xlib/XCB uses the protocol layer of Xlib, but replaces the Xlib transport layer with XCB, and provides access to the underlying XCB connection for direct use of XCB. Xlib/XCB allows an application to open a single connection to the X display server and use both XCB and Xlib, possibly through a mixture of libraries designed for one or the other.
Sign in to keep reading
4 more chapters are free with a Lably account.
Example
<span id="mwUg"></span><span class="c1" id="mwUw">// Simple XCB application for opening a window and drawing a box in it</span> <span class="c1" id="mwVA">// To compile it using GNU, use:</span> <span class="c1" id="mwVQ">// gcc x.c -lxcb</span> <span class="cp" id="mwVg">#include</span><span class="w" id="mwVw"> </span><span class="cpf" id="mwWA"><stdio.h></span> <span class="cp" id="mwWQ">#include</span><span class="w" id="mwWg"> </span><span class="cpf" id="mwWw"><stdlib.h></span> <span class="cp" id="mwXA">#include</span><span class="w" id="mwXQ"> </span><span class="cpf" id="mwXg"><xcb/xcb.h></span> <span class="kt" id="mwXw">int</span><span class="w" id="mwYA"> </span><span class="nf" id="mwYQ">main</span><span class="p" id="mwYg">(</span><span class="kt" id="mwYw">void</span><span class="p" id="mwZA">)</span> <span class="p" id="mwZQ">{</span> <span class="w" id="mwZg"> </span><span class="n" id="mwZw">xcb_connection_t</span><span class="w" id="mwaA"> </span><span class="o" id="mwaQ">*</span><span class="n" id="mwag">c</span><span class="p" id="mwaw">;</span> <span class="w" id="mwbA"> </span><span class="n" id="mwbQ">xcb_screen_t</span><span class="w" id="mwbg"> </span><span class="o" id="mwbw">*</span><span class="n" id="mwcA">s</span><span class="p" id="mwcQ">;</span> <span class="w" id="mwcg"> </span><span class="n" id="mwcw">xcb_window_t</span><span class="w" id="mwdA"> </span><span class="n" id="mwdQ">w</span><span class="p" id="mwdg">;</span> <span class="w" id="mwdw"> </span><span class="n" id="mweA">xcb_gcontext_t</span><span class="w" id="mweQ"> </span><span class="n" id="mweg">g</span><span class="p" id="mwew">;</span> <span class="w" id="mwfA"> </span><span class="n" id="mwfQ">xcb_generic_event_t</span><span class="w" id="mwfg"> </span><span class="o" id="mwfw">*</span><span class="n" id="mwgA">e</span><span class="p" id="mwgQ">;</span> <span class="w" id="mwgg"> </span><span class="kt" id="mwgw">uint32_t</span><span class="w" id="mwhA"> </span><span class="n" id="mwhQ">mask</span><span class="p" id="mwhg">;</span> <span class="w" id="mwhw"> </span><span class="kt" id="mwiA">uint32_t</span><span class="w" id="mwiQ"> </span><span class="n" id="mwig">values</span><span class="p" id="mwiw">[</span><span class="mi" id="mwjA">2</span><span class="p" id="mwjQ">];</span> <span class="w" id="mwjg"> </span><span class="kt" id="mwjw">int</span><span class="w" id="mwkA"> </span><span class="n" id="mwkQ">done</span><span class="w" id="mwkg"> </span><span class="o" id="mwkw">=</span><span class="w" id="mwlA"> </span><span class="mi" id="mwlQ">0</span><span class="p" id="mwlg">;</span> <span class="w" id="mwlw"> </span><span class="n" id="mwmA">xcb_rectangle_t</span><span class="w" id="mwmQ"> </span><span class="n" id="mwmg">r</span><span class="w" id="mwmw"> </span><span class="o" id="mwnA">=</span><span class="w" id="mwnQ"> </span><span class="p" id="mwng">{</span><span class="w" id="mwnw"> </span><span class="mi" id="mwoA">20</span><span class="p" id="mwoQ">,</span><span class="w" id="mwog"> </span><span class="mi" id="mwow">20</span><span class="p" id="mwpA">,</span><span class="w" id="mwpQ"> </span><span class="mi" id="mwpg">60</span><span class="p" id="mwpw">,</span><span class="w" id="mwqA"> </span><span class="mi" id="mwqQ">60</span><span class="w" id="mwqg"> </span><span class="p" id="mwqw">};</span> <span class="w" id="mwrA"> </span><span class="c1" id="mwrQ">// open connection to the server</span> <span class="w" id="mwrg"> </span><span class="n" id="mwrw">c</span><span class="w" id="mwsA"> </span><span class="o" id="mwsQ">=</span><span class="w" id="mwsg"> </span><span class="n" id="mwsw">xcb_connect</span><span class="p" id="mwtA">(</span><span class="nb" id="mwtQ">NULL</span><span class="p" id="mwtg">,</span><span class="w" id="mwtw"> </span><span class="nb" id="mwuA">NULL</span><span class="p" id="mwuQ">);</span> <span class="w" id="mwug"> </span><span class="k" id="mwuw">if</span><span class="w" id="mwvA"> </span><span class="p" id="mwvQ">(</span><span class="n" id="mwvg">xcb_connection_has_error</span><span class="p" id="mwvw">(</span><span class="n" id="mwwA">c</span><span class="p" id="mwwQ">))</span><span class="w" id="mwwg"> </span><span class="p" id="mwww">{</span> <span class="w" id="mwxA"> </span><span class="n" id="mwxQ">printf</span><span class="p" id="mwxg">(</span><span class="s" id="mwxw">"Cannot open display</span><span class="se" id="mwyA">\n</span><span class="s" id="mwyQ">"</span><span class="p" id="mwyg">);</span> <span class="w" id="mwyw"> </span><span class="n" id="mwzA">exit</span><span class="p" id="mwzQ">(</span><span class="n" id="mwzg">EXIT_FAILURE</span><span class="p" id="mwzw">);</span> <span class="w" id="mw0A"> </span><span class="p" id="mw0Q">}</span> <span class="w" id="mw0g"> </span><span class="c1" id="mw0w">// get the first screen</span> <span class="w" id="mw1A"> </span><span class="n" id="mw1Q">s</span><span class="w" id="mw1g"> </span><span class="o" id="mw1w">=</span><span class="w" id="mw2A"> </span><span class="n" id="mw2Q">xcb_setup_roots_iterator</span><span class="p" id="mw2g">(</span><span class="w" id="mw2w"> </span><span class="n" id="mw3A">xcb_get_setup</span><span class="p" id="mw3Q">(</span><span class="n" id="mw3g">c</span><span class="p" id="mw3w">)</span><span class="w" id="mw4A"> </span><span class="p" id="mw4Q">).</span><span class="n" id="mw4g">data</span><span class="p" id="mw4w">;</span> <span class="w" id="mw5A"> </span><span class="c1" id="mw5Q">// create black graphics context</span> <span class="w" id="mw5g"> </span><span class="n" id="mw5w">g</span><span class="w" id="mw6A"> </span><span class="o" id="mw6Q">=</span><span class="w" id="mw6g"> </span><span class="n" id="mw6w">xcb_generate_id</span><span class="p" id="mw7A">(</span><span class="n" id="mw7Q">c</span><span class="p" id="mw7g">);</span> <span class="w" id="mw7w"> </span><span class="n" id="mw8A">w</span><span class="w" id="mw8Q"> </span><span class="o" id="mw8g">=</span><span class="w" id="mw8w"> </span><span class="n" id="mw9A">s</span><span class="o" id="mw9Q">-></span><span class="n" id="mw9g">root</span><span class="p" id="mw9w">;</span> <span class="w" id="mw-A"> </span><span class="n" id="mw-Q">mask</span><span class="w" id="mw-g"> </span><span class="o" id="mw-w">=</span><span class="w" id="mw_A"> </span><span class="n" id="mw_Q">XCB_GC_FOREGROUND</span><span class="w" id="mw_g"> </span><span class="o" id="mw_w">|</span><span class="w" id="mwAQA"> </span><span class="n" id="mwAQE">XCB_GC_GRAPHICS_EXPOSURES</span><span class="p" id="mwAQI">;</span> <span class="w" id="mwAQM"> </span><span class="n" id="mwAQQ">values</span><span class="p" id="mwAQU">[</span><span class="mi" id="mwAQY">0</span><span class="p" id="mwAQc">]</span><span class="w" id="mwAQg"> </span><span class="o" id="mwAQk">=</span><span class="w" id="mwAQo"> </span><span class="n" id="mwAQs">s</span><span class="o" id="mwAQw">-></span><span class="n" id="mwAQ0">black_pixel</span><span class="p" id="mwAQ4">;</span> <span class="w" id="mwAQ8"> </span><span class="n" id="mwARA">values</span><span class="p" id="mwARE">[</span><span class="mi" id="mwARI">1</span><span class="p" id="mwARM">]</span><span class="w" id="mwARQ"> </span><span class="o" id="mwARU">=</span><span class="w" id="mwARY"> </span><span class="mi" id="mwARc">0</span><span class="p" id="mwARg">;</span> <span class="w" id="mwARk"> </span><span class="n" id="mwARo">xcb_create_gc</span><span class="p" id="mwARs">(</span><span class="n" id="mwARw">c</span><span class="p" id="mwAR0">,</span><span class="w" id="mwAR4"> </span><span class="n" id="mwAR8">g</span><span class="p" id="mwASA">,</span><span class="w" id="mwASE"> </span><span class="n" id="mwASI">w</span><span class="p" id="mwASM">,</span><span class="w" id="mwASQ"> </span><span class="n" id="mwASU">mask</span><span class="p" id="mwASY">,</span><span class="w" id="mwASc"> </span><span class="n" id="mwASg">values</span><span class="p" id="mwASk">);</span> <span class="w" id="mwASo"> </span><span class="c1" id="mwASs">// create window</span> <span class="w" id="mwASw"> </span><span class="n" id="mwAS0">w</span><span class="w" id="mwAS4"> </span><span class="o" id="mwAS8">=</span><span class="w" id="mwATA"> </span><span class="n" id="mwATE">xcb_generate_id</span><span class="p" id="mwATI">(</span><span class="n" id="mwATM">c</span><span class="p" id="mwATQ">);</span> <span class="w" id="mwATU"> </span><span class="n" id="mwATY">mask</span><span class="w" id="mwATc"> </span><span class="o" id="mwATg">=</span><span class="w" id="mwATk"> </span><span class="n" id="mwATo">XCB_CW_BACK_PIXEL</span><span class="w" id="mwATs"> </span><span class="o" id="mwATw">|</span><span class="w" id="mwAT0"> </span><span class="n" id="mwAT4">XCB_CW_EVENT_MASK</span><span class="p" id="mwAT8">;</span> <span class="w" id="mwAUA"> </span><span class="n" id="mwAUE">values</span><span class="p" id="mwAUI">[</span><span class="mi" id="mwAUM">0</span><span class="p" id="mwAUQ">]</span><span class="w" id="mwAUU"> </span><span class="o" id="mwAUY">=</span><span class="w" id="mwAUc"> </span><span class="n" id="mwAUg">s</span><span class="o" id="mwAUk">-></span><span class="n" id="mwAUo">white_pixel</span><span class="p" id="mwAUs">;</span> <span class="w" id="mwAUw"> </span><span class="n" id="mwAU0">values</span><span class="p" id="mwAU4">[</span><span class="mi" id="mwAU8">1</span><span class="p" id="mwAVA">]</span><span class="w" id="mwAVE"> </span><span class="o" id="mwAVI">=</span><span class="w" id="mwAVM"> </span><span class="n" id="mwAVQ">XCB_EVENT_MASK_EXPOSURE</span><span class="w" id="mwAVU"> </span><span class="o" id="mwAVY">|</span><span class="w" id="mwAVc"> </span><span class="n" id="mwAVg">XCB_EVENT_MASK_KEY_PRESS</span><span class="p" id="mwAVk">;</span> <span class="w" id="mwAVo"> </span><span class="n" id="mwAVs">xcb_create_window</span><span class="p" id="mwAVw">(</span><span class="n" id="mwAV0">c</span><span class="p" id="mwAV4">,</span><span class="w" id="mwAV8"> </span><span class="n" id="mwAWA">s</span><span class="o" id="mwAWE">-></span><span class="n" id="mwAWI">root_depth</span><span class="p" id="mwAWM">,</span><span class="w" id="mwAWQ"> </span><span class="n" id="mwAWU">w</span><span class="p" id="mwAWY">,</span><span class="w" id="mwAWc"> </span><span class="n" id="mwAWg">s</span><span class="o" id="mwAWk">-></span><span class="n" id="mwAWo">root</span><span class="p" id="mwAWs">,</span> <span class="w" id="mwAWw"> </span><span class="mi" id="mwAW0">10</span><span class="p" id="mwAW4">,</span><span class="w" id="mwAW8"> </span><span class="mi" id="mwAXA">10</span><span class="p" id="mwAXE">,</span><span class="w" id="mwAXI"> </span><span class="mi" id="mwAXM">100</span><span class="p" id="mwAXQ">,</span><span class="w" id="mwAXU"> </span><span class="mi" id="mwAXY">100</span><span class="p" id="mwAXc">,</span><span class="w" id="mwAXg"> </span><span class="mi" id="mwAXk">1</span><span class="p" id="mwAXo">,</span> <span class="w" id="mwAXs"> </span><span class="n" id="mwAXw">XCB_WINDOW_CLASS_INPUT_OUTPUT</span><span class="p" id="mwAX0">,</span><span class="w" id="mwAX4"> </span><span class="n" id="mwAX8">s</span><span class="o" id="mwAYA">-></span><span class="n" id="mwAYE">root_visual</span><span class="p" id="mwAYI">,</span> <span class="w" id="mwAYM"> </span><span class="n" id="mwAYQ">mask</span><span class="p" id="mwAYU">,</span><span class="w" id="mwAYY"> </span><span class="n" id="mwAYc">values</span><span class="p" id="mwAYg">);</span> <span class="w" id="mwAYk"> </span><span class="c1" id="mwAYo">// map (show) the window</span> <span class="w" id="mwAYs"> </span><span class="n" id="mwAYw">xcb_map_window</span><span class="p" id="mwAY0">(</span><span class="n" id="mwAY4">c</span><span class="p" id="mwAY8">,</span><span class="w" id="mwAZA"> </span><span class="n" id="mwAZE">w</span><span class="p" id="mwAZI">);</span> <span class="w" id="mwAZM"> </span><span class="n" id="mwAZQ">xcb_flush</span><span class="p" id="mwAZU">(</span><span class="n" id="mwAZY">c</span><span class="p" id="mwAZc">);</span> <span class="w" id="mwAZg"> </span><span class="c1" id="mwAZk">// event loop</span> <span class="w" id="mwAZo"> </span><span class="k" id="mwAZs">while</span><span class="w" id="mwAZw"> </span><span class="p" id="mwAZ0">(</span><span class="o" id="mwAZ4">!</span><span class="n" id="mwAZ8">done</span><span class="w" id="mwAaA"> </span><span class="o" id="mwAaE">&&</span><span class="w" id="mwAaI"> </span><span class="p" id="mwAaM">(</span><span class="n" id="mwAaQ">e</span><span class="w" id="mwAaU"> </span><span class="o" id="mwAaY">=</span><span class="w" id="mwAac"> </span><span class="n" id="mwAag">xcb_wait_for_event</span><span class="p" id="mwAak">(</span><span class="n" id="mwAao">c</span><span class="p" id="mwAas">)))</span><span class="w" id="mwAaw"> </span><span class="p" id="mwAa0">{</span> <span class="w" id="mwAa4"> </span> <span class="w" id="mwAa8"> </span><span class="k" id="mwAbA">switch</span><span class="w" id="mwAbE"> </span><span class="p" id="mwAbI">(</span><span class="n" id="mwAbM">e</span><span class="o" id="mwAbQ">-></span><span class="n" id="mwAbU">response_type</span><span class="w" id="mwAbY"> </span><span class="o" id="mwAbc">&</span><span class="w" id="mwAbg"> </span><span class="o" id="mwAbk">~</span><span class="mh" id="mwAbo">0x80</span><span class="p" id="mwAbs">)</span><span class="w" id="mwAbw"> </span><span class="p" id="mwAb0">{</span> <span class="w" id="mwAb4"> </span><span class="k" id="mwAb8">case</span><span class="w" id="mwAcA"> </span><span class="no" id="mwAcE">XCB_EXPOSE</span><span class="p" id="mwAcI">:</span><span class="w" id="mwAcM"> </span><span class="c1" id="mwAcQ">// draw or redraw the window</span> <span class="w" id="mwAcU"> </span><span class="n" id="mwAcY">xcb_poly_fill_rectangle</span><span class="p" id="mwAcc">(</span><span class="n" id="mwAcg">c</span><span class="p" id="mwAck">,</span><span class="w" id="mwAco"> </span><span class="n" id="mwAcs">w</span><span class="p" id="mwAcw">,</span><span class="w" id="mwAc0"> </span><span class="n" id="mwAc4">g</span><span class="p" id="mwAc8">,</span><span class="w" id="mwAdA"> </span><span class="mi" id="mwAdE">1</span><span class="p" id="mwAdI">,</span><span class="w" id="mwAdM"> </span><span class="o" id="mwAdQ">&</span><span class="n" id="mwAdU">r</span><span class="p" id="mwAdY">);</span> <span class="w" id="mwAdc"> </span><span class="n" id="mwAdg">xcb_flush</span><span class="p" id="mwAdk">(</span><span class="n" id="mwAdo">c</span><span class="p" id="mwAds">);</span> <span class="w" id="mwAdw"> </span><span class="k" id="mwAd0">break</span><span class="p" id="mwAd4">;</span> <span class="w" id="mwAd8"> </span><span class="k" id="mwAeA">case</span><span class="w" id="mwAeE"> </span><span class="no" id="mwAeI">XCB_KEY_PRESS</span><span class="p" id="mwAeM">:</span><span class="w" id="mwAeQ"> </span><span class="c1" id="mwAeU">// exit on key press</span> <span class="w" id="mwAeY"> </span><span class="n" id="mwAec">done</span><span class="w" id="mwAeg"> </span><span class="o" id="mwAek">=</span><span class="w" id="mwAeo"> </span><span class="mi" id="mwAes">1</span><span class="p" id="mwAew">;</span> <span class="w" id="mwAe0"> </span><span class="k" id="mwAe4">break</span><span class="p" id="mwAe8">;</span> <span class="w" id="mwAfA"> </span><span class="p" id="mwAfE">}</span> <span class="w" id="mwAfI"> </span><span class="n" id="mwAfM">free</span><span class="p" id="mwAfQ">(</span><span class="n" id="mwAfU">e</span><span class="p" id="mwAfY">);</span> <span class="w" id="mwAfc"> </span><span class="p" id="mwAfg">}</span> <span class="w" id="mwAfk"> </span><span class="c1" id="mwAfo">// close connection to server</span> <span class="w" id="mwAfs"> </span><span class="n" id="mwAfw">xcb_disconnect</span><span class="p" id="mwAf0">(</span><span class="n" id="mwAf4">c</span><span class="p" id="mwAf8">);</span> <span class="w" id="mwAgA"> </span><span class="n" id="mwAgE">exit</span><span class="p" id="mwAgI">(</span><span class="n" id="mwAgM">EXIT_SUCCESS</span><span class="p" id="mwAgQ">);</span> <span class="p" id="mwAgU">}</span>The bitwise and operation a->response_type & ~0x80 removes a bit that indicates where the event came from.
XCB has a comparable, but slightly lower-level API than Xlib, as can be seen with this example.
Protocol description
Creators of XCB have invented a specialized interface description language to model X11 protocol in language-neutral way and facilitate generation of bindings to other programming languages. libxcb itself is implemented as a code generator and a tiny C stub of utility functions.
An example:
<span id="mwAh8"></span><span class="nt" id="mwAiA"><xcb</span><span class="w" id="mwAiE"> </span><span class="na" id="mwAiI">header=</span><span class="s" id="mwAiM">"bigreq"</span><span class="w" id="mwAiQ"> </span><span class="na" id="mwAiU">extension-xname=</span><span class="s" id="mwAiY">"BIG-REQUESTS"</span> <span class="w" id="mwAic"> </span><span class="na" id="mwAig">extension-name=</span><span class="s" id="mwAik">"BigRequests"</span><span class="w" id="mwAio"> </span><span class="na" id="mwAis">extension-multiword=</span><span class="s" id="mwAiw">"true"</span> <span class="w" id="mwAi0"> </span><span class="na" id="mwAi4">major-version=</span><span class="s" id="mwAi8">"0"</span><span class="w" id="mwAjA"> </span><span class="na" id="mwAjE">minor-version=</span><span class="s" id="mwAjI">"0"</span><span class="nt" id="mwAjM">></span> <span class="w" id="mwAjQ"> </span><span class="nt" id="mwAjU"><request</span><span class="w" id="mwAjY"> </span><span class="na" id="mwAjc">name=</span><span class="s" id="mwAjg">"Enable"</span><span class="w" id="mwAjk"> </span><span class="na" id="mwAjo">opcode=</span><span class="s" id="mwAjs">"0"</span><span class="nt" id="mwAjw">></span> <span class="w" id="mwAj0"> </span><span class="nt" id="mwAj4"><reply></span> <span class="w" id="mwAj8"> </span><span class="nt" id="mwAkA"><pad</span><span class="w" id="mwAkE"> </span><span class="na" id="mwAkI">bytes=</span><span class="s" id="mwAkM">"1"</span><span class="w" id="mwAkQ"> </span><span class="nt" id="mwAkU">/></span> <span class="w" id="mwAkY"> </span><span class="nt" id="mwAkc"><field</span><span class="w" id="mwAkg"> </span><span class="na" id="mwAkk">type=</span><span class="s" id="mwAko">"CARD32"</span><span class="w" id="mwAks"> </span><span class="na" id="mwAkw">name=</span><span class="s" id="mwAk0">"maximum_request_length"</span><span class="w" id="mwAk4"> </span><span class="nt" id="mwAk8">/></span> <span class="w" id="mwAlA"> </span><span class="nt" id="mwAlE"></reply></span> <span class="w" id="mwAlI"> </span><span class="nt" id="mwAlM"></request></span> <span class="nt" id="mwAlQ"></xcb></span>
Logo
The XCB logo was produced by Gearóid Molloy, author of the web comic Neko the Kitty, and donated to the project.
Other language bindings
- XCB.pm - Perl module implementing bindings to XCB.
- xpyb - The Python binding to the X Window System using XCB. As of June 2013, it does not support Python 3. Provided by freedesktop.org.
- xcffib - Another Python binding which supports Python 2 & 3 as well as several more X extensions than xpyb.

