From: Josh Triplett Date: Sun, 19 Feb 2006 00:49:41 +0000 (-0800) Subject: Remove xcl and CVSROOT. X-Git-Tag: 1.8.1~401 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=47ceed78612d48dcda62cc2686fc527d61abe38b;p=profile%2Fivi%2Flibxcb.git Remove xcl and CVSROOT. --- 47ceed78612d48dcda62cc2686fc527d61abe38b diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..3d5e104 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,17 @@ +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +compile +config.guess +config.log +config.status +config.sub +configure +depcomp +install-sh +libtool +ltmain.sh +missing +mkinstalldirs +*.pc diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..8c328d3 --- /dev/null +++ b/COPYING @@ -0,0 +1,30 @@ +Copyright (C) 2001-2004 Bart Massey, Jamey Sharp, and Josh Triplett. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall +be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the authors +or their institutions shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this +Software without prior written authorization from the +authors. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..7ba7263 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,610 @@ +2005-12-28 Jamey Sharp + + * configure.ac: + Replace obsolete AC_OUTPUT(...) call with AC_CONFIG_FILES(...) + and the no-argument AC_OUTPUT macro. + +2005-12-24 Jamey Sharp + + * src/xcb_xlib.c, src/xcbxlib.h, src/Makefile.am: + New header and two functions specifically for Xlib's use, so + we can quit installing xcbint.h. + + * src/xcb_out.c, src/xcbint.h: + Now that Xlib uses entirely public API, force_sequence_wrap is + purely internal to xcb_out. + +2005-12-20 Jamey Sharp + + * src/xcb_util.c: + Use AF_UNIX instead of PF_UNIX, because they're interchangeable + on Linux (and 4.x BSD?) but on MacOS X the latter is not + available. Thanks to Ian Osgood for testing. + +2005-12-12 Jamey Sharp + + * src/xcb_util.c: + Rewrite XCBParseDisplay to handle all error cases correctly. + Thanks to Travis Spencer for pointing out a problem with + the previous sscanf call; turns out that sscanf won't do what + I want anyway, so this version just uses strtoul. + +2005-12-12 Jamey Sharp + + * tests/check_public.c: + Fix segfault in fail_unless calls and provide more useful error + messages. Also remove DISPLAY from the environment and test + ParseDisplay on a null pointer. + +2005-12-07 Jamey Sharp + + * src/xcb.h, src/xcb_in.c: + Use GCC attribute extension, if available, to mark some + functions deprecated; and rename XCBWaitEvent to + XCBWaitForEvent, with a deprecated backwards compatibility + function. + +2005-12-07 Jamey Sharp + + * src/xcb.h, src/xcb_conn.c, src/xcb_util.c: + Rename XCBConnect to XCBConnectToFD, and implement XCBConnect + and XCBConnectToDisplayWithAuthInfo, as specified by the XcbApi + documentation. Provide a trivial implementation of deprecated + XCBConnectBasic for backwards compatibility. Fix XCBParseDisplay + to accept a null screen pointer. + +2005-09-30 Trevor Woerner + + reviewer: Jamey Sharp + + * Makefile.am, configure.ac, src/Makefile.am, tests/Makefile.am, + src/check_all.c, src/check_public.c, src/check_suites.h: + Created a new directory called "tests" where the unit tests + will reside, separate from other files. Moved the unit + test files from the "src" directory into the new "tests" + directory. + + * configure.ac, tests/CheckLog.xsl, tests/.cvsignore, + tests/Makefile.am, tests/check_all.c: + Added an XSLT transform to post-process the XML log file which + is generated by the unit test suite into an HTML page. Added + the necessary hooks into the build system to have this + translation occur when necessary as part of the build process. + +2005-08-15 Trevor Woerner + + reviewer: Jamey Sharp + + * src/Makefile.am: + Make builds work when the source and build directories + are different. + +2005-08-03 Trevor Woerner + + reviewer: Jamey Sharp + + * configure.ac: + Allow people to not have check as long as they have at + least automake version 1.9. Older versions of automake + still work as long as check is installed or the NoCheck + instructions are followed. + +2005-07-21 Jamey Sharp + + * src/xcb_conn.c: + Fix one uninitialized memory warning from Valgrind. + More will have to wait. + +2005-07-21 Jamey Sharp + + * src/xcb_ext.c: + Fix memory leak reported by Carl Worth (thanks Carl!). + +2005-05-22 Josh Triplett + + * src/c-client.xsl: + Permit unions to have fixed-length list fields. + +2005-05-21 Josh Triplett + + * src/c-client.xsl: + In function parameters and structure fields, line up field names in + the same starting column. + +2005-05-17 Josh Triplett + + * src/c-client.xsl: + Make header files self-sufficient, by including xcb.h in the + generated headers rather than the generated sources. + + * src/xcbext.h: + Make xcbext.h self-sufficient, by including xcb.h. + +2005-05-17 Josh Triplett + + * src/c-client.xsl: + Line up function parameters with opening parenthesis. + +2005-05-17 Jamey Sharp + + * src/c-client.xsl: + Improve whitespace output on function declarations. + +2005-04-23 Jeremy Kolb + * src/c-client.xsl: + Added list support for typedefs. + GLX now compiles. + +2005-04-23 Josh Triplett + + * src/c-client.xsl: + Allow protocol descriptions to explicitly qualify types with a + namespace, which should be the value of the header attribute from + the protocol description containing the desired type. + +2005-04-10 Jamey Sharp + + * src/xcb.h, src/xcb_in.c: + New public function XCBGetRequestRead: returns the last sequence + number that the server is known to have processed. This function + enables apps to determine whether forcing a cookie is going to + block. + +2005-04-09 Jamey Sharp + + * src/xcb_ext.c: + Implement XCBPrefetchExtensionData. An extension can now be in + one of three states in a particular connection's cache: not + queried; query cookie available; and query reply available. + +2005-04-09 Jamey Sharp + + * src/xcb_ext.c, src/xcbint.h: + Assign a display-independent unique integer to each XCBExtension + structure. Use a map instead of a list for the extension cache. + Key the map on the assigned integer. + +2005-04-06 Jeremy Kolb + + * src/c-client.xsl: + Added support for c types float and double. + Needed for GLX extension. + +2005-04-02 Jamey Sharp + + * src/c-client.xsl: + Workaround for XSLT processors that can't understand attribute + values of the form '{{ "{...}" }}'. (What? That looks completely + clear to me. *grin*) + +2005-04-01 Jamey Sharp + + * src/xcb_list.c: + Make the _destroy operations no-op on null pointers. + +2005-03-31 Jamey Sharp + + * src/xcb.h, src/xcb_conn.c, src/xcb_out.c, src/xcbint.h: + Lazily check for BIG-REQUESTS support. The first call to + XCBGetMaximumRequestLength takes the two-round-trip penalty for + discovering BIG-REQUESTS support, and caches the result for + subsequent calls. Also XCBSendRequest is now careful to only ask + for the true maximum request length if the length from the + connection setup data isn't sufficient for the current request. + +2005-03-31 Jamey Sharp + + * src/xcb_in.c: + Fix X error handling to, uh, not hang. + +2005-03-30 Jamey Sharp + + * src/xcb_in.c, src/xcbint.h: + Accept zero or more replies to any request. Eliminates, for the + moment, nearly all run-time error checking regarding the number + of replies expected for a particular request. Also breaks the + unexpected reply callback, which is OK because I was going to + remove it anyway, and now I've done so. + +2005-03-30 Jamey Sharp + + * src/xcb_list.c, src/xcbint.h: + Add a map ADT implemented using the list ADT. + +2005-03-28 Vincent Torri + + * doc/tutorial/index.html, doc/tutorial/xcb.css: + Add a tutorial + +2005-03-27 Jeremy Kolb + + * src/Makefile.am: + Added xf86dri (xcb-proto/src/extensions/xf86dri.h). + Removed compilation of record as it's broken. + +2005-03-25 Jamey Sharp + + * src/xcb_in.c: + Instead of storing a pending flag per reply record, look in the + readers list to find out whether there's a reader waiting for + the reply we've just been asked to wait for. + +2005-03-25 Jamey Sharp + + * src/xcb_list.c, src/xcbint.h: + Add _xcb_queue_is_empty. + +2005-03-25 Jamey Sharp + + * src/xcb_in.c, src/xcb_list.c, src/xcbint.h: + Add a queue ADT. Currently implemented using the list ADT, but + analysis will probably suggest a better data structure. The + split is intended to help that analysis. + +2005-03-25 Jamey Sharp + + * src/xcb_in.c, src/xcb_list.c, src/xcbint.h: + Remove _xcb_list_length. (Two callers in xcb_in didn't actually + care about the returned value beyond "empty" or "non-empty", + which they can get other ways.) _xcb_in_events_length became + obsolete in the process, and I took _xcb_list_clear out of + xcbint.h while I was at it because only _xcb_list_delete calls + it these days. + +2005-03-25 Jamey Sharp + + * src/xcb.h, src/xcb_in.c: + Remove XCBEventQueueLength and XCBEventQueueClear: they're not + part of the new API, and they interfere with analysis of the + _xcb_list implementation. + +2005-03-24 Josh Triplett + + * configure.ac: + Change pdx.freedesktop.org to lists.freedesktop.org in package + email address. + +2005-03-23 Jamey Sharp + + * src/xcb_conn.c, src/xcb_in.c: + avn@daemon.hole.ru pointed out two memory leaks in XCB, which + this update fixes. I also introduced a third a couple of days + ago, which this fixes as well. + +2005-03-23 Jamey Sharp + + * src/xcb_in.c: + Quit storing an "error" flag: it's redundant with the contents + of the packet that it was stored with. + +2005-03-22 Jamey Sharp + + * src/xcb_in.c, src/xcbint.h: + My recent Xlib patch stressed XCB's pending reply queue in ways + it has never been stressed before, with thousands of entries. + Profiling revealed that wake_up_next_reader was taking most of + the cycles of my test app with its linear search of the reply + queue. So I gave it its own 'readers' queue, which can have at + most one entry per thread, and which can be no more than the + number of pending replies. In the current implementation the + readers queue uses only constant-time operations, too. + +2005-03-20 Jamey Sharp + + * src/xcb_in.c: + Wait for the last known read sequence number to pass the request + we're waiting for, instead of checking whether data has arrived + for the current request. Causes null to be returned if somebody + screwed up by expecting a reply when none can come; relied on by + new Xlib/XCB bits that intentionally and routinely screw up this + way because the API doesn't give them enough information. + + * src/xcb_list.c, src/xcbint.h: + Add _xcb_list_peek_head so Xlib doesn't have to repeatedly + remove and re-insert the item at the head of its new + pending_requests queue. Profiling showed that was a significant + performance hit for the above-mentioned patch and with this + three-line function apps are actually usable again. + +2004-11-26 Josh Triplett + + * src/c-client.xsl: + In do-request processing, use the existing num-parts variable + rather than recalculating the same expression. + +2004-11-26 Josh Triplett + + * src/c-client.xsl: + * Add a list of known core types, and don't search all the + protocol descriptions for types in that list. This + significantly shortens the processing time. + * Search for all definitions of a non-core type, not just the + first, in order to check for duplicate definitions. + * Add an error message for non-core types with no definitions + found. + +2004-11-10 Josh Triplett + + * src/c-client.xsl: + Don't create a separate local variable for exprfields, and change + an explicit xsl:for-each to an xsl:apply-templates. + +2004-11-10 Josh Triplett + + * src/c-client.xsl: + Prefix variables in request functions with "xcb_" to avoid + collisions with field names. + +2004-11-09 Josh Triplett + + * src/c-client.xsl: + * src/xcb_out.c: + * src/xcbext.h: + More API changes: Put constant request-specific data into a static + const structure in each request function. + +2004-11-09 Josh Triplett + + * src/c-client.xsl: + Add support for an tag in a function body, which indents + the s it contains. + + * debian/.cvsignore: + debian/copyright is a generated file, so add it to + debian/.cvsignore + +2004-11-08 Jamey Sharp + + * src/xcb_conn.c: + Make the __thread-based assertion a compile-time + option, defaulting to off. It breaks on many systems + and isn't critical to XCB's functionality. + +2004-11-07 Josh Triplett + + * c-client.xsl: + Update XSLT to deal with change from extension element to + extension-name and extension-xname attributes on xcb element. + +2004-11-06 Josh Triplett + + * xcb.h: + * xcb_auth.c: + * xcb_conn.c: + * xcb_ext.c: + * xcb_in.c: + * xcb_list.c: + * xcb_out.c: + * xcb_util.c: + * xcb_xid.c: + * xcbext.h: + * xcbint.h: + Include license in every file rather than referencing COPYING. + Update copyright notices to 2004. + + * COPYING: + Remove non-applicable licenses from COPYING file. + +2004-11-06 Josh Triplett + + * configure.ac: + * src/.cvsignore: + * src/Makefile.am: + * src/xcb.h: + Merged changes for XML-XCB project. + + * src/c-client.xsl: + * src/xcb.h: + Add XSLT binding generator and non-M4 version of xcb.h. + + * src/client-c.xcb: + * src/xcb.h.m4: + Remove M4 binding generator and M4 version of xcb.h. + + * debian/changelog: + * debian/control: + * debian/copyright.debian: + * debian/rules: + Updated Debian packaging. + +2004-09-30 Jamey Sharp + + * src/xcbext.h: + * src/xcb_in.c: + * src/client-c.xcb: + Renamed XCBWaitReply to XCBWaitForReply for new API. + +2004-09-30 Jamey Sharp + + * src/Makefile.am: + Fix build failure when compiling tests. + +2004-09-29 Jamey Sharp + + * src/xcb.h.m4: + * src/xcb_in.c: + Added XCBPollForEvent function from new API. + +2004-09-29 Jamey Sharp + + * src/xcb.h.m4: + * src/xcbext.h: + * src/client-c.xcb: + * src/xcb_ext.c: + Update the extension cache for its new API. The + optimizations that this API enables are not yet + implemented, but the current implementation should + at least function correctly. + +2004-09-29 Jamey Sharp + + * src/xcb_util.c: + * src/xcbext.h: + Oops, XCBPopcount was supposed to change argument + types too. + +2004-09-29 Jamey Sharp + + * src/client-c.xcb: + * src/xcb_util.c: + * src/xcbext.h: + Renamed XCBOnes to XCBPopcount as per new API spec. + +2004-09-29 Jamey Sharp + + * src/xcbext.h: + * src/xcb.h.m4: + * src/Makefile.am: + * src/client-c.xcb: + * src/xcb_in.c: + * src/xcb_out.c: + * src/xcb_util.c: + * src/xcb_xid.c: + Moved declarations that are only useful to protocol + implementations into a separate header file, + xcbext.h. + +2004-09-28 Jamey Sharp + + * src/xcbint.h: + * src/xcb_conn.c: + Add internal sanity check macros for sequence + numbers, and invoke them every time _xcb_conn_wait + is entered. + +2004-09-28 Jamey Sharp + + * src/client-c.xcb: + Allow LISTPARAMs to omit the length argument. When + generating C code, a LOCALPARAM is automatically + generated for the length if the length argument is + omitted. + +2004-08-13 Jamey Sharp + + * configure.ac: + * src/Makefile.am: + * src/.cvsignore: + * src/check_all.c: + * src/check_suites.h: + * src/check_public.c: + Add the first unit tests for XCB. This adds a build + dependency on 'check'; I hope somebody will make it + more of a build recommendation. + +2004-08-13 Jamey Sharp + + * src/xcb_conn.c: + Add a sanity check: assert() that _xcb_conn_wait + will not be re-entered within the same thread. This + turns out not to be true in some current buggy code. + Xlib re-enters from _XAsyncReplyHandler in + src/xcl/display.c; and the X Test Suite seems to + catch SIGABRT and continue running. + +2004-08-10 Jamey Sharp + + * src/xcb_out.c: + I misread the BIG-REQUESTS specification. The long + length field needs to count itself too. + +2004-07-24 Jamey Sharp + + * src/client-c.xcb: + Renamed functions that return new iterators to + *Iter, to avoid conflict with similar functions that + return arrays. + + Deprecating ARRAYFIELD in favor of LISTFIELD, which + now generates both array and iterator accessors. You + get an array accessor as long as the element type is + fixed length; you get an interator accessor as long + as the base type has an iterator. You always get a + 'Length' function. + +2004-07-24 Jamey Sharp + + * src/xcb_auth.c: + Bart cleaned up some code that I made ugly, and + I'm fixing a warning that resulted from a static + function being created but not necessarily used. + +2004-07-07 Jamey Sharp + + * src/xcb_xid.c: + OK, it might be a good idea to commit something + that compiles. I thought I'd tested this change... + +2004-07-06 Jamey Sharp + + * src/xcbint.h: + * src/xcb_xid.c: + Added support for the XC-Misc extension's ability + to request more XIDs from the server when the + client runs out of them. + +2004-07-06 Jamey Sharp + + * src/xcb.h.m4: + * src/xcb_auth.c: + * src/xcb_util.c: + Removed XCBNextNonce, and the nonce parameter of + XCBGetAuthInfo, from the API. XCB can compute + that just fine without help from the application. + +2004-07-06 Jamey Sharp + + * src/Makefile.am: + Importing part of patches, adding SYNC, by + Mikko Markus Torni . + This needed better padding computation in XCB + before it could be implemented cleanly. + +2004-07-02 Jamey Sharp + + * src/Makefile.am: + Importing part of patches, adding XC-MISC, by + Mikko Markus Torni . + +2004-07-02 Jamey Sharp + + * src/xcb.h.m4: + * src/xcb_in.c: + Remove XCBEventQueueRemove and XCBEventQueueFind. + Their existence in the API constrains the + implementation, and they're not useful for real + code, like toolkits, anyway. + +2004-07-02 Jamey Sharp + + * src/client-c.xcb: + * src/xcb.h.m4: + XCB headers are now compatible with C++ source. + +2004-07-02 Jamey Sharp + + * src/client-c.xcb: + * src/xcb.h.m4: + Keith's fix for padding didn't quite work, despite + looking quite sensible at the time. Replaced + XCB_TYPE_CEIL with XCB_TYPE_PAD and made all the + iterators, lists, and arrays count the number of + bytes from the beginning of the current request. + +2004-07-02 Jamey Sharp + + * src/xcb_out.c: + * src/xcbint.h: + Force a response from the server if we haven't seen + one in 65530 requests. If you don't do this, XCB + gets confused the next time it waits for a reply. + +2004-06-16 Keith Packard + + * src/client-c.xcb: + * src/xcb.h.m4: + Must round datatype lengths to 4-byte boundary for + NEXTFIELD and End macros. Created new XCB_TYPE_CEIL + macro for this purpose and used it in a couple of + places. It is to be hoped that this represents all + of the locations that need changing... diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..54caf7c --- /dev/null +++ b/INSTALL @@ -0,0 +1,229 @@ +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..df93163 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,6 @@ +SUBDIRS=src tests + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = xcb.pc + +EXTRA_DIST=xcb.pc.in diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..d68a142 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,3 @@ +#! /bin/sh +autoreconf -v --install || exit 1 +./configure "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..903eeed --- /dev/null +++ b/configure.ac @@ -0,0 +1,84 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT([libXCB], + 0.9, + [xcb@lists.freedesktop.org]) +AC_CONFIG_SRCDIR([xcb.pc.in]) +AM_INIT_AUTOMAKE([foreign dist-bzip2]) + +dnl This ifdef has no useful effect prior to automake 1.9, but in 1.9 +dnl it allows the user to not have check.m4 installed. +m4_ifdef([AM_PATH_CHECK],[ +AM_PATH_CHECK(0.8.2, [HAVE_CHECK=true], [HAVE_CHECK=false]) +]) +AM_CONDITIONAL(HAVE_CHECK, test x$HAVE_CHECK = xtrue) + +AC_CONFIG_HEADERS([src/config.h]) + +AC_PROG_LIBTOOL +AC_PROG_CC + +AC_PATH_PROG(XSLTPROC, xsltproc, no) +if test "$XSLTPROC" = "no"; then + AC_MSG_ERROR([XCB requires xsltproc.]) +fi + +HTML_CHECK_RESULT=false +if test x"$HAVE_CHECK" = xtrue; then + if test x"$XSLTPROC" != xno; then + HTML_CHECK_RESULT=true + fi +fi +AC_SUBST(HTML_CHECK_RESULT) + +# Checks for pkg-config packages +PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 0.9) +PKG_CHECK_MODULES(XPROTO, xproto) +PKG_CHECK_MODULES(XAU, xau) + +# Find the xcb-proto protocol descriptions +AC_MSG_CHECKING(XCBPROTO_XCBINCLUDEDIR) +XCBPROTO_XCBINCLUDEDIR=`$PKG_CONFIG --variable=xcbincludedir xcb-proto` +AC_MSG_RESULT($XCBPROTO_XCBINCLUDEDIR) +AC_SUBST(XCBPROTO_XCBINCLUDEDIR) + +AC_HEADER_STDC +AC_SEARCH_LIBS(gethostbyname, nsl) +AC_SEARCH_LIBS(connect, socket) + +xcbincludedir='${includedir}/X11/XCB' +AC_SUBST(xcbincludedir) + +AC_ARG_WITH(opt, +AC_HELP_STRING([--with-opt], [compile with reasonable optimizations]) +AC_HELP_STRING([--with-opt=FLAGS], [compile with specified FLAGS]) +AC_HELP_STRING([--with-opt=small], [compile for smallest code]) +AC_HELP_STRING([--with-opt=debug], [compile for debugging (default)]), +[ + case "$withval" in + yes) + optflags="-O3" + ;; + small) + optflags="-Os -fomit-frame-pointer -DNDEBUG" + ;; + no|debug) + optflags="-g" + ;; + *) + optflags="$withval" + ;; + esac +]) +AC_CACHE_CHECK([what compiler optimizations to apply], [optflags], [optflags="-g"]) +AC_DEFINE(_XOPEN_SOURCE, 500, [Conform to Single Unix Specification.]) +CDEBUGFLAGS="$optflags -Wall -pedantic -Wpointer-arith \ + -Wstrict-prototypes -Wmissing-declarations -Wnested-externs" +AC_SUBST(CDEBUGFLAGS) + +AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile]) +AC_CONFIG_FILES([xcb.pc]) + +AC_OUTPUT diff --git a/debian/.cvsignore b/debian/.cvsignore new file mode 100644 index 0000000..cad8b05 --- /dev/null +++ b/debian/.cvsignore @@ -0,0 +1,6 @@ +compat +copyright +fd.o-* +stamp-* +tmp +files diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..148dd94 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,41 @@ +libxcb0 (0.9-1pre2v4) unstable; urgency=low + + pre2v1: + * Split into libxcb0 and libxcb0-dev. + * Change control file for new packages. + * Add install and dirs files for new packages. + * Update Build-Depends for renaming of fd.o-xau, fd.o-xproto, and + fd.o-xcb-proto. + * Remove fd.o prefix from package name. + * Change Maintainer to xcb@lists.freedesktop.org, move myself to + Uploaders, and add Jamey Sharp to Uploaders. Update copyright.debian + accordingly. + * Add Bugs field pointing to xcb@lists.freedesktop.org. + * Update homepage URL in description and copyright.debian to + http://xcb.freedesktop.org, and put it in a Homepage: field in the + description. + + pre2v2: + * Add libxcb0-dbg package. + + pre2v3: + * New upstream snapshot. + + pre2v4: + * New upstream snapshot. + + -- Josh Triplett Tue, 17 May 2005 12:53:53 -0700 + +fd.o-xcb (0.9-1) unstable; urgency=low + + * New version using XSLT; works with XML descriptions in xcb-proto 0.9. + * Updated Debian packaging. + + -- Josh Triplett Fri, 29 Oct 2004 15:11:09 -0700 + +fd.o-xcb (0.8-1) unstable; urgency=low + + * Initial Release. + + -- Jamey Sharp Thu, 18 Mar 2004 00:09:03 -0800 + diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..33c61c0 --- /dev/null +++ b/debian/control @@ -0,0 +1,56 @@ +Source: libxcb0 +Priority: optional +Maintainer: XCB Developers +Uploaders: Jamey Sharp , Josh Triplett +Build-Depends: x-dev, libxau-dev, xcb-proto, cdbs, debhelper (>= 4.1.76), pkg-config, autoconf, automake1.9 | automaken, libtool, xsltproc, check, binutils (>= 2.12.90.0.9) +Build-Conflicts: automake1.4, automake1.5, automake1.6 +Standards-Version: 3.6.1 +Bugs: mailto:xcb@lists.freedesktop.org + +Package: libxcb0 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: X C Binding + Xlib has been the standard C binding for the X Window System protocol for + many years now. It is an excellent piece of work, but there are applications + for which it is not ideal. XCB builds on nearly two decades of experience + with X specifically and software engineering in general in an effort to + replace the aging Xlib code base. + . + This package contains the library files needed to run software using + XCB. + . + Homepage: http://xcb.freedesktop.org + +Package: libxcb0-dev +Section: libdevel +Architecture: any +Depends: libxcb0 (= ${Source-Version}), x-dev +Description: X C Binding, development files + Xlib has been the standard C binding for the X Window System protocol for + many years now. It is an excellent piece of work, but there are applications + for which it is not ideal. XCB builds on nearly two decades of experience + with X specifically and software engineering in general in an effort to + replace the aging Xlib code base. + . + This package contains the header and library files needed to build software + using XCB. + . + Homepage: http://xcb.freedesktop.org + +Package: libxcb0-dbg +Section: libdevel +Architecture: any +Depends: libxcb0 (= ${Source-Version}) +Description: X C Binding, debugging symbols + Xlib has been the standard C binding for the X Window System protocol for + many years now. It is an excellent piece of work, but there are applications + for which it is not ideal. XCB builds on nearly two decades of experience + with X specifically and software engineering in general in an effort to + replace the aging Xlib code base. + . + This package contains the debugging symbols associated with libxcb0. gdb will + automatically use these symbols when debugging libxcb0. + . + Homepage: http://xcb.freedesktop.org diff --git a/debian/copyright.debian b/debian/copyright.debian new file mode 100644 index 0000000..7cd330a --- /dev/null +++ b/debian/copyright.debian @@ -0,0 +1,12 @@ +This package was debianized by Jamey Sharp on +Thu, 18 Mar 2004 00:48:42 -0800, and later updated by Josh Triplett +. The package is co-maintained by the XCB developers +via the XCB mailing list . + +It was downloaded from http://xcb.freedesktop.org. + +Upstream Authors: Jamey Sharp + Josh Triplett + +Copyright: + diff --git a/debian/libxcb0-dev.dirs b/debian/libxcb0-dev.dirs new file mode 100644 index 0000000..4418816 --- /dev/null +++ b/debian/libxcb0-dev.dirs @@ -0,0 +1,2 @@ +usr/lib +usr/include diff --git a/debian/libxcb0-dev.install b/debian/libxcb0-dev.install new file mode 100644 index 0000000..5ab44bc --- /dev/null +++ b/debian/libxcb0-dev.install @@ -0,0 +1,5 @@ +usr/X11R6/include/X11/* +usr/lib/lib*.a +usr/lib/lib*.so +usr/lib/pkgconfig/* +usr/lib/*.la diff --git a/debian/libxcb0.dirs b/debian/libxcb0.dirs new file mode 100644 index 0000000..6845771 --- /dev/null +++ b/debian/libxcb0.dirs @@ -0,0 +1 @@ +usr/lib diff --git a/debian/libxcb0.install b/debian/libxcb0.install new file mode 100644 index 0000000..d0dbfd1 --- /dev/null +++ b/debian/libxcb0.install @@ -0,0 +1 @@ +usr/lib/lib*.so.* diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..e81cbea --- /dev/null +++ b/debian/rules @@ -0,0 +1,22 @@ +#!/usr/bin/make -f + +DEB_DH_INSTALL_SOURCEDIR=debian/tmp + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/autotools.mk + +DEB_CONFIGURE_EXTRA_FLAGS = --with-opt +DEB_CONFIGURE_INCLUDEDIR = "\$${prefix}/X11R6/include" +DEB_DH_STRIP_ARGS=--dbg-package=libxcb0 + +debian/stamp-autotools-files: + autoreconf -v --install + touch debian/stamp-autotools-files + +debian/copyright: debian/copyright.debian COPYING + cat $+ > $@ + +clean:: + -rm -f debian/copyright + +common-install-prehook-arch common-install-prehook-indep:: debian/copyright diff --git a/doc/tutorial/index.html b/doc/tutorial/index.html new file mode 100755 index 0000000..ac6e502 --- /dev/null +++ b/doc/tutorial/index.html @@ -0,0 +1,3772 @@ + + + + + + Basic Graphics Programming With The XCB Library + + + + +
+ Basic Graphics Programming With The XCB Library +
+
+
    +
  1. Introduction
  2. +
  3. The client and server model of the X window system
  4. +
  5. GUI programming: the asynchronous model
  6. +
  7. Basic XCB notions
  8. +
      +
    1. The X Connection
    2. +
    3. Requests and replies: the Xlib killers
    4. +
    5. The Graphics Context
    6. +
    7. Object handles
    8. +
    9. Memory allocation for XCB structures
    10. +
    11. Events
    12. +
    +
  9. Using XCB-based programs
  10. +
      +
    1. Installation of XCB
    2. +
    3. Compiling XCB-based programs
    4. +
    +
  11. Opening and closing the connection to an X server
  12. +
  13. Checking basic information about a connection
  14. +
  15. Creating a basic window - the "hello world" program
  16. +
  17. Drawing in a window
  18. +
      +
    1. Allocating a Graphics Context
    2. +
    3. Changing the attributes of a Graphics Context
    4. +
    5. Drawing primitives: point, line, box, circle,...
    6. +
    +
  19. X Events
  20. +
      +
    1. Registering for event types using event masks
    2. +
    3. Receiving events: writing the events loop
    4. +
    5. Expose events
    6. +
    7. Getting user input
    8. +
        +
      1. Mouse button press and release events
      2. +
      3. Mouse movement events
      4. +
      5. Mouse pointer enter and leave events
      6. +
      7. The keyboard focus
      8. +
      9. Keyboard press and release events
      10. +
      +
    9. X events: a complete example
    10. +
    +
  21. Handling text and fonts
  22. +
      +
    1. The Font structure
    2. +
    3. Loading a Font
    4. +
    5. Assigning a Font to a Graphic Context
    6. +
    7. Drawing text in a window
    8. +
    +
  23. Windows hierarchy
  24. +
      +
    1. Root, parent and child windows
    2. +
    3. Events propagation
    4. +
    +
  25. Interacting with the window manager
  26. +
      +
    1. Window properties
    2. +
    3. Setting the window name and icon name
    4. +
    5. Setting preferred window size(s)
    6. +
    7. Setting miscellaneous window manager hints
    8. +
    9. Setting an application's icon
    10. +
    +
  27. Simple window operations
  28. +
      +
    1. Mapping and un-mapping a window
    2. +
    3. Configuring a window
    4. +
    5. Moving a window around the screen
    6. +
    7. Resizing a window
    8. +
    9. Changing windows stacking order: raise and lower
    10. +
    11. Iconifying and de-iconifying a window
    12. +
    13. Getting informations about a window
    14. +
    +
  29. Using colors to paint the rainbow
  30. +
      +
    1. Color maps
    2. +
    3. Allocating and freeing Color Maps
    4. +
    5. Allocating and freeing a color entry
    6. +
    7. Drawing with a color
    8. +
    +
  31. X Bitmaps and Pixmaps
  32. +
      +
    1. What is a X Bitmap ? An X Pixmap ?
    2. +
    3. Loading a bitmap from a file
    4. +
    5. Drawing a bitmap in a window
    6. +
    7. Creating a pixmap
    8. +
    9. Drawing a pixmap in a window
    10. +
    11. Freeing a pixmap
    12. +
    +
  33. Messing with the mouse cursor
  34. +
      +
    1. Creating and destroying a mouse cursor
    2. +
    3. Setting a window's mouse cursor
    4. +
    +
  35. Translation of basic Xlib functions and macros
  36. +
      +
    1. Members of the Display structure
    2. +
        +
      1. ConnectionNumber
      2. +
      3. DefaultScreen
      4. +
      5. QLength
      6. +
      7. ScreenCount
      8. +
      9. ServerVendor
      10. +
      11. ProtocolVersion
      12. +
      13. ProtocolRevision
      14. +
      15. VendorRelease
      16. +
      17. DisplayString
      18. +
      19. BitmapUnit
      20. +
      21. BitmapBitOrder
      22. +
      23. BitmapPad
      24. +
      25. ImageByteOrder
      26. +
      +
    3. ScreenOfDisplay related functions
    4. +
        +
      1. ScreenOfDisplay
      2. +
      3. DefaultScreenOfDisplay
      4. +
      5. RootWindow / RootWindowOfScreen
      6. +
      7. DefaultRootWindow
      8. +
      9. DefaultVisual / DefaultVisualOfScreen
      10. +
      11. DefaultGC / DefaultGCOfScreen
      12. +
      13. BlackPixel / BlackPixelOfScreen
      14. +
      15. WhitePixel / WhitePixelOfScreen
      16. +
      17. DisplayWidth / WidthOfScreen
      18. +
      19. DisplayHeight / HeightOfScreen
      20. +
      21. DisplayWidthMM / WidthMMOfScreen
      22. +
      23. DisplayHeightMM / HeightMMOfScreen
      24. +
      25. DisplayPlanes / DefaultDepth / DefaultDepthOfScreen / PlanesOfScreen
      26. +
      27. DefaultColormap / DefaultColormapOfScreen
      28. +
      29. MinCmapsOfScreen
      30. +
      31. MaxCmapsOfScreen
      32. +
      33. DoesSaveUnders
      34. +
      35. DoesBackingStore
      36. +
      37. EventMaskOfScreen
      38. +
      +
    5. Miscellaneaous macros
    6. +
        +
      1. DisplayOfScreen
      2. +
      3. DisplayCells / CellsOfScreen
      4. +
      +
    +
+
+
+
    +
  1. Introduction
  2. +

    + This tutorial is based on the + Xlib Tutorial + written by Guy Keren. The + author allowed me to take some parts of his text, mainly the text which + deals with the X Windows generality. +

    +

    + This tutorial is intended to people who want to start to program + with the XCB + library. As for the Xlib + library, it is useless and a real X + programmer should use a much higher level of abstraction, such + as using Motif, + LessTiff, + GTK, + QT or + EWL. However, + we need to start somewhere. More than this, knowing how things + work down below is never a bad idea. +

    +

    + After reading this tutorial, one should be able to write very + simple graphical programs, but not programs with a descent user + interface. For such programs, one of the previously mentioned + library should be used. +

    +

    + But what is XCB ? Xlib has been + the standard C binding for the X + Window System protocol for many years now. It is an + excellent piece of work, but there are applications for which it + is not ideal, for example +

      +
    • Small platforms: Xlib is a large piece of code, and + it's difficult to make it smaller
    • +
    • Latency hiding: Xlib requests requiring a reply are + effectively synchronous: they block until the reply appears, + whether the result is needed immediately or not.
    • +
    • Direct access to the protocol: Xlib does quite a + bit of caching, layering, and similar optimizations. While this + is normally a feature, it makes it difficult to simply emit + specified X protocol requests and process specific + responses.
    • +
    • Threaded applications: While Xlib does attempt to + support multithreading, the API makes this difficult and + error-prone.
    • +
    • New extensions: The Xlib infrastructure provides + limited support for the new creation of X extension client side + code.
    • +
    +

    +

    + For these reasons, among others, XCB, an X C binding, has been + designed to solve the above problems and thus provide a base for +

      +
    • Toolkit implementation.
    • +
    • Direct protocol-level programming.
    • +
    • Lightweight emulation of commonly used portions of the + Xlib API (in progress)
    • +
    +

    +

    +
  3. The client and server model of the X window system
  4. +

    + The X Window System was developed with one major goal: + flexibility. The idea was that the way things look is one thing, + but the way things work is another matter. Thus, the lower + levels provide the tools required to draw windows, handle user + input, allow drawing graphics using colors (or black and white + screens), etc. To this point, a decision was made to separate + the system into two parts. A client that decides what to do, and + a server that actually draws on the screen and reads user input + in order to send it to the client for processing. +

    +

    + This model is the complete opposite of what is used to when + dealing with clients and servers. In our case, the user seats + near the machine controlled by the server, while the client + might be running on a remote machine. The server controls the + screens, mouse and keyboard. A client may connect to the server, + request that it draws a window (or several windows), and ask the + server to send it any input the user sends to these + windows. Thus, several clients may connect to a single X server + (one might be running an mail software, one running a WWW + browser, etc). When input is sent by the user to some window, + the server sends a message to the client controlling this window + for processing. The client decides what to do with this input, + and sends the server requests for drawing in the window. +

    +

    + The whole session is carried out using the X message + protocol. This protocol was originally carried over the TCP/IP + protocol suite, allowing the client to run on any machine + connected to the same network that the server is. Later on, the + X servers were extended to allow clients running on the local + machine with more optimized access to the server (note that an X + protocol message may be several hundreds of KB in size), such as + using shred memory, or using Unix domain sockets (a method for + creating a logical channel on a Unix system between two processors). +

    +
  5. GUI programming: the asynchronous model
  6. +

    + Unlike conventional computer programs, that carry some serial + nature, a GUI program usually uses an asynchronous programming + model, also known as "event-driven programming". This means that + that program mostly sits idle, waiting for events sent by the X + server, and then acts upon these events. An event may say "The + user pressed the 1st button mouse in spot (x,y)", or "The window + you control needs to be redrawn". In order for the program to e + responsive to the user input, as well as to refresh requests, it + needs to handle each event in a rather short period of time + (e.g. less that 200 milliseconds, as a rule of thumb). +

    +

    + This also implies that the program may not perform operations + that might take a long time while handling an event (such as + opening a network connection to some remote server, or + connecting to a database server, or even performing a long file + copy operation). Instead, it needs to perform all these + operations in an asynchronous manner. This may be done by using + various asynchronous models to perform the longish operations, + or by performing them in a different process or thread. +

    +

    + So the way a GUI program looks is something like that: +

      +
    1. Perform initialization routines.
    2. +
    3. Connect to the X server.
    4. +
    5. Perform X-related initialization.
    6. +
    7. While not finished:
    8. +
        +
      1. Receive the next event from the X server.
      2. +
      3. Handle the event, possibly sending various drawing + requests to the X server.
      4. +
      5. If the event was a quit message, exit the loop.
      6. +
      +
    9. Close down the connection to the X server.
    10. +
    11. Perform cleanup operations.
    12. +
    +

    +

    +
  7. Basic XCB notions
  8. +

    + XCB has been created to eliminate the needs of + programs to actually implement the X protocol layer. This + library gives a program a very low-level access to any X + server. Since the protocol is standardized, a client using any + implementation of XCB may talk with any X server (the same + occurs for Xlib, of course). We now give a brief description of + the basic XCB notions. They will be detailed later. +

    +
      +
    1. The X Connection
    2. +

      + The major notion of using XCB is the X Connection. This is a + structure representing the connection we have open with a + given X server. It hides a queue of messages coming from the + server, and a queue of pending requests that our client + intends to send to the server. In XCB, this structure is named + 'XCBConnection'. When we open a connection to an X server, the + library returns a pointer to such a structure. Later, we + supply this pointer to any XCB function that should send + messages to the X server or receive messages from this server. +

      +
    3. Requests and + replies: the Xlib killers
    4. +

      + To ask informations to the X server, we have to make a request + and ask for a reply. With Xlib, these two tasks are + automatically done: Xlib locks the system, sends a request, + waits for a reply from the X server and unlocks. This is + annoying, especially if one makes a lot of requests to the X + server. Indeed, Xlib has to wait for the end of a reply + before asking for the next request (because of the locks that + Xlib sends). For example, here is a time-line of N=4 + requests/replies with Xlib, with a round-trip latency + T_round_trip that is 5 times long as the time required + to write or read a request/reply (T_write/T_read): +

      +
      +  W-----RW-----RW-----RW-----R
      +
      +
        +
      • W: Writing request
      • +
      • -: Stalled, waiting for data
      • +
      • R: Reading reply
      • +
      +

      + The total time is N * (T_write + T_round_trip + T_read). +

      +

      + With XCB, we can suppress most of the round-trips as the + requests and the replies are not locked. We usually send a + request, then XCB returns to us a cookie, which is an + identifier. Then, later, we ask for a reply using this + cookie and XCB returns a + pointer to that reply. Hence, with XCB, we can send a lot of + requests, and later in the program, ask for all the replies + when we need them. Here is the time-line for 4 + requests/replies when we use this property of XCB: +

      +
      +  WWWW--RRRR
      +
      +

      + The total time is N * T_write + max (0, T_round_trip - (N-1) * + T_write) + N * T_read. Which can be considerably faster than + all those Xlib round-trips. +

      +

      + Here is a program that computes the time to create 500 atoms + with Xlib and XCB. It shows the Xlib way, the bad XCB way + (which is similar to Xlib) and the good XCB way. On my + computer, XCB is 25 times faster than Xlib. +

      +
      +#include <stdlib.h>
      +#include <stdio.h>
      +#include <string.h>
      +#include <sys/time.h>
      +
      +#include <X11/XCB/xcb.h>
      +
      +#include <X11/Xlib.h>
      +
      +double
      +get_time(void)
      +{
      +  struct timeval timev;
      +  
      +  gettimeofday(&timev, NULL);
      +
      +  return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
      +}
      +
      +int
      +main ()
      +{
      +  XCBConnection       *c;
      +  XCBATOM             *atoms;
      +  XCBInternAtomCookie *cs;
      +  char               **names;
      +  int                  count;
      +  int                  i;
      +  double               start;
      +  double               end;
      +  double               diff;
      +
      +  /* Xlib */
      +  Display *disp;
      +  Atom    *atoms_x;
      +  double   diff_x;
      +
      +  c = XCBConnectBasic ();
      +
      +  count = 500;
      +  atoms = (XCBATOM *)malloc (count * sizeof (atoms));
      +  names = (char **)malloc (count * sizeof (char *));
      +
      +  /* init names */
      +  for (i = 0; i < count; ++i)
      +    {
      +      char buf[100];
      +
      +      sprintf (buf, "NAME%d", i);
      +      names[i] = strdup (buf);
      +    }
      +
      +  /* bad use */
      +  start = get_time ();
      +
      +  for (i = 0; i < count; ++i)
      +    atoms[i] = XCBInternAtomReply (c, 
      +                                   XCBInternAtom (c,
      +                                                  0,
      +                                                  strlen(names[i]),
      +                                                  names[i]),
      +                                   NULL)->atom;
      +
      +  end = get_time ();
      +  diff = end - start;
      +  printf ("bad use time  : %f\n", diff);
      +
      +  /* good use */
      +  start = get_time ();
      +
      +  cs = (XCBInternAtomCookie *) malloc (count * sizeof(XCBInternAtomCookie));
      +  for(i = 0; i < count; ++i)
      +    cs[i] = XCBInternAtom (c, 0, strlen(names[i]), names[i]);
      +
      +  for(i = 0; i < count; ++i)
      +    {
      +      XCBInternAtomRep *r;
      +
      +      r = XCBInternAtomReply(c, cs[i], 0);
      +      if(r)
      +        atoms[i] = r->atom;
      +      free(r);
      +    }
      +
      +  end = get_time ();
      +  printf ("good use time : %f\n", end - start);
      +  printf ("ratio         : %f\n", diff / (end - start));
      +  diff = end - start;
      +
      +  /* free var */
      +  for (i = 0; i < count; ++i)
      +    {
      +      free (names[i]);
      +    }
      +  free (atoms);
      +  free (cs);
      +
      +  XCBDisconnect (c);
      +
      +  /* Xlib */
      +  disp = XOpenDisplay (getenv("DISPLAY"));
      +
      +  atoms_x = (Atom *)malloc (count * sizeof (atoms_x));
      +
      +  start = get_time ();
      +
      +  for (i = 0; i < count; ++i)
      +    atoms_x[i] = XInternAtom(disp, names[i], 0);
      +
      +  end = get_time ();
      +  diff_x = end - start;
      +  printf ("Xlib use time : %f\n", diff_x);
      +  printf ("ratio         : %f\n", diff_x / diff);
      +
      +  free (atoms_x);
      +  free (names);
      +
      +  XCloseDisplay (disp);
      +  
      +  return 1;
      +}
      +
      +
    5. The Graphic Context
    6. +

      + When we perform various drawing operations (graphics, text, + etc), we may specify various options for controlling how the + data will be drawn (what foreground and background colors to + use, how line edges will be connected, what font to use when + drawing some text, etc). In order to avoid the need to supply + hundreds of parameters to each drawing function, a graphical + context structure is used. We set the various drawing options + in this structure, and then, we pass a pointer to this + structure to any drawing routines. This is rather handy, as we + often need to perform several drawing requests with the same + options. Thus, we would initialize a graphical context, set + the desired options, and pass this structure to all drawing + functions. +

      +

      + Note that graphic contexts have no client-side structure in + XCB, they're just XIDs. Xlib has a client-side structure + because it caches the GC contents so it can avoid making + redundant requests, but of course XCB doesn't do that. +

      +
    7. Events
    8. +

      + A structure is used to pass events received from the X + server. XCB supports exactly the events specified in the + protocol (33 events). This structure contains the type + of event received, as well as the data associated with the + event (e.g. position on the screen where the event was + generated, mouse button associated with the event, region of + the screen associated with a "redraw" event, etc). The way to + read the event's data epends on the event type. +

      +
    +

    +
  9. Using XCB-based programs
  10. +

    +
      +
    1. Installation of XCB
    2. +

      + To build XCB from source, you need to have installed at + least: +

      +
        +
      • pkgconfig 0.15.0
      • +
      • automake 1.7
      • +
      • autoconf 2.50
      • +
      • check
      • +
      • xsltproc
      • +
      +

      + You have to checkout in CVS the following modules: +

      +
        +
      • Xproto from xlibs
      • +
      • Xau from xlibs
      • +
      • xcb-proto
      • +
      • xcb
      • +
      +

      + Note that Xproto and xcb-proto exist only to install header + files, so typing 'make' or 'make all' will produce the message + "Nothing to be done for 'all'". That's normal. +

      +
    3. Compiling XCB-based programs
    4. +

      + Compiling XCB-based programs requires linking them with the XCB + library. This is easily done thanks to pkgconfig: +

      +
      +gcc -Wall prog.c -o prog `pkg-config --cflags --libs xcb`
      +
      +
    +
  11. Opening and closing the connection to an X server
  12. +

    + An X program first needs to open the connection to the X + server. There is a function that opens a connection. It requires + the display name, or NULL. In the latter case, the display name + will be the one in the environment variable DISPLAY. +

    +
    +XCBConnection *XCBConnect (const char *displayname,
    +                           int        *screenp);
    +
    +

    + The second parameter returns the screen number used for the + connection. The returned structure describes an XCB connection + and is opaque. Here is how the connection can be opened: +

    +
    +#include <X11/XCB/xcb.h>
    +
    +int
    +main (int argc, char *argv[])
    +{
    +  XCBConnection *c;
    +  
    +  /* Open the connection to the X server. use the DISPLAY environment variable as the default display name */
    +  c = XCBConnect (NULL, NULL);
    +
    +  return 1;
    +}
    +
    +

    + To close a connection, it suffices to use: +

    +
    +void XCBDisconnect (XCBConnection *c);
    +
    +
    +
    + Comparison Xlib/XCB +
    +
    +
      +
    • XOpenDisplay ()
    • +
    +
    +
    +
      +
    • XCBConnect ()
    • +
    +
    +
    +
      +
    • XCloseDisplay ()
    • +
    +
    +
    +
      +
    • XCBDisconnect ()
    • +
    +
    +
    +

    +

    +
  13. Checking basic information about a connection
  14. +

    + Once we opened a connection to an X server, we should check some + basic informations about it: what screens it has, what is the + size (width and height) of the screen, how many colors it + supports (black and white ? grey scale ?, 256 colors ? more ?), + and so on. We get such informations from the XCBSCREEN + structure: +

    +
    +typedef struct {
    +    XCBWINDOW root;
    +    XCBCOLORMAP default_colormap;
    +    CARD32 white_pixel;
    +    CARD32 black_pixel;
    +    CARD32 current_input_masks;
    +    CARD16 width_in_pixels;
    +    CARD16 height_in_pixels;
    +    CARD16 width_in_millimeters;
    +    CARD16 height_in_millimeters;
    +    CARD16 min_installed_maps;
    +    CARD16 max_installed_maps;
    +    XCBVISUALID root_visual;
    +    BYTE backing_stores;
    +    BOOL save_unders;
    +    CARD8 root_depth;
    +    CARD8 allowed_depths_len;
    +} XCBSCREEN;
    +
    +

    + We could retrieve the first screen of the connection by using the + following function: +

    +
    +XCBSCREENIter XCBConnSetupSuccessRepRootsIter (XCBConnSetupSuccessRep *R);
    +
    +

    + Here is a small program that shows how to use this function: +

    +
    +#include <stdio.h>
    +
    +#include <X11/XCB/xcb.h>
    +
    +int
    +main (int argc, char *argv[])
    +{
    +  XCBConnection *c;
    +  XCBSCREEN     *screen;
    +  int            screen_nbr;
    +  XCBSCREENIter  iter;
    +  
    +  /* Open the connection to the X server. Use the DISPLAY environment variable */
    +  c = XCBConnect (NULL, &screen_nbr);
    +  
    +  /* Get the screen #screen_nbr */
    +  iter = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c));
    +  for (; iter.rem; --screen_nbr, XCBSCREENNext (&iter))
    +    if (screen_nbr == 0)
    +      {
    +        screen = iter.data;
    +        break;
    +      }
    +
    +  printf ("\n");
    +  printf ("Informations of screen %ld:\n", screen->root.xid);
    +  printf ("  width.........: %d\n", screen->width_in_pixels);
    +  printf ("  height........: %d\n", screen->height_in_pixels);
    +  printf ("  white pixel...: %ld\n", screen->white_pixel);
    +  printf ("  black pixel...: %ld\n", screen->black_pixel);
    +  printf ("\n");
    +
    +  return 1;
    +}
    +
    +
  15. Creating a basic window - the "hello world" program
  16. +

    + After we got some basic informations about our screen, we can + create our first window. In the X Window System, a window is + characterized by an Id. So, in XCB, a window is of type: +

    +
    +typedef struct {
    +    CARD32 xid;
    +} XCBWINDOW;
    +
    +

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

    +
    +XCBWINDOW XCBWINDOWNew(XCBConnection *c);
    +
    +

    + Then, XCB supplies the following function to create new windows: +

    +
    +XCBVoidCookie XCBCreateWindow (XCBConnection *c,             /* Pointer to the XCBConnection structure */
    +                               CARD8          depth,         /* Depth of the screen */
    +                               XCBWINDOW      wid,           /* Id of the window */
    +			       XCBWINDOW      parent,        /* Id of an existing window that should be the parent of the new window */
    +			       INT16          x,             /* X position of the top-left corner of the window (in pixels) */
    +			       INT16          y,             /* Y position of the top-left corner of the window (in pixels) */
    +		       	       CARD16         width,         /* Width of the window (in pixels) */
    +			       CARD16         height,        /* Height of the window (in pixels) */
    +			       CARD16         border_width,  /* Width of the window's border (in pixels) */
    +			       CARD16         _class,
    +			       XCBVISUALID    visual,
    +			       CARD32         value_mask,
    +			       const CARD32  *value_list);
    +
    +

    + The fact that we created the window does not mean that it will + be drawn on screen. By default, newly created windows are not + mapped on the screen (they are invisible). In order to make our + window visible, we use the function XCBMapWindow(), whose + prototype is +

    +
    +XCBVoidCookie XCBMapWindow (XCBConnection *c, XCBWINDOW window);
    +
    +

    + Finally, here is a small program to create a window of size + 150x150 pixels, positioned at the top-left corner of the screen: +

    +
    +#include <unistd.h>
    +
    +#include <X11/XCB/xcb.h>
    +
    +int
    +main (int argc, char *argv[])
    +{
    +  XCBConnection *c;
    +  XCBSCREEN     *screen;
    +  XCBDRAWABLE    win;
    +  
    +  /* Open the connection to the X server */
    +  c = XCBConnect (NULL, NULL);
    +  
    +  /* Get the first screen */
    +  screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data;
    +
    +  /* Ask for our window's Id */
    +  win.window = XCBWINDOWNew(c);
    +
    +  /* Create the window */
    +  XCBCreateWindow (c,                        /* Connection          */
    + 		   0,                        /* depth               */
    +		   win.window,               /* window Id           */
    +		   screen->root,             /* parent window       */
    +		   0, 0,                     /* x, y                */
    +		   150, 150,                 /* width, height       */
    +		   10,                       /* border_width        */
    +		   InputOutput,              /* class               */
    +		   screen->root_visual,      /* visual              */
    +		   0, NULL);                 /* masks, not used yet */
    +
    +  /* Map the window on the screen */
    +  XCBMapWindow (c, win.window);
    +
    +  XCBSync (c, 0);
    +  
    +  pause ();
    +
    +  return 1;
    +}
    +
    +

    + In this code, you see one more function - XCBSync(), not explained + yet. It is used to flush all the pending requests. More + precisely, there are 2 functions that do such things. The first + one is XCBFlush(): +

    +
    +int XCBFlush (XCBConnection *c);
    +
    +

    + This function flushes all pending requests to the X server (much + like the fflush() function is used to + flush standard output). The second function is + XCBSync(): +

    +
    +int XCBSync(XCBConnection *c, XCBGenericError **e);
    +
    +

    + This functions also flushes all pending requests to the X + server, and then waits until the X server finishing processing + these requests. In a normal program, this will not be necessary + (we'll see why when we get to write a normal X program), but for + now, we put it there. +

    +

    + The window that is created by the above code has a default + background (gray). This one can be set to a specific color, + thanks to the two last parameters of + XCBCreateWindow(), which are not + described yet. See the subsections + Configuring a window or + Registering for event types using event masks + for exemples on how to use these parameters. In addition, as no + events are handled, you have to make a Ctrl-C to interrupt the + program. +

    +

    + TODO: one should tell what these functions return and + about the generic error +

    +
    +
    + Comparison Xlib/XCB +
    +
    +
      +
    • XCreateWindow ()
    • +
    +
    +
    +
      +
    • XCBWINDOWNew ()
    • +
    • XCBCreateWindow ()
    • +
    +
    +
    +

    +
  17. Drawing in a window
  18. +

    + Drawing in a window can be done using various graphical + functions (drawing pixels, lines, rectangles, etc). In order to + draw in a window, we first need to define various general + drawing parameters (what line width to use, which color to draw + with, etc). This is done using a graphical context. +

    +
      +
    1. Allocating a Graphics Context
    2. +

      + As we said, a graphical context defines several attributes to + be used with the various drawing functions. For this, we + define a graphical context. We can use more than one graphical + context with a single window, in order to draw in multiple + styles (different colors, different line widths, etc). In XCB, + a Graphics Context is, as a window, characterized by an Id: +

      +
      +typedef struct {
      +    CARD32 xid;
      +} XCBGCONTEXT;
      +
      +

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

      +
      +XCBGCONTEXT XCBGCONTEXTNew (XCBConnection *c);
      +
      +

      + Then, we set the attributes of the graphic context with this function: +

      +
      +XCBVoidCookie XCBCreateGC (XCBConnection *c,
      +                           XCBGCONTEXT    cid,
      +			   XCBDRAWABLE    drawable,
      +			   CARD32         value_mask,
      +			   const CARD32  *value_list);
      +
      +

      + We give now an example on how to allocate a graphic context + that specifies that each drawing functions that use it will + draw in foreground with a black color. +

      +
      +#include <X11/XCB/xcb.h>
      +
      +int
      +main (int argc, char *argv[])
      +{
      +  XCBConnection *c;
      +  XCBSCREEN     *screen;
      +  XCBDRAWABLE    win;
      +  XCBGCONTEXT    black;
      +  CARD32         mask;
      +  CARD32         value[1];
      +  
      +  /* Open the connection to the X server and get the first screen */
      +  c = XCBConnect (NULL, NULL);
      +  screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data;
      +
      +  /* Create a black graphic context for drawing in the foreground */
      +  win.window = screen->root;
      +  black = XCBGCONTEXTNew (c);
      +  mask = GCForeground;
      +  value[0] = screen->black_pixel;
      +  XCBCreateGC (c, black, win, mask, value);
      +
      +  return 1;
      +}
      +
      +

      + Note should be taken regarding the role of "value_mask" and + "value_list" in the prototype of XCBCreateGC(). Since a + graphic context has many attributes, and since we often just + want to define a few of them, we need to be able to tell the + XCBCreateGC() which attributes we + want to set. This is what the "value_mask" parameter is + for. We then use the "value_list" parameter to specify actual + values for the attribute we defined in "value_mask". Thus, for + each constant used in "value_list", we will use the matching + constant in "value_mask". In this case, we define a graphic + context with one attribute: when drawing (a point, a line, + etc), the foreground color will be black. The rest of the + attributes of this graphic context will be set to their + default values. +

      +

      + See the next Subsection for more details. +

      +
      +
      + Comparison Xlib/XCB +
      +
      +
        +
      • XCreateGC ()
      • +
      +
      +
      +
        +
      • XCBGCONTEXTNew ()
      • +
      • XCBCreateGC ()
      • +
      +
      +
      +

      +
    3. Changing the attributes of a Graphics Context
    4. +

      + Once we have allocated a Graphic Context, we may need to + change its attributes (for example, changing the foreground + color we use to draw a line, or changing the attributes of the + font we use to display strings. See Subsections Drawing with a + color and Assigning a Font to a Graphic Context). This is done + by using this function: +

      +
      +XCBVoidCookie XCBChangeGC (XCBConnection *c,           /* The XCB Connection */
      +                           XCBGCONTEXT    gc,          /* The Graphic Context */
      +			   CARD32         value_mask,  /* Components of the Graphic Context that have to be set */
      +			   const CARD32  *value_list); /* Value as specified by value_mask */
      +
      +

      + The value_mask parameter could take + these values: +

      +
        +
      • GCFunction
      • +
      • GCPlaneMask
      • +
      • GCForeground
      • +
      • GCBackground
      • +
      • GCLineWidth
      • +
      • GCLineStyle
      • +
      • GCCapStyle
      • +
      • GCJoinStyle
      • +
      • GCFillStyle
      • +
      • GCFillRule
      • +
      • GCTile
      • +
      • GCStipple
      • +
      • GCTileStipXOrigin
      • +
      • GCTileStipYOrigin
      • +
      • GCFont
      • +
      • GCSubwindowMode
      • +
      • GCGraphicsExposures
      • +
      • GCClipXOrigin
      • +
      • GCClipYOrigin
      • +
      • GCClipMask
      • +
      • GCDashOffset
      • +
      • GCDashList
      • +
      • GCArcMode
      • +
      +

      + It is possible to set several attributes at the same + time (for example setting the attributes of a font and the + color which will be used to display a string), by OR'ing these + values in value_mask. Then + value_list has to be an array which + lists the value for the respective attributes. See Subsection + Drawing with a color to have an example. +

      +

      + TODO: set the links of the 3 subsections, once they will + be written :) +

      +

      + TODO: give an example which sets several attributes. +

      +
    5. Drawing primitives: point, line, box, circle,...
    6. +

      + After we have created a Graphic Context, we can draw on a + window using this Graphic Context, with a set of XCB + functions, collectively called "drawing primitive". Let see + how they are used. +

      +

      + To draw a point, or several points, we use +

      +
      +XCBVoidCookie XCBPolyPoint (XCBConnection  *c,               /* The connection to the X server */
      +                            BYTE            coordinate_mode, /* Coordinate mode, usually set to CoordModeOrigin */
      +			    XCBDRAWABLE     drawable,        /* The drawable on which we want to draw the point(s) */
      +			    XCBGCONTEXT     gc,              /* The Graphic Context we use to draw the point(s) */
      +			    CARD32          points_len,      /* The number of points */
      +			    const XCBPOINT *points);         /* An array of points */
      +
      +

      + The coordinate_mode parameter + specifies the coordinate mode. Available values are +

      +
        +
      • CoordModeOrigin
      • +
      • CoordModePrevious
      • +
      +

      + The XCBPOINT type is just a + structure with two fields (the coordinates of the point): +

      +
      +typedef struct {
      +    INT16 x;
      +    INT16 y;
      +} XCBPOINT;
      +
      +

      + You could see an example in xpoints.c. TODO Set the link. +

      +

      + To draw a line, or a polygonal line, we use +

      +
      +XCBVoidCookie XCBPolyLine (XCBConnection  *c,               /* The connection to the X server */
      +                           BYTE            coordinate_mode, /* Coordinate mode, usually set to CoordModeOrigin */
      +			   XCBDRAWABLE     drawable,        /* The drawable on which we want to draw the line(s) */
      +			   XCBGCONTEXT     gc,              /* The Graphic Context we use to draw the line(s) */
      +			   CARD32          points_len,      /* The number of points in the polygonal line */
      +			   const XCBPOINT *points);         /* An array of points */
      +
      +

      + This function will draw the line between the first and the + second points, then the line between the second and the third + points, and so on. +

      +

      + To draw a segment, or several segments, we use +

      +
      +XCBVoidCookie XCBPolySegment (XCBConnection    *c,              /* The connection to the X server */
      +                              XCBDRAWABLE       drawable,       /* The drawable on which we want to draw the segment(s) */
      +			      XCBGCONTEXT       gc,             /* The Graphic Context we use to draw the segment(s) */
      +			      CARD32            segments_len,   /* The number of segments */
      +			      const XCBSEGMENT *segments);      /* An array of segments */
      +
      +

      + The XCBSEGMENT type is just a + structure with four fields (the coordinates of the two points + that define the segment): +

      +
      +typedef struct {
      +    INT16 x1;
      +    INT16 y1;
      +    INT16 x2;
      +    INT16 y2;
      +} XCBSEGMENT;
      +
      +

      + To draw a rectangle, or several rectangles, we use +

      +
      +XCBVoidCookie XCBPolyRectangle (XCBConnection      *c,              /* The connection to the X server */
      +				XCBDRAWABLE         drawable,       /* The drawable on which we want to draw the rectangle(s) */
      +				XCBGCONTEXT         gc,             /* The Graphic Context we use to draw the rectangle(s) */
      +				CARD32              rectangles_len, /* The number of rectangles */
      +				const XCBRECTANGLE *rectangles);    /* An array of rectangles */
      +
      +

      + The XCBRECTANGLE type is just a + structure with four fields (the coordinates of the top-left + corner of the rectangle, and its width and height): +

      +
      +typedef struct {
      +    INT16 x;
      +    INT16 y;
      +    CARD16 width;
      +    CARD16 height;
      +} XCBRECTANGLE;
      +
      +

      + TODO: there's no coordinate_mode. Is it normal ? +

      +

      + To draw an elliptical arc, or several elliptical arcs, we use +

      +
      +XCBVoidCookie XCBPolyArc (XCBConnection *c,          /* The connection to the X server */
      +                          XCBDRAWABLE    drawable,   /* The drawable on which we want to draw the arc(s) */
      +			  XCBGCONTEXT    gc,         /* The Graphic Context we use to draw the arc(s) */
      +			  CARD32         arcs_len,   /* The number of arcs */
      +			  const XCBARC  *arcs);      /* An array of arcs */
      +
      +

      + The XCBARC type is a structure with + six fields: +

      +
      +typedef struct {
      +    INT16 x;        /* Top left x coordinate of the rectangle surrounding the ellipse */
      +    INT16 y;        /* Top left y coordinate of the rectangle surrounding the ellipse */
      +    CARD16 width;   /* Width of the rectangle surrounding the ellipse */
      +    CARD16 height;  /* Height of the rectangle surrounding the ellipse */
      +    INT16 angle1;   /* Angle at which the arc begins */
      +    INT16 angle2;   /* Angle at which the arc ends */
      +} XCBARC;
      +
      +
      +

      + Note: the angles are expressed in units of 1/64 of a degree, + so to have an angle of 90 degrees, starting at 0, + angle1 = 0 and + angle2 = 90 << 6. Positive angles + indicate counterclockwise motion, while negative angles + indicate clockwise motion. +

      +
      +

      + TODO: there's no coordinate_mode. Is it normal ? +

      +

      + TODO: I think that (x,y) should be the center of the + ellipse, and (width, height) the radius. It's more logical. +

      +

      + The corresponding function which fill inside the geometrical + object are listed below, without further explanation, as they + are used as the above functions. +

      +

      + To Fill a polygon defined by the points given as arguments , + we use +

      +
      +XCBVoidCookie XCBFillPoly (XCBConnection  *c,
      +                           XCBDRAWABLE     drawable,
      +			   XCBGCONTEXT     gc,
      +			   CARD8           shape,
      +			   CARD8           coordinate_mode,
      +			   CARD32          points_len,
      +			   const XCBPOINT *points);
      +
      +

      + The shape parameter specifies a + shape that helps the server to improve performance. Available + values are +

      +
        +
      • Complex
      • +
      • Convex
      • +
      • Nonconvex
      • +
      +

      + To fill one or several rectangles, we use +

      +
      +XCBVoidCookie XCBPolyFillRectangle (XCBConnection      *c,
      +                                    XCBDRAWABLE         drawable,
      +				    XCBGCONTEXT         gc,
      +				    CARD32              rectangles_len,
      +				    const XCBRECTANGLE *rectangles);
      +
      +

      + To fill one or several arcs, we use +

      +
      +XCBVoidCookie XCBPolyFillArc (XCBConnection *c,
      +                              XCBDRAWABLE    drawable,
      +			      XCBGCONTEXT    gc,
      +			      CARD32         arcs_len,
      +			      const XCBARC  *arcs);
      +
      +

      +

      + To illustrate these functions, here is an example that draws + four points, a polygonal line, two segments, two rectangles + and two arcs. Remark that we use events for the first time, as + an introduction to the next section. +

      +
      +#include <stdlib.h>
      +#include <stdio.h>
      +
      +#include <X11/XCB/xcb.h>
      +
      +/* Get the depth of the screen. Needed in order to draw something */
      +int
      +get_depth(XCBConnection *c,
      +	  XCBSCREEN     *root)
      +{
      +  XCBDRAWABLE        drawable;
      +  XCBGetGeometryRep *geom;
      +  int                depth;
      +
      +  drawable.window = root->root;
      +  geom = XCBGetGeometryReply (c, XCBGetGeometry(c, drawable), 0);
      +
      +  if(!geom)
      +    {
      +      perror ("GetGeometry(root) failed");
      +      exit (0);
      +    }
      +  
      +  depth = geom->depth;
      +  free (geom);
      +
      +  return depth;
      +}
      +
      +int
      +main (int argc, char *argv[])
      +{
      +  XCBConnection   *c;
      +  XCBSCREEN       *screen;
      +  XCBDRAWABLE      win;
      +  XCBGCONTEXT      foreground;
      +  XCBGenericEvent *e;
      +  CARD32           mask = 0;
      +  CARD32           values[2];
      +
      +  /* geometric objects */
      +  XCBPOINT         points[] = {
      +    {10, 10},
      +    {10, 20},
      +    {20, 10},
      +    {20, 20}};
      +
      +  XCBPOINT         polyline[] = {
      +    {50, 10},
      +    {55, 30},
      +    {80, 10},
      +    {90, 20}};
      +
      +  XCBSEGMENT       segments[] = {
      +    {100, 10, 140, 30},
      +    {110, 25, 130, 60}};
      +
      +  XCBRECTANGLE     rectangles[] = {
      +    { 10, 50, 40, 20},
      +    { 80, 50, 10, 40}};
      +
      +  XCBARC           arcs[] = {
      +    {10, 100, 60, 40, 0, 90 << 6},
      +    {90, 100, 55, 40, 0, 270 << 6}};
      +  
      +  /* Open the connection to the X server */
      +  c = XCBConnect (NULL, NULL);
      +  
      +  /* Get the first screen */
      +  screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data;
      +
      +  /* Create black (foregroung) graphic context */
      +  win.window = screen->root;
      +
      +  foreground = XCBGCONTEXTNew (c);
      +  mask = GCForeground | GCGraphicsExposures;
      +  values[0] = screen->black_pixel;
      +  values[1] = 0;
      +  XCBCreateGC (c, foreground, win, mask, values);
      +
      +  /* Ask for our window's Id */
      +  win.window = XCBWINDOWNew(c);
      +
      +  /* Create the window */
      +  mask = XCBCWBackPixel | XCBCWEventMask;
      +  values[0] = screen->white_pixel;
      +  values[1] = ExposureMask;
      +  XCBCreateWindow (c,                        /* Connection          */
      + 		   0,                        /* depth               */
      +		   win.window,               /* window Id           */
      +		   screen->root,             /* parent window       */
      +		   0, 0,                     /* x, y                */
      +		   150, 150,                 /* width, height       */
      +		   10,                       /* border_width        */
      +		   InputOutput,              /* class               */
      +		   screen->root_visual,      /* visual              */
      +		   mask, values);            /* masks */
      +
      +  /* Map the window on the screen */
      +  XCBMapWindow (c, win.window);
      +
      +
      +  /* We flush the request */
      +  XCBSync (c, 0);
      +
      +  while ((e = XCBWaitEvent (c)))
      +    {
      +      switch (e->response_type)
      +	{
      +	case XCBExpose:
      +	  {
      +	    /* We draw the points */
      +	    XCBPolyPoint (c, CoordModeOrigin, win, foreground, 4, points);
      +	    
      +	    /* We draw the polygonal line */
      +	    XCBPolyLine (c, CoordModeOrigin, win, foreground, 4, polyline);
      +	    
      +	    /* We draw the segements */
      +	    XCBPolySegment (c, win, foreground, 2, segments);
      +	    
      +	    /* We draw the rectangles */
      +	    XCBPolyRectangle (c, win, foreground, 2, rectangles);
      +	    
      +	    /* We draw the arcs */
      +	    XCBPolyArc (c, win, foreground, 2, arcs);
      +
      +	    /* We flush the request */
      +	    XCBSync (c, 0);
      +	    
      +	    break;
      +	  }
      +	default:
      +	  {
      +	    /* Unknown event type, ignore it */
      +	    break;
      +	  }
      +	}
      +      /* Free the Generic Event */
      +      free (e);
      +    }
      +
      +  return 1;
      +}
      +
      +
    +
  19. X Events
  20. +

    + In an X program, everything is driven by events. Event painting + on the screen is sometimes done as a response to an event (an + Expose event). If part of a program's + window that was hidden, gets exposed (e.g. the window was raised + above other widows), the X server will send an "expose" event to + let the program know it should repaint that part of the + window. User input (key presses, mouse movement, etc) is also + received as a set of events. +

    +
      +
    1. Registering for event types using event masks
    2. +

      + During the creation of a window, you should give it what kind + of events it wishes to receive. Thus, you may register for + various mouse (also called pointer) events, keyboard events, + expose events, and so on. This is done for optimizing the + server-to-client connection (i.e. why send a program (that + might even be running at the other side of the globe) an event + it is not interested in ?) +

      +

      + In XCB, you use the "value_mask" and "value_list" data in the + XCBCreateWindow() function to + register for events. Here is how we register for + Expose event when creating a window: +

      +
      +  mask = XCBCWEventMask;
      +  valwin[0] = ExposureMask;
      +  win.window = XCBWINDOWNew (c);
      +  XCBCreateWindow (c, depth, win.window, root->root,
      +		   0, 0, 150, 150, 10,
      +		   InputOutput, root->root_visual,
      +		   mask, valwin);
      +
      +

      + ExposureMask is a constant defined + in the "X.h" header file. If we wanted to register to several + event types, we can logically "or" them, as follows: +

      +
      +  mask = XCBCWEventMask;
      +  valwin[0] = ExposureMask | ButtonPressMask;
      +  win.window = XCBWINDOWNew (c);
      +  XCBCreateWindow (c, depth, win.window, root->root,
      +		   0, 0, 150, 150, 10,
      +		   InputOutput, root->root_visual,
      +		   mask, valwin);
      +
      +

      + This registers for Expose events as + well as for mouse button presses insode the created + window. You should note that a mask may represent several + event sub-types. +

      +

      + The values that a mask could take are given + by the XCBCW enumeration: +

      +
      +typedef enum {
      +    XCBCWBackPixmap       = 1L<<0,
      +    XCBCWBackPixel        = 1L<<1,
      +    XCBCWBorderPixmap     = 1L<<2,
      +    XCBCWBorderPixel      = 1L<<3,
      +    XCBCWBitGravity       = 1L<<4,
      +    XCBCWWinGravity       = 1L<<5,
      +    XCBCWBackingStore     = 1L<<6,
      +    XCBCWBackingPlanes    = 1L<<7,
      +    XCBCWBackingPixel     = 1L<<8,
      +    XCBCWOverrideRedirect = 1L<<9,
      +    XCBCWSaveUnder        = 1L<<10,
      +    XCBCWEventMask        = 1L<<11,
      +    XCBCWDontPropagate    = 1L<<12,
      +    XCBCWColormap         = 1L<<13,
      +    XCBCWCursor           = 1L<<14
      +} XCBCW;
      +
      +
      +

      Note: we must be careful when setting the values of the valwin + parameter, as they have to follow the order the + XCBCW enumeration. Here is an + example: +

      +
      +
      +  mask = XCBCWEventMask | XCBCWBackPixmap;
      +  valwin[0] = None;                           /* for XCBCWBackPixmap (whose value is 1)    */
      +  valwin[1] = ExposureMask | ButtonPressMask; /* for XCBCWEventMask, whose value (2048)    */
      +                                              /* is superior to the one of XCBCWBackPixmap */
      +
      +

      + If the window has already been created, we can use the + XCBConfigureWindow() function to set + the events that the window will receive. The subsection + Configuring a window shows its + prototype. As an example, here is a piece of code that + configures the window to receive the + Expose and + ButtonPressMask events: +

      +
      +const static CARD32 values[] = { ExposureMask | ButtonPressMask };
      +
      +/* The connection c and the window win are supposed to be defined */
      +
      +XCBConfigureWindow (c, win, XCBCWEventMask, values);
      +
      +
      +

      + Note: A common bug programmers do is adding code to handle new + event types in their program, while forgetting to add the + masks for these events in the creation of the window. Such a + programmer then should sit down for hours debugging his + program, wondering "Why doesn't my program notice that I + released the button?", only to find that they registered for + button press events but not for button release events. +

      +
      +
    3. Receiving events: writing the events loop
    4. +

      + After we have registered for the event types we are interested + in, we need to enter a loop of receiving events and handling + them. There are two ways to receive events: a blocking way and + a non blocking way: +

      +
        +
      • + XCBWaitEvent (XCBConnection *c) + is the blocking way. It waits (so blocks...) until an event is + queued in the X server. Then it retrieves it into a newly + allocated structure (it dequeues it from the queue) and returns + it. This structure has to be freed. The function returns + NULL if an error occurs. +
      • +
        +
      • + XCBPollForEvent (XCBConnection *c, int + *error) is the non blocking way. It looks at the event + queue and returns (and dequeues too) an existing event into + a newly allocated structure. This structure has to be + freed. It returns NULL if there is + no event. If an error occurs, the parameter error will be filled with the error + status. +
      • +
      +

      + There are various ways to write such a loop. We present two + ways to write such a loop, with the two functions above. The + first one uses XCBWaitEvent, which + is similar to an event Xlib loop using only XNextEvent: +

      +
      +  XCBGenericEvent *e;
      +
      +  while ((e = XCBWaitEvent (c)))
      +    {
      +      switch (e->response_type)
      +	{
      +	case XCBExpose:
      +	  {
      +	    /* Handle the Expose event type */
      +	    XCBExposeEvent *ev = (XCBExposeEvent *)e;
      +
      +	    /* ... */
      +
      +	    break;
      +	  }
      +	case XCBButtonPress: 
      +	  {
      +	    /* Handle the ButtonPress event type */
      +	    XCBButtonPressEvent *ev = (XCBButtonPressEvent *)e;
      +
      +	    /* ... */
      +
      +	    break;
      +	  }
      +	default:
      +	  {
      +	    /* Unknown event type, ignore it */
      +	    break;
      +	  }
      +	}
      +      /* Free the Generic Event */
      +      free (e);
      +    }
      +
      +

      + You will certainly want to use XCBPollForEvent(XCBConnection *c, int + *error) if, in Xlib, you use XPending: +

      +
      +  while (XPending (display))
      +    {
      +      XEvent ev;
      +
      +      XNextEvent(d, &ev);
      +      
      +      /* Manage your event */
      +    }
      +
      +

      + Such a loop in XCB looks like: +

      +
      +  XCBGenericEvent *ev;
      +
      +  while ((ev = XCBPollForEvent (conn, 0)))
      +    {
      +      /* Manage your event */
      +    }
      +
      +

      + The events are managed in the same way as with XCBWaitEvent. + Obviously, we will need to give the user some way of + terminating the program. This is usually done by handling a + special "quit" event, as we will soon see. +

      +
      +
      + Comparison Xlib/XCB +
      +
      +
        +
      • XNextEvent ()
      • +
      +
      +
      +
        +
      • XCBWaitEvent ()
      • +
      +
      +
      +
        +
      • XPending ()
      • +
      • XNextEvent ()
      • +
      +
      +
      +
        +
      • XCBPollForEvent ()
      • +
        +
      +
      +
      +

      +

    5. Expose events
    6. +

      + The Expose event is one of the most + basic (and most used) events an application may receive. It + will be sent to us in one of several cases: +

        +
      • A window that covered part of our window has moved + away, exposing part (or all) of our window.
      • +
      • Our window was raised above other windows.
      • +
      • Our window mapped for the first time.
      • +
      • Our window was de-iconified.
      • +
      +

      +

      + You should note the implicit assumption hidden here: the + contents of our window is lost when it is being obscured + (covered) by either windows. One may wonder why the X server + does not save this contents. The answer is: to save + memory. After all, the number of windows on a display at a + given time may be very large, and storing the contents of all + of them might require a lot of memory. Actually, there is a + way to tell the X server to store the contents of a window in + special cases, as we will see later. +

      +

      + When we get an Expose event, we + should take the event's data from the members of the following + structure: +

      +
      +typedef struct {
      +    BYTE response_type;  /* The type of the event, here it is XCBExpose */
      +    CARD8 pad0;
      +    CARD16 sequence;
      +    XCBWINDOW window;    /* The Id of the window that receives the event (in case */
      +                         /* our application registered for events on several windows */
      +    CARD16 x;            /* The x coordinate of the top-left part of the window that needs to be redrawn */
      +    CARD16 y;            /* The y coordinate of the top-left part of the window that needs to be redrawn */
      +    CARD16 width;        /* The width of the part of the window that needs to be redrawn */
      +    CARD16 height;       /* The height of the part of the window that needs to be redrawn */
      +    CARD16 count;
      +} XCBExposeEvent;
      +
      +
    7. Getting user input
    8. +

      + User input traditionally comes from two sources: the mouse + and the keyboard. Various event types exist to notify us of + user input (a key being presses on the keyboard, a key being + released on the keyboard, the mouse moving over our window, + the mouse entering (or leaving) our window, and so on. +

      +
        +
      1. Mouse button press and release events
      2. +

        + The first event type we will deal with is a mouse + button-press (or button-release) event in our window. In + order to register to such an event type, we should add one + (or more) of the following masks when we create our window: +

        +
          +
        • ButtonPressMask: notify us + of any button that was pressed in one of our windows.
        • +
        • ButtonReleaseMask: notify us + of any button that was released in one of our windows.
        • +
        +

        + The structure to be checked for in our events loop is the + same for these two events, and is the following: +

        +
        +typedef struct {
        +    BYTE response_type;  /* The type of the event, here it is XCBButtonPressEvent or XCBButtonReleaseEvent */
        +    XCBBUTTON detail;
        +    CARD16 sequence;
        +    XCBTIMESTAMP time;   /* Time, in milliseconds the event took place in */
        +    XCBWINDOW root;
        +    XCBWINDOW event;
        +    XCBWINDOW child;
        +    INT16 root_x;
        +    INT16 root_y;
        +    INT16 event_x;       /* The x coordinate where the mouse has been pressed in the window */
        +    INT16 event_y;       /* The y coordinate where the mouse has been pressed in the window */
        +    CARD16 state;        /* A mask of the buttons (or keys) during the event */
        +    BOOL same_screen;
        +} XCBButtonPressEvent;
        +
        +typedef XCBButtonPressEvent XCBButtonReleaseEvent;
        +
        +

        + The time field may be used to calculate "double-click" + situations by an application (e.g. if the mouse button was + clicked two times in a duration shorter than a given amount + of time, assume this was a double click). +

        +

        + The state field is a mask of the buttons held down during + the event. It is a bitwise OR of any of the following: +

        +
          +
        • Button1Mask
        • +
        • Button2Mask
        • +
        • Button3Mask
        • +
        • Button4Mask
        • +
        • Button5Mask
        • +
        • ShiftMask
        • +
        • LockMask
        • +
        • ControlMask
        • +
        • Mod1Mask
        • +
        • Mod2Mask
        • +
        • Mod3Mask
        • +
        • Mod4Mask
        • +
        • Mod5Mask
        • +
        +

        + Their names are self explanatory, where the first 5 refer to + the mouse buttons that are being pressed, while the rest + refer to various "special keys" that are being pressed (Mod1 + is usually the 'Alt' key or the 'Meta' key). +

        +

        + TODO: Problem: it seems that the state does not + change when clicking with various buttons. +

        +
      3. Mouse movement events
      4. +

        + Similar to mouse button press and release events, we also + can be notified of various mouse movement events. These can + be split into two families. One is of mouse pointer + movement while no buttons are pressed, and the second is a + mouse pointer motion while one (or more) of the buttons are + pressed (this is sometimes called "a mouse drag operation", + or just "dragging"). The following event masks may be added + during the creation of our window: +

        +
          +
        • PointerMotionMask: events of + the pointer moving in one of the windows controlled by our + application, while no mouse button is held pressed.
        • +
        • ButtonMotionMask: Events of + the pointer moving while one or more of the mouse buttons + is held pressed.
        • +
        • Button1MotionMask: same as + ButtonMotionMask, but only when + the 1st mouse button is held pressed.
        • +
        • Button2MotionMask, + Button3MotionMask, + Button4MotionMask, + Button5MotionMask: same as + Button1MotionMask, but + respectively for 2nd, 3rd, 4th and 5th mouse button.
        • +
        +

        + The structure to be checked for in our events loop is the + same for these events, and is the following: +

        +
        +typedef struct {
        +    BYTE response_type;  /* The type of the event */
        +    BYTE detail;
        +    CARD16 sequence;
        +    XCBTIMESTAMP time;   /* Time, in milliseconds the event took place in */
        +    XCBWINDOW root;
        +    XCBWINDOW event;
        +    XCBWINDOW child;
        +    INT16 root_x;
        +    INT16 root_y;
        +    INT16 event_x;       /* The x coordinate of the mouse when the  event was generated */
        +    INT16 event_y;       /* The y coordinate of the mouse when the  event was generated */
        +    CARD16 state;        /* A mask of the buttons (or keys) during the event */
        +    BOOL same_screen;
        +} XCBMotionNotifyEvent;
        +
        +
      5. Mouse pointer enter and leave events
      6. +

        + Another type of event that applications might be interested + at, is a mouse pointer entering a window the program + controls, or leaving such a window. Some programs use these + events to show the user tht the applications is now in + focus. In order to register for such an event type, we + should add one (or more) of the following masks when we + create our window: +

        +
          +
        • EnterWindowMask: notify us + when the mouse pointer enters any of our controlled + windows.
        • +
        • LeaveWindowMask: notify us + when the mouse pointer leaves any of our controlled + windows.
        • +
        +

        + The structure to be checked for in our events loop is the + same for these two events, and is the following: +

        +
        +typedef struct {
        +    BYTE response_type;  /* The type of the event */
        +    BYTE detail;
        +    CARD16 sequence;
        +    XCBTIMESTAMP time;   /* Time, in milliseconds the event took place in */
        +    XCBWINDOW root;
        +    XCBWINDOW event;
        +    XCBWINDOW child;
        +    INT16 root_x;
        +    INT16 root_y;
        +    INT16 event_x;       /* The x coordinate of the mouse when the  event was generated */
        +    INT16 event_y;       /* The y coordinate of the mouse when the  event was generated */
        +    CARD16 state;        /* A mask of the buttons (or keys) during the event */
        +    BYTE mode;           /* The number of mouse button that was clicked */
        +    BYTE same_screen_focus;
        +} XCBEnterNotifyEvent;
        +
        +typedef XCBEnterNotifyEvent XCBLeaveNotifyEvent;
        +
        +
      7. The keyboard focus
      8. +

        + There may be many windows on a screen, but only a single + keyboard attached to them. How does the X server then know + which window should be sent a given keyboard input ? This is + done using the keyboard focus. Only a single window on the + screen may have the keyboard focus at a given time. There + is a XCB function that allow a program to set the keyboard + focus to a given window. The user can usually set the + keyboard ficus using the window manager (often by clicking + on the title bar of the desired window). Once our window + has the keyboard focus, every key press or key release will + cause an event to be sent to our program (if it regsitered + for these event types...). +

        +
      9. Keyboard press and release events
      10. +

        + If a window controlled by our program currently holds the + keyboard focus, it can receive key press and key release + events. So, we should add one (or more) of the following + masks when we create our window: +

        +
          +
        • KeyPressMask: notify us when + a key was pressed while any of our controlled windows had + the keyboard focus.
        • +
        • KeyReleaseMask: notify us + when a key was released while any of our controlled + windows had the keyboard focus.
        • +
        +

        + The structure to be checked for in our events loop is the + same for these two events, and is the following: +

        +
        +typedef struct {
        +    BYTE response_type;  /* The type of the event */
        +    XCBKEYCODE detail;
        +    CARD16 sequence;
        +    XCBTIMESTAMP time;   /* Time, in milliseconds the event took place in */
        +    XCBWINDOW root;
        +    XCBWINDOW event;
        +    XCBWINDOW child;
        +    INT16 root_x;
        +    INT16 root_y;
        +    INT16 event_x;
        +    INT16 event_y;
        +    CARD16 state;
        +    BOOL same_screen;
        +} XCBKeyPressEvent;
        +
        +typedef XCBKeyPressEvent XCBKeyReleaseEvent;
        +
        +

        + The detail field refer to the + physical key on the keyboard. +

        +

        + TODO: Talk about getting the ASCII code from the key code. +

        +
      +
    9. X events: a complete example
    10. +

      + As an example for handling events, we show a program that + creates a window, enter an events loop and check for all the + events described above, and write on the terminal the relevant + characteristics of the event. With this code, it should be + easy to add drawing operations, like those which have been + described above. +

      +
      +#include <malloc.h>
      +#include <stdio.h>
      +
      +#include <X11/XCB/xcb.h>
      +
      +int
      +main (int argc, char *argv[])
      +{
      +  XCBConnection   *c;
      +  XCBSCREEN       *screen;
      +  XCBDRAWABLE      win;
      +  XCBGenericEvent *e;
      +  CARD32           mask = 0;
      +  CARD32           values[2];
      +  
      +  /* Open the connection to the X server */
      +  c = XCBConnect (NULL, NULL);
      +  
      +  /* Get the first screen */
      +  screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data;
      +
      +  /* Ask for our window's Id */
      +  win.window = XCBWINDOWNew(c);
      +
      +  /* Create the window */
      +  mask = XCBCWBackPixel | XCBCWEventMask;
      +  values[0] = screen->white_pixel;
      +  values[1] = ExposureMask      | ButtonPressMask  | ButtonReleaseMask |
      +              PointerMotionMask | EnterWindowMask  | LeaveWindowMask   |
      +               KeyPressMask     | KeyReleaseMask;
      +  XCBCreateWindow (c,                        /* Connection          */
      + 		   0,                        /* depth               */
      +		   win.window,               /* window Id           */
      +		   screen->root,             /* parent window       */
      +		   0, 0,                     /* x, y                */
      +		   150, 150,                 /* width, height       */
      +		   10,                       /* border_width        */
      +		   InputOutput,              /* class               */
      +		   screen->root_visual,      /* visual              */
      +		   mask, values);            /* masks */
      +
      +  /* Map the window on the screen */
      +  XCBMapWindow (c, win.window);
      +
      +  XCBSync (c, 0);
      +  while ((e = XCBWaitEvent (c)))
      +    {
      +      switch (e->response_type)
      +	{
      +	case XCBExpose:
      +	  {
      +	    XCBExposeEvent *ev = (XCBExposeEvent *)e;
      +	    
      +	    printf ("Window %ld exposed. Region to be redrawn at location (%d,%d), with dimension (%d,%d)\n",
      +	            ev->window.xid, ev->x, ev->y, ev->width, ev->height);
      +	    break;
      +	  }
      +	case XCBButtonPress: 
      +	  {
      +	    XCBButtonPressEvent *ev = (XCBButtonPressEvent *)e;
      +	    int                  button_num = 0;
      +	    
      +	    if ((ev->state | Button1Mask) == Button1Mask)
      +	      button_num = 1;
      +	    if ((ev->state | Button2Mask) == Button2Mask)
      +	      button_num = 2;
      +	    if ((ev->state | Button3Mask) == Button3Mask)
      +	      button_num = 3;
      +	    if ((ev->state | Button4Mask) == Button4Mask)
      +	      button_num = 4;
      +	    if ((ev->state | Button5Mask) == Button5Mask)
      +	      button_num = 5;
      +	      
      +	    switch (ev->detail.id)
      +	      {
      +	      case 4:
      +	        {
      +		printf ("Wheel Button up in window %ld, at coordinates (%d,%d)\n",
      +                        ev->event.xid, ev->event_x, ev->event_y);
      +		break;
      +		}
      +	      case 5:
      +	        {
      +		printf ("Wheel Button down in window %ld, at coordinates (%d,%d)\n",
      +                        ev->event.xid, ev->event_x, ev->event_y);
      +		break;
      +		}
      +	      default:
      +	        printf ("Button %d pressed in window %ld, at coordinates (%d,%d)\n",
      +                        ev->detail.id, ev->event.xid, ev->event_x, ev->event_y);
      +	      }
      +	    break;
      +	  }
      +	case XCBButtonRelease: 
      +	  {
      +	    XCBButtonReleaseEvent *ev = (XCBButtonReleaseEvent *)e;
      +	    int                  button_num = 0;
      +	    
      +	    if ((ev->state | Button1Mask) == Button1Mask)
      +	      button_num = 1;
      +	    if ((ev->state | Button2Mask) == Button2Mask)
      +	      button_num = 2;
      +	    if ((ev->state | Button3Mask) == Button3Mask)
      +	      button_num = 3;
      +	    if ((ev->state | Button4Mask) == Button4Mask)
      +	      button_num = 4;
      +	    if ((ev->state | Button5Mask) == Button5Mask)
      +	      button_num = 5;
      +	    
      +	    printf ("Button %d released in window %ld, at coordinates (%d,%d)\n",
      +                    ev->detail.id, ev->event.xid, ev->event_x, ev->event_y);
      +	    break;
      +	  }
      +	case XCBMotionNotify:
      +	  {
      +	    XCBMotionNotifyEvent *ev = (XCBMotionNotifyEvent *)e;
      +	    
      +	    printf ("Mouse moved in window %ld, at coordinates (%d,%d)\n",
      +                    ev->event.xid, ev->event_x, ev->event_y);
      +	    break;
      +	  }
      +	case XCBEnterNotify:
      +	  {
      +	    XCBEnterNotifyEvent *ev = (XCBEnterNotifyEvent *)e;
      +	    
      +	    printf ("Mouse entered window %ld, at coordinates (%d,%d)\n",
      +                    ev->event.xid, ev->event_x, ev->event_y);
      +	    break;
      +	  }
      +	case XCBLeaveNotify:
      +	  {
      +	    XCBLeaveNotifyEvent *ev = (XCBLeaveNotifyEvent *)e;
      +	    
      +	    printf ("Mouse leaved window %ld, at coordinates (%d,%d)\n",
      +                    ev->event.xid, ev->event_x, ev->event_y);
      +	    break;
      +	  }
      +	case XCBKeyPress: 
      +	  {
      +	    XCBKeyPressEvent *ev = (XCBKeyPressEvent *)e;
      +
      +	    printf ("Key pressed in window %ld\n",
      +                    ev->event.xid);
      +	    break;
      +	  }
      +	case XCBKeyRelease: 
      +	  {
      +	    XCBKeyReleaseEvent *ev = (XCBKeyReleaseEvent *)e;
      +
      +	    printf ("Key releaseed in window %ld\n",
      +                    ev->event.xid);
      +	    break;
      +	  }
      +	default:
      +	  {
      +	    /* Unknown event type, ignore it */
      +	    break;
      +	  }
      +	}
      +      /* Free the Generic Event */
      +      free (e);
      +    }
      +
      +  return 1;
      +}
      +
      +
    +
  21. Handling text and fonts
  22. +

    + Besides drawing graphics on a window, we often want to draw + text. Text strings have two major properties: the characters to + be drawn and the font with which they are drawn. In order to + draw text, we need to first request the X server to load a + font. We the assign a font to a Graphic Context, and finally, we + draw the text in a window, using the Graphic Context. +

    +
      +
    1. The Font structure
    2. +

      + In order to support flexible fonts, a font structure is + defined. You know what ? Its an Id: +

      +
      +typedef struct {
      +    CARD32 xid;
      +} XCBFONT;
      +
      +

      + It is used to contain information about a font, and is passed + to several functions that handle fonts selection and text drawing. +

      +
    +
  23. Interacting with the window manager
  24. +

    + After we have seen how to create windows and draw on them, we + take one step back, and look at how our windows are interacting + with their environment (the full screen and the other + windows). First of all, our application needs to interact with + the window manager. The window manager is responsible to + decorating drawn windows (i.e. adding a frame, an iconify + button, a system menu, a title bar, etc), as well as handling + icons shown when windows are being iconified. It also handles + ordering of windows on the screen, and other administrative + tasks. We need to give it various hints as to how we want it to + treat our application's windows. +

    +
      +
    1. Window properties
    2. +

      + Many of the parameters communicated to the window manager are + passed using data called "properties". These properties are + attached by the X server to different windows, and are stores + in a format that makes it possible to read them from different + machines that may use different architectures (remember that + an X client program may run on a remote machine). +

      +

      + The property and its type (a string, an integer, etc) are + Id. Their type are XCBATOM: +

      +
      +typedef struct {
      +    CARD32 xid;
      +} XCBATOM;
      +
      +

      + To change the property of a window, we use the following + function: +

      +
      +XCBVoidCookie XCBChangeProperty (XCBConnection *c,  /* Connection to the X server */
      +                                 CARD8 mode,        /* Property mode */
      +				 XCBWINDOW window,  /* Window */
      +				 XCBATOM property,  /* Property to change */
      +				 XCBATOM type,      /* Type of the property */
      +				 CARD8 format,      /* Format of the property (8, 16, 32) */
      +				 CARD32 data_len,   /* Length of the data parameter */
      +				 const void *data); /* Data */
      +
      +

      + The mode parameter coud be one of + the following value (defined in the X.h header file): +

      +
        +
      • PropModeReplace
      • +
      • PropModePrepend
      • +
      • PropModeAppend
      • +
      +

      +
    3. Setting the window name and icon name
    4. +

      + The firt thing we want to do would be to set the name for our + window. This is done using the + XCBChangeProperty() function. This + name may be used by the window manager as the title of the + window (in the title bar), in a task list, etc. The property + atom to use to set the name of a window is + WM_NAME (and + WM_ICON_NAME for the iconified + window) and its type is STRING. Here + is an example of utilization: +

      +
      +#include <string.h>
      +
      +#include <X11/XCB/xcb.h>
      +#include <X11/XCB/xcb_atom.h>
      +
      +int
      +main (int argc, char *argv[])
      +{
      +  XCBConnection *c;
      +  XCBSCREEN     *screen;
      +  XCBDRAWABLE    win;
      +  char          *title = "Hello World !";
      +  char          *title_icon = "Hello World ! (iconified)";
      +
      +
      +  
      +  /* Open the connection to the X server */
      +  c = XCBConnect (NULL, NULL);
      +  
      +  /* Get the first screen */
      +  screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data;
      +
      +  /* Ask for our window's Id */
      +  win.window = XCBWINDOWNew(c);
      +
      +  /* Create the window */
      +  XCBCreateWindow (c,                        /* Connection          */
      + 		   0,                        /* depth               */
      +		   win.window,               /* window Id           */
      +		   screen->root,             /* parent window       */
      +		   0, 0,                     /* x, y                */
      +		   250, 150,                 /* width, height       */
      +		   10,                       /* border_width        */
      +		   InputOutput,              /* class               */
      +		   screen->root_visual,      /* visual              */
      +		   0, NULL);                 /* masks, not used     */
      +
      +  /* Set the title of the window */
      +  XCBChangeProperty(c, PropModeReplace, win.window,
      +		    WM_NAME, STRING, 8,
      +		    strlen(title), title);
      +
      +  /* Set the title of the window icon */
      +  XCBChangeProperty(c, PropModeReplace, win.window,
      +		    WM_ICON_NAME, STRING, 8,
      +		    strlen(title_icon), title_icon);
      +
      +  /* Map the window on the screen */
      +  XCBMapWindow (c, win.window);
      +
      +  XCBSync (c, 0);
      +  
      +  while (1) {}
      +
      +  return 1;
      +}
      +
      +
      +

      Note: the use of the atoms needs our program to be compiled + and linked against xcb_atom, so that we have to use +

      +
      +
      +gcc prog.c -o prog `pkg-config --cflags --libs xcb_atom`
      +
      +
      +

      + for the program to compile fine. +

      +
      +
    +
  25. Simple window operations
  26. +

    + One more thing we can do to our window is manipulate them on the + screen (resize them, move them, raise or lower them, iconify + them, and so on). Some window operations functions are supplied + by XCB for this purpose. +

    +
      +
    1. Mapping and un-mapping a window
    2. +

      + The first pair of operations we can apply on a window is + mapping it, or un-mapping it. Mapping a window causes the + window to appear on the screen, as we have seen in our simple + window program example. Un-mapping it causes it to be removed + from the screen (although the window as a logical entity still + exists). This gives the effect of making a window hidden + (unmapped) and shown again (mapped). For example, if we have a + dialog box window in our program, instead of creating it every + time the user asks to open it, we can create the window once, + in an un-mapped mode, and when the user asks to open it, we + simply map the window on the screen. When the user clicked the + 'OK' or 'Cancel' button, we simply un-map the window. This is + much faster than creating and destroying the window, however, + the cost is wasted resources, both on the client side, and on + the X server side. +

      +

      + To map a window, you use the following function: +

      +
      +XCBVoidCookie XCBMapWindow(XCBConnection *c, XCBWINDOW window);
      +
      +

      + To have a simple example, see the example + above. The mapping operation will cause an + Expose event to be sent to our + application, unless the window is completely covered by other + windows. +

      +

      + Un-mapping a window is also simple. You use the function +

      +
      +XCBVoidCookie XCBUnmapWindow(XCBConnection *c, XCBWINDOW window);
      +
      +

      + The utilization of this function is the same as + XCBMapWindow(). +

      +
    3. Configuring a window
    4. +

      + As we have seen when we have created our first window, in the + X Events subsection, we can set some attributes to the window + (that is, the position, the size, the events the window will + receive, etc). If we want to modify them, but the window is + already created, we can change them by using hte following + function: +

      +
      +XCBVoidCookie XCBConfigureWindow (XCBConnection *c,            /* The connection to the X server*/
      +                                  XCBWINDOW      window,       /* The window to configure */
      +				  CARD16         value_mask,   /* The mask */
      +				  const CARD32  *value_list);  /* The values to set */
      +
      +

      + We set the value_mask to one or + several mask values that are in the X.h header: +

        +
      • CWX: new x coordinate of the window's top left corner
      • +
      • CWY: new y coordinate of the window's top left corner
      • +
      • CWWidth: new width of the window
      • +
      • CWHeight: new height of the window
      • +
      • CWBorderWidth: new width of the border of the window
      • +
      • CWSibling
      • +
      • CWStackMode: the new stacking order
      • +
      +

      +

      + We then give to value_mask the new + value. We now describe how to use + XCBConfigureWindow in some useful + situations. +

      +
    5. Moving a window around the screen
    6. +

      + An operation we might want to do with windows is to move them + to a different location. This can be done like this: +

      +
      +const static CARD32 values[] = { 10, 20 };
      +
      +/* The connection c and the window win are supposed to be defined */
      +
      +/* Move the window to coordinates x = 10 and y = 20 */
      +XCBConfigureWindow (c, win, CWX | CWY, values);
      +
      +

      + Note that when the window is moved, it might get partially + exposed or partially hidden by other windows, and thus we + might get Expose events due to this + operation. +

      +
    7. Resizing a window
    8. +

      + Yet another operation we can do is to change the size of a + window. This is done using the following code: +

      +
      +const static CARD32 values[] = { 200, 300 };
      +
      +/* The connection c and the window win are supposed to be defined */
      +
      +/* Resize the window to width = 10 and height = 20 */
      +XCBConfigureWindow (c, win, CWWidth | CWHeight, values);
      +
      +

      + We can also combine the move and resize operations using one + single call to XCBConfigureWindow: +

      +
      +const static CARD32 values[] = { 10, 20, 200, 300 };
      +
      +/* The connection c and the window win are supposed to be defined */
      +
      +/* Move the window to coordinates x = 10 and y = 20 */
      +/* and resize the window to width = 10 and height = 20 */
      +XCBConfigureWindow (c, win, CWX | CWY | CWWidth | CWHeight, values);
      +
      +
    9. Changing windows stacking order: raise and lower
    10. +

      + Until now, we changed properties of a single window. We'll see + that there are properties that relate to the window and other + windows. One of hem is the stacking order. That is, the order + in which the windows are layered on top of each other. The + front-most window is said to be on the top of the stack, while + the back-most window is at the bottom of the stack. Here is + how to manipulate our windows stack order: +

      +
      +const static CARD32 values[] = { Above };
      +
      +/* The connection c and the window win are supposed to be defined */
      +
      +/* Move the window on the top of the stack */
      +XCBConfigureWindow (c, win, CWStackMode, values);
      +
      +
      +const static CARD32 values[] = { Below };
      +
      +/* The connection c and the window win are supposed to be defined */
      +
      +/* Move the window on the bottom of the stack */
      +XCBConfigureWindow (c, win, CWStackMode, values);
      +
      +
    11. Getting information about a window
    12. +

      + Just like we can set various attributes of our windows, we can + also ask the X server supply the current values of these + attributes. For example, we can chewk where a window is + located on the screen, what is its current size, wheter it is + mapped or not, etc. The structure that contains some of this + information is +

      +
      +typedef struct {
      +    BYTE response_type;
      +    CARD8 depth;            /* depth of the window */
      +    CARD16 sequence;
      +    CARD32 length;
      +    XCBWINDOW root;         /* Id of the root window *>
      +    INT16 x;                /* X coordinate of the window's location */
      +    INT16 y;                /* Y coordinate of the window's location */
      +    CARD16 width;           /* Width of the window */
      +    CARD16 height;          /* Height of the window */
      +    CARD16 border_width;    /* Width of the window's border */
      +} XCBGetGeometryRep;
      +
      +

      + XCB fill this structure with two functions: +

      +
      +XCBGetGeometryCookie  XCBGetGeometry      (XCBConnection         *c,
      +                                           XCBDRAWABLE            drawable);
      +XCBGetGeometryRep    *XCBGetGeometryReply (XCBConnection         *c,
      +                                           XCBGetGeometryCookie   cookie,
      +                                           XCBGenericError      **e);
      +
      +

      + You use them as follows: +

      +
      +  XCBConnection     *c;
      +  XCBDRAWABLE        win;
      +  XCBGetGeometryRep *geom;
      +
      +  /* You initialize c and win */
      +
      +  geom = XCBGetGeometryReply (c, XCBGetGeometry (c, win), 0);
      +
      +  /* Do something with the fields of geom */
      +  
      +  free (geom);
      +
      +

      + Remark that you have to free the structure, as + XCBGetGeometryReply allocates a + newly one. +

      +

      + One problem is that the returned location of the window is + relative to its parent window. This makes these coordinates + rather useless for any window manipulation functions, like + moving it on the screen. In order to overcome this problem, we + need to take a two-step operation. First, we find out the Id + of the parent window of our window. We then translate the + above relative coordinates to the screen coordinates. +

      +

      + To get the Id of the parent window, we need this structure: +

      +
      +typedef struct {
      +    BYTE response_type;
      +    CARD8 pad0;
      +    CARD16 sequence;
      +    CARD32 length;
      +    XCBWINDOW root;
      +    XCBWINDOW parent;    /* Id of the parent window */
      +    CARD16 children_len;
      +    CARD8 pad1[14];
      +} XCBQueryTreeRep;
      +
      +

      + To fill this structure, we use these two functions: +

      +
      +XCBQueryTreeCookie XCBQueryTree      (XCBConnection       *c,
      +                                      XCBWINDOW            window);
      +XCBQueryTreeRep   *XCBQueryTreeReply (XCBConnection       *c,
      +                                      XCBQueryTreeCookie   cookie,
      +				      XCBGenericError    **e);
      +
      +

      + The translated coordinates will be found in this structure: +

      +
      +typedef struct {
      +    BYTE response_type;
      +    BOOL same_screen;
      +    CARD16 sequence;
      +    CARD32 length;
      +    XCBWINDOW child;
      +    CARD16 dst_x;        /* Translated x coordinate */
      +    CARD16 dst_y;        /* Translated y coordinate */
      +} XCBTranslateCoordinatesRep;
      +
      +

      + As usual, we need two functions to fill this structure: +

      +
      +XCBTranslateCoordinatesCookie XCBTranslateCoordinates      (XCBConnection                  *c,
      +                                                            XCBWINDOW                       src_window,
      +							    XCBWINDOW                       dst_window,
      +							    INT16                           src_x,
      +							    INT16                           src_y);
      +XCBTranslateCoordinatesRep   *XCBTranslateCoordinatesReply (XCBConnection                 *c,
      +							    XCBTranslateCoordinatesCookie   cookie,
      +							    XCBGenericError               **e);
      +
      +

      + We use them as follows: +

      +
      +  XCBConnection              *c;
      +  XCBDRAWABLE                 win;
      +  XCBGetGeometryRep          *geom;
      +  XCBQueryTreeRep            *tree;
      +  XCBTranslateCoordinatesRep *trans;
      +
      +  /* You initialize c and win */
      +
      +  geom  = XCBGetGeometryReply (c, XCBGetGeometry (c, win), 0);
      +  if (!geom)
      +    return 0;
      +
      +  tree  = XCBQueryTreeReply (c, XCBQueryTree (c, win), 0);
      +  if (!tree)
      +    return 0;
      +
      +  trans = XCBTranslateCoordinatesReply (c,
      +                                        XCBTranslateCoordinates (c,
      +                                                                 win,
      +								 tree->parent,
      +								 geom->x, geom->y),
      +                                        0);
      +  if (!trans)
      +    return 0;
      +
      +  /* the translated coordinates are in trans->dst_x and trans->dst_y */
      +
      +  free (trans);
      +  free (tree);
      +  free (geom);
      +
      +

      + Of course, as for geom, + tree and + trans have to be freed. +

      +

      + The work is a bit hard, but XCB is a very low-level library. +

      +

      + TODO: the utilization of these functions should be a + prog, which displays the coordinates of the window. +

      +

      + There is another structure that gives informations about our window: +

      +
      +typedef struct {
      +    BYTE response_type;
      +    CARD8 backing_store;
      +    CARD16 sequence;
      +    CARD32 length;
      +    XCBVISUALID visual;            /* Visual of the window */
      +    CARD16 _class;
      +    CARD8 bit_gravity;
      +    CARD8 win_gravity;
      +    CARD32 backing_planes;
      +    CARD32 backing_pixel;
      +    BOOL save_under;
      +    BOOL map_is_installed;
      +    CARD8 map_state;               /* Map state of the window */
      +    BOOL override_redirect;
      +    XCBCOLORMAP colormap;          /* Colormap of the window */
      +    CARD32 all_event_masks;
      +    CARD32 your_event_mask;
      +    CARD16 do_not_propagate_mask;
      +} XCBGetWindowAttributesRep;
      +
      +

      + XCB supplies these two functions to fill it: +

      +
      +XCBGetWindowAttributesCookie XCBGetWindowAttributes      (XCBConnection                 *c, 
      +                                                          XCBWINDOW                      window);
      +XCBGetWindowAttributesRep   *XCBGetWindowAttributesReply (XCBConnection                 *c, 
      +                                                          XCBGetWindowAttributesCookie   cookie,
      +							  XCBGenericError              **e);
      +
      +

      + You use them as follows: +

      +
      +  XCBConnection             *c;
      +  XCBDRAWABLE                win;
      +  XCBGetWindowAttributesRep *attr;
      +
      +  /* You initialize c and win */
      +
      +  attr = XCBGetWindowAttributesReply (c, XCBGetWindowAttributes (c, win), 0);
      +
      +  if (!attr)
      +    return 0;
      +
      +  /* Do something with the fields of attr */
      +  
      +  free (attr);
      +
      +

      + As for geom, + attr has to be freed. +

      +
    +
  27. Using colors to paint the rainbow
  28. +

    + Up until now, all our painting operation were done using black + and white. We will (finally) see now how to draw using colors. +

    +
      +
    1. Color maps
    2. +

      + In the beginning, there were not enough colors. Screen + controllers could only support a limited number of colors + simultaneously (initially 2, then 4, 16 and 256). Because of + this, an application could not just ask to draw in a "light + purple-red" color, and expect that color to be available. Each + application allocated the colors it needed, and when all the + color entries (4, 16, 256 colors) were in use, the next color + allocation would fail. +

      +

      + Thus, the notion of "a color map" was introduced. A color map + is a table whose size is the same as the number of + simultaneous colors a given screen controller. Each entry + contained the RGB (Red, Green and Blue) values of a different + color (all colors can be drawn using some combination of red, + green and blue). When an application wants to draw on the + screen, it does not specify which color to use. Rather, it + specifies which color entry of some color map to be used + during this drawing. Change the value in this color map entry + and the drawing will use a different color. +

      +

      + In order to be able to draw using colors that got something to + do with what the programmer intended, color map allocation + functions are supplied. You could ask to allocate entry for a + color with a set of RGB values. If one already existed, you + would get its index in the table. If none existed, and the + table was not full, a new cell would be allocated to contain + the given RGB values, and its index returned. If the table was + full, the procedure would fail. You could then ask to get a + color map entry with a color that is closest to the one you + were asking for. This would mean that the actual drawing on + the screen would be done using colors similar to what you + wanted, but not the same. +

      +

      + On today's more modern screens where one runs an X server with + support for 16 million colors, this limitation looks a little + silly, but remember that there are still older computers with + older graphics cards out there. Using color map, support for + these screen becomes transparent to you. On a display + supporting 16 million colors, any color entry allocation + request would succeed. On a display supporting a limited + number of colors, some color allocation requests would return + similar colors. It won't look as good, but your application + would still work. +

      +
    3. Allocating and freeing Color Maps
    4. +

      + When you draw using XCB, you can choose to use the standard + color map of the screen your window is displayed on, or you + can allocate a new color map and apply it to a window. In the + latter case, each time the mouse moves onto your window, the + screen color map will be replaced by your window's color map, + and you'll see all the other windows on screen change their + colors into something quite bizzare. In fact, this is the + effect you get with X applications that use the "-install" + command line option. +

      +

      + In XCB, a color map is (as often in X) an Id: +

      +
      +typedef struct {
      +    CARD32 xid;
      +} XCBCOLORMAP;
      +
      +

      + In order to access the screen's default color map, you just + have to retrieve the default_colormap + field of the XCBSCREEN structure + (see Section + Checking basic information about a connection): +

      +
      +#include <stdio.h>
      +
      +#include <X11/XCB/xcb.h>
      +
      +int
      +main (int argc, char *argv[])
      +{
      +  XCBConnection *c;
      +  XCBSCREEN     *screen;
      +  XCBCOLORMAP    colormap;
      +  
      +  /* Open the connection to the X server and get the first screen */
      +  c = XCBConnect (NULL, NULL);
      +  screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data;
      +
      +  colormap = screen->default_colormap;
      +
      +  return 1;
      +}
      +
      +

      + This will return the color map used by default on the first + screen (again, remember that an X server may support several + different screens, each of which might have its own resources). +

      +

      + The other option, that of allocating a new colormap, works as + follows. We first ask the X server to give an Id to our color + map, with this function: +

      +
      +XCBCOLORMAP XCBCOLORMAPNew (XCBConnection *c);
      +
      +

      + Then, we create the color map with +

      +
      +XCBVoidCookie XCBCreateColormap (XCBConnection *c,       /* Pointer to the XCBConnection structure */
      +                                 BYTE           alloc,   /* Colormap entries to be allocated (AllocNone or AllocAll) */
      +				 XCBCOLORMAP    mid,     /* Id of the color map */
      +				 XCBWINDOW      window,  /* Window on whose screen the colormap will be created */
      +				 XCBVISUALID    visual); /* Id of the visual supported by the screen */
      +
      +

      + Here is an example of creation of a new color map: +

      +
      +#include <X11/XCB/xcb.h>
      +
      +int
      +main (int argc, char *argv[])
      +{
      +  XCBConnection *c;
      +  XCBSCREEN     *screen;
      +  XCBWINDOW      win;
      +  XCBCOLORMAP    cmap
      +  
      +  /* Open the connection to the X server and get the first screen */
      +  c = XCBConnect (NULL, NULL);
      +  screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data;
      +
      +  /* We create the window win here*/
      +
      +  cmap = XCBCOLORMAPNew (c);
      +  XCBCreateColormap (c, AllocNone, cmap, win, screen->root_visual);
      +
      +  return 1;
      +}
      +
      +

      + Note that the window parameter is only used to allow the X + server to create the color map for the given screen. We can + then use this color map for any window drawn on the same screen. +

      +

      + To free a color map, it suffices to use this function: +

      +
      +XCBVoidCookie XCBFreeColormap (XCBConnection *c,   /* The connection */
      +                               XCBCOLORMAP cmap);  /* The color map */
      +
      +
      +
      + Comparison Xlib/XCB +
      +
      +
        +
      • XCreateColormap ()
      • +
      +
      +
      +
        +
      • XCBCOLORMAPNew ()
      • +
      • XCBCreateColormap ()
      • +
      +
      +
      +
        +
      • XFreeColormap ()
      • +
      +
      +
      +
        +
      • XCBFreeColormap ()
      • +
      +
      +
      +

      +
    5. Allocating and freeing a color entry
    6. +

      + Once we got access to some color map, we can strat allocating + colors. The informations related to a color are stored in the + following structure: +

      +
      +typedef struct {
      +    BYTE response_type;
      +    CARD8 pad0;
      +    CARD16 sequence;
      +    CARD32 length;
      +    CARD16 red;          /* The red component   */
      +    CARD16 green;        /* The green component */
      +    CARD16 blue;         /* The blue component  */
      +    CARD8 pad1[2];
      +    CARD32 pixel;        /* The entry in the color map, supplied by the X server */
      +} XCBAllocColorRep;
      +
      +

      + XCB supplies these two functions to fill it: +

      +
      +XCBAllocColorCookie XCBAllocColor      (XCBConnection *c,
      +                                        XCBCOLORMAP    cmap,
      +				        CARD16         red,
      +			                CARD16         green,
      +				        CARD16         blue);
      +XCBAllocColorRep   *XCBAllocColorReply (XCBConnection        *c,
      +                                        XCBAllocColorCookie   cookie,
      +					XCBGenericError     **e);
      +
      +

      + The fuction XCBAllocColor() takes the + 3 RGB components as parameters (red, green and blue). Here is an + example of using these functions: +

      +
      +#include <malloc.h>
      +
      +#include <X11/XCB/xcb.h>
      +
      +int
      +main (int argc, char *argv[])
      +{
      +  XCBConnection    *c;
      +  XCBSCREEN        *screen;
      +  XCBWINDOW         win;
      +  XCBCOLORMAP       cmap;
      +  XCBAllocColorRep *rep;
      +  
      +  /* Open the connection to the X server and get the first screen */
      +  c = XCBConnect (NULL, NULL);
      +  screen = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).data;
      +
      +  /* We create the window win here*/
      +
      +  cmap = XCBCOLORMAPNew (c);
      +  XCBCreateColormap (c, AllocNone, cmap, win, screen->root_visual);
      +
      +  rep = XCBAllocColorReply (c, XCBAllocColor (c, cmap, 65535, 0, 0), 0);
      +  
      +  if (!rep)
      +    return 0;
      +
      +  /* Do something with r->pixel or the components */
      +
      +  free (rep);
      +
      +  return 1;
      +}
      +
      +

      + As XCBAllocColorReply() allocates + memory, you have to free rep. +

      +

      + TODO: Talk about freeing colors. +

      +
    +
  29. X Bitmaps and Pixmaps
  30. +

    + One thing many so-called "Multi-Media" applications need to od, + is display images. In the X world, this is done using bitmaps + and pixmaps. We have already seen some usage of them when + setting an icon for our application. Lets study them further, + and see how to draw these images inside a window, along side the + simple graphics and text we have seen so far. +

    +

    + One thing to note before delving further, is that XCB (nor Xlib) + supplies no means of manipulating popular image formats, such as + gif, png, jpeg or tiff. It is up to the programmer (or to higher + level graphics libraries) to translate these image formats into + formats that the X server is familiar with (x bitmaps and x + pixmaps). +

    +
      +
    1. What is a X Bitmap ? An X Pixmap ?
    2. +

      + An X bitmap is a two-color image stored in a format specific + to the X window system. When stored in a file, the bitmap data + looks like a C source file. It contains variables defining the + width and the height of the bitmap, an array containing the + bit values of the bitmap (the size of the array is + weight*height), and an optional hot-spot location (that will + be explained later, when discussing mouse cursors). +

      +

      + An X pixmap is a format used to stored images in the memory of + an X server. This format can store both black and white images + (such as x bitmaps) as well as color images. It is the only + image format supported by the X protocol, and any image to be + drawn on screen, should be first translated into this format. +

      +

      + In actuality, an X pixmap can be thought of as a window that + does not appear on the screen. Many graphics operations that + work on windows, will also work on pixmaps. Indeed, the type + of X pixmap in XCB is an Id like a window: +

      +
      +typedef struct {
      +    CARD32 xid;
      +} XCBPIXMAP;
      +
      +

      + In order to make the difference between a window and a pixmap, + XCB introduces a drawable type, which is a union +

      +
      +typedef union {
      +    XCBWINDOW window;
      +    XCBPIXMAP pixmap;
      +} XCBDRAWABLE;
      +
      +

      + in order to avoid confusion between a window and a pixmap.The + operations that will work indifferently on a window or a pixmap + will require a XCBDRAWABLE +

      +
      +

      + Remark: In Xlib, there is no specific difference between a + Drawable, a + Pixmap or a + Window: all are 32 bit long + integer. +

      +
      +
    3. Creating a pixmap
    4. +

      + Sometimes we want to create an un-initialized pixmap, so we + can later draw into it. This is useful for image drawing + programs (creating a new empty canvas will cause the creation + of a new pixmap on which the drawing can be stored). It is + also useful when reading various image formats: we load the + image data into memory, create a pixmap on the server, and + then draw the decoded image data onto that pixmap. +

      +

      + To create a new pixmap, we first ask the X server to give an + Id to our pixmap, with this function: +

      +
      +XCBPIXMAP XCBPIXMAPNew (XCBConnection *c);
      +
      +

      + Then, XCB supplies the following function to create new pixmaps: +

      +
      +XCBVoidCookie XCBCreatePixmap (XCBConnection *c,         /* Pointer to the XCBConnection structure */
      +                               CARD8          depth,     /* Depth of the screen */
      +			       XCBPIXMAP      pid,       /* Id of the pixmap */
      +			       XCBDRAWABLE    drawable,
      +			       CARD16         width,     /* Width of the window (in pixels) */
      +			       CARD16         height);   /* Height of the window (in pixels) */
      +
      +

      + TODO: Explain the drawable parameter, and give an + example (like xpoints.c) +

      +
    5. Drawing a pixmap in a window
    6. +

      + Once we got a handle to a pixmap, we can draw it on some + window, using the following function: +

      +
      +XCBVoidCookie XCBCopyArea (XCBConnection *c,             /* Pointer to the XCBConnection structure */
      +                           XCBDRAWABLE    src_drawable,  /* The Drawable we want to paste */
      +			   XCBDRAWABLE    dst_drawable,  /* The Drawable on which we copy the previous Drawable */
      +			   XCBGCONTEXT    gc,            /* A Graphic Context */
      +			   INT16          src_x,         /* Top left x coordinate of the region we want to copy */
      +			   INT16          src_y,         /* Top left y coordinate of the region we want to copy */
      +			   INT16          dst_x,         /* Top left x coordinate of the region where we want to copy */
      +			   INT16          dst_y,         /* Top left y coordinate of the region where we want to copy */
      +			   CARD16         width,         /* Width of the region we want to copy */
      +			   CARD16         height);       /* Height of the region we want to copy */
      +
      +

      + As you can see, we could copy the whole pixmap, as well as + only a given rectangle of the pixmap. This is useful to + optimize the drawing speed: we could copy only what we have + modified in the pixmap. +

      +

      + One important note should be made: it is possible to + create pixmaps with different depths on the same screen. When + we perform copy operations (a pixmaap onto a window, etc), we + should make sure that both source and target have the same + depth. If they have a different depth, the operation would + fail. The exception to this is if we copy a specific bit plane + of the source pixmap using the + XCBCopyPlane function. In such an + event, we can copy a specific plain to the target window (in + actuality, setting a specific bit in the color of each pixel + copied). This can be used to generate strange graphic effects + in widow, but beyond the scope of this tutorial. +

      +
    7. Freeing a pixmap
    8. +

      + Finally, when we are done using a given pixmap, we should free + it, in order to free resources of the X server. This is done + using this function: +

      +
      +XCBVoidCookie XCBFreePixmap (XCBConnection *c,        /* Pointer to the XCBConnection structure */
      +                             XCBPIXMAP      pixmap);  /* A given pixmap */
      +
      +

      + Of course, after having freed it, we must not try accessing + the pixmap again. +

      +

      + TODO: Give an example, or a link to xpoints.c +

      +
    +
  31. Translation of basic Xlib functions and macros
  32. +

    + The problem when you want to port an Xlib program to XCB is that + you don't know if the Xlib function that you want to "translate" + is a X Window one or an Xlib macro. In that section, we describe + a way to translate the usual functions or macros that Xlib + provides. It's usually just a member of a structure. +

    +
      +
    1. Members of the Display structure
    2. + In this section, we look at how to translate the macros that + returns some members of the Display + structure. They are obtain by using a function that requires a + XCBConnection * or a member of the + XCBConnSetupSuccessRep structure + (via the function XCBGetSetup), or + a function that requires that structure. +
        +
      1. ConnectionNumber
      2. +

        + This number is the file descriptor that connects the client + to the server. You just have to use that function: +

        +
        +int XCBGetFileDescriptor(XCBConnection *c);
        +
        +
      3. DefaultScreen
      4. +

        + That number is not stored by XCB. It is returned in the + second parameter of the function XCBConnect. + Hence, you have to store it yourself if you want to use + it. Then, to get the XCBSCREEN + structure, you have to iterate on the screens. + The equivalent function of the Xlib's + ScreenOfDisplay function can be + found below. OK, here is the + small piece of code to get that number: +

        +
        +XCBConnection *c;
        +int            screen_default_nbr;
        +
        +/* you pass the name of the display you want to XCBConnect */
        +
        +c = XCBConnect (display_name, &screen_default_nbr);
        +
        +/* screen_default_nbr contains now the number of the default screen */
        +
        +
      5. QLength
      6. +

        + Not documented yet. +

        +
      7. ScreenCount
      8. +

        + You get the count of screens with the functions + XCBGetSetup + and + XCBConnSetupSuccessRepRootsIter + (if you need to iterate): +

        +
        +XCBConnection *c;
        +int            screen_count;
        +
        +/* you init the connection */
        +
        +screen_count = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).rem;
        +
        +/* screen_count contains now the count of screens */
        +
        +

        + If you don't want to iterate over the screens, a better way + to get that number is to use + XCBConnSetupSuccessRepRootsLength: +

        +
        +XCBConnection *c;
        +int            screen_count;
        +
        +/* you init the connection */
        +
        +screen_count = XCBConnSetupSuccessRepRootsLength (XCBGetSetup (c));
        +
        +/* screen_count contains now the count of screens */
        +
        +
      9. ServerVendor
      10. +

        + You get the name of the vendor of the server hardware with + the functions XCBGetSetup + and + XCBConnSetupSuccessRepVendor. Beware + that, unlike Xlib, the string returned by XCB is not + necessarily null-terminaled: +

        +
        +XCBConnection *c;
        +char          *vendor = NULL;
        +int            length;
        +
        +/* you init the connection */
        +length = XCBConnSetupSuccessRepVendorLength (XCBGetSetup (c));
        +vendor = (char *)malloc (length + 1);
        +if (vendor)
        +memcpy (vendor, XCBConnSetupSuccessRepVendor (XCBGetSetup (c)), length);
        +vendor[length] = '\0';
        +
        +/* vendor contains now the name of the vendor. Must be freed when not used anymore */
        +
        +
      11. ProtocolVersion
      12. +

        + You get the major version of the protocol in the + XCBConnSetupSuccessRep + structure, with the function XCBGetSetup: +

        +
        +XCBConnection *c;
        +CARD16         protocol_major_version;
        +
        +/* you init the connection */
        +
        +protocol_major_version = XCBGetSetup (c)->protocol_major_version;
        +
        +/* protocol_major_version contains now the major version of the protocol */
        +
        +
      13. ProtocolRevision
      14. +

        + You get the minor version of the protocol in the + XCBConnSetupSuccessRep + structure, with the function XCBGetSetup: +

        +
        +XCBConnection *c;
        +CARD16         protocol_minor_version;
        +
        +/* you init the connection */
        +
        +protocol_minor_version = XCBGetSetup (c)->protocol_minor_version;
        +
        +/* protocol_minor_version contains now the minor version of the protocol */
        +
        +
      15. VendorRelease
      16. +

        + You get the number of the release of the server hardware in the + XCBConnSetupSuccessRep + structure, with the function XCBGetSetup: +

        +
        +XCBConnection *c;
        +CARD32         release_number;
        +
        +/* you init the connection */
        +
        +release_number = XCBGetSetup (c)->release_number;
        +
        +/* release_number contains now the number of the release of the server hardware */
        +
        +
      17. DisplayString
      18. +

        + The name of the display is not stored in XCB. You have to + store it by yourself. +

        +
      19. BitmapUnit
      20. +

        + You get the bitmap scanline unit in the + XCBConnSetupSuccessRep + structure, with the function XCBGetSetup: +

        +
        +XCBConnection *c;
        +CARD8          bitmap_format_scanline_unit;
        +
        +/* you init the connection */
        +
        +bitmap_format_scanline_unit = XCBGetSetup (c)->bitmap_format_scanline_unit;
        +
        +/* bitmap_format_scanline_unit contains now the bitmap scanline unit */
        +
        +
      21. BitmapBitOrder
      22. +

        + You get the bitmap bit order in the + XCBConnSetupSuccessRep + structure, with the function XCBGetSetup: +

        +
        +XCBConnection *c;
        +CARD8          bitmap_format_bit_order;
        +
        +/* you init the connection */
        +
        +bitmap_format_bit_order = XCBGetSetup (c)->bitmap_format_bit_order;
        +
        +/* bitmap_format_bit_order contains now the bitmap bit order */
        +
        +
      23. BitmapPad
      24. +

        + You get the bitmap scanline pad in the + XCBConnSetupSuccessRep + structure, with the function XCBGetSetup: +

        +
        +XCBConnection *c;
        +CARD8          bitmap_format_scanline_pad;
        +
        +/* you init the connection */
        +
        +bitmap_format_scanline_pad = XCBGetSetup (c)->bitmap_format_scanline_pad;
        +
        +/* bitmap_format_scanline_pad contains now the bitmap scanline pad */
        +
        +
      25. ImageByteOrder
      26. +

        + You get the image byte order in the + XCBConnSetupSuccessRep + structure, with the function XCBGetSetup: +

        +
        +XCBConnection *c;
        +CARD8          image_byte_order;
        +
        +/* you init the connection */
        +
        +image_byte_order = XCBGetSetup (c)->image_byte_order;
        +
        +/* image_byte_order contains now the image byte order */
        +
        +
      +
    3. ScreenOfDisplay related functions
    4. +

      + in Xlib, ScreenOfDisplay returns a + Screen structure that contains + several characteristics of your screen. XCB has a similar + structure (XCBSCREEN), + but the way to obtain it is a bit different. With + Xlib, you just provide the number of the screen and you grab it + from an array. With XCB, you iterate over all the screens to + obtain the one you want. The complexity of this operation is + O(n). So the best is to store this structure if you often use + it. See ScreenOfDisplay just below. +

      +

      + Xlib provides generally two functions to obtain the characteristics + related to the screen. One with the display and the number of + the screen, which calls ScreenOfDisplay, + and the other that uses the Screen structure. + This might be a bit confusing. As mentioned above, with XCB, it + is better to store the XCBSCREEN + structure. Then, you have to read the members of this + structure. That's why the Xlib functions are put by pairs (or + more) as, with XCB, you will use the same code. +

      +
        +
      1. ScreenOfDisplay
      2. +

        + This function returns the Xlib Screen + structure. With XCB, you iterate over all thee screens and + once you get the one you want, you return it: +

        +
        
        +XCBSCREEN *ScreenOfDisplay (XCBConnection *c,
        +                            int            screen)
        +{
        +  XCBSCREENIter iter;
        +
        +  iter = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c));
        +  for (; iter.rem; --screen, XCBSCREENNext (&iter))
        +    if (screen == 0)
        +      return iter.data;
        +
        +  return NULL;
        +}
        +
        +

        + As mentioned above, you might want to store the value + returned by this function. +

        +

        + All the functions below will use the result of that + fonction, as they just grab a specific member of the + XCBSCREEN structure. +

        +
      3. DefaultScreenOfDisplay
      4. +

        + It is the default screen that you obtain when you connect to + the X server. It suffices to call the ScreenOfDisplay + function above with the connection and the number of the + default screen. +

        +
        +XCBConnection *c;
        +int            screen_default_nbr;
        +XCBSCREEN     *default_screen;  /* the returned default screen */
        +
        +/* you pass the name of the display you want to XCBConnect */
        +
        +c = XCBConnect (display_name, &screen_default_nbr);
        +default_screen = ScreenOfDisplay (c, screen_default_nbr);
        +
        +/* default_screen contains now the default root window, or a NULL window if no screen is found */
        +
        +
      5. RootWindow / RootWindowOfScreen
      6. +

        +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +XCBWINDOW      root_window = { 0 };  /* the returned window */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  root_window = screen->root;
        +
        +/* root_window contains now the root window, or a NULL window if no screen is found */
        +
        +
      7. DefaultRootWindow
      8. +

        + It is the root window of the default screen. So, you call + ScreenOfDisplay with the + default screen number and you get the + root window as above: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_default_nbr;
        +XCBWINDOW      root_window = { 0 };  /* the returned root window */
        +
        +/* you pass the name of the display you want to XCBConnect */
        +
        +c = XCBConnect (display_name, &screen_default_nbr);
        +screen = ScreenOfDisplay (c, screen_default_nbr);
        +if (screen)
        +  root_window = screen->root;
        +
        +/* root_window contains now the default root window, or a NULL window if no screen is found */
        +
        +
      9. DefaultVisual / DefaultVisualOfScreen
      10. +

        + While a Visual is, in Xlib, a structure, in XCB, there are + two types: XCBVISUALID, which is + the Id of the visual, and XCBVISUALTYPE, + which corresponds to the Xlib Visual. To get the Id of the + visual of a screen, just get the + root_visual + member of a XCBSCREEN: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +XCBVISUALID    root_visual = { 0 };    /* the returned visual Id */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  root_visual = screen->root_visual;
        +
        +/* root_visual contains now the value of the Id of the visual, or a NULL visual if no screen is found */
        +
        +

        + To get the XCBVISUALTYPE + structure, it's a bit less easier. You have to get the + XCBSCREEN structure that you want, + get its root_visual member, + then iterate on the XCBDEPTHs + and the XCBVISUALTYPEs, and compare + the XCBVISUALID of these XCBVISUALTYPEs: + with root_visual: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +XCBVISUALID    root_visual = { 0 };
        +XCBVISUATYPE  *visual_type = NULL;    /* the returned visual type */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  {
        +    XCBDEPTHIter depth_iter;
        +
        +    depth_iter = XCBSCREENAllowedDepthsIter (screen);
        +    for (; depth_iter.rem; XCBDEPTHNext (&depth_iter))
        +      {
        +        XCBVISUALTYPEIter visual_iter;
        +
        +        visual_iter = XCBDEPTHVisualsIter (depth_iter.data);
        +        for (; visual_iter.rem; XCBVISUALTYPENext (&visual_iter))
        +          {
        +            if (screen->root_visual.id == visual_iter.data->visual_id.id)
        +              {
        +                visual_type = visual_iter.data;
        +                break;
        +              }
        +          }
        +      }
        +  }
        +
        +/* visual_type contains now the visual structure, or a NULL visual structure if no screen is found */
        +
        +
      11. DefaultGC / DefaultGCOfScreen
      12. +

        + This default Graphic Context is just a newly created Graphic + Context, associated to the root window of a + XCBSCREEN, + using the black white pixels of that screen: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +XCBGCONTEXT    gc = { 0 };    /* the returned default graphic context */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  {
        +    XCBDRAWABLE draw;
        +    CARD32      mask;
        +    CARD32      values[2];
        +
        +    gc = XCBGCONTEXTNew (c);
        +    draw.window = screen->root;
        +    mask = GCForeground | GCBackground;
        +    values[0] = screen->black_pixel;
        +    values[1] = screen->white_pixel;
        +    XCBCreateGC (c, gc, draw, mask, values);
        +  }
        +
        +/* gc contains now the default graphic context */
        +
        +
      13. BlackPixel / BlackPixelOfScreen
      14. +

        + It is the Id of the black pixel, which is in the structure + of an XCBSCREEN. +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD32         black_pixel = 0;    /* the returned black pixel */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  black_pixel = screen->black_pixel;
        +
        +/* black_pixel contains now the value of the black pixel, or 0 if no screen is found */
        +
        +
      15. WhitePixel / WhitePixelOfScreen
      16. +

        + It is the Id of the white pixel, which is in the structure + of an XCBSCREEN. +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD32         white_pixel = 0;    /* the returned white pixel */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  white_pixel = screen->white_pixel;
        +
        +/* white_pixel contains now the value of the white pixel, or 0 if no screen is found */
        +
        +
      17. DisplayWidth / WidthOfScreen
      18. +

        + It is the width in pixels of the screen that you want, and + which is in the structure of the corresponding + XCBSCREEN. +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD32         width_in_pixels = 0;    /* the returned width in pixels */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  width_in_pixels = screen->width_in_pixels;
        +
        +/* width_in_pixels contains now the width in pixels, or 0 if no screen is found */
        +
        +
      19. DisplayHeight / HeightOfScreen
      20. +

        + It is the height in pixels of the screen that you want, and + which is in the structure of the corresponding + XCBSCREEN. +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD32         height_in_pixels = 0;    /* the returned height in pixels */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  height_in_pixels = screen->height_in_pixels;
        +
        +/* height_in_pixels contains now the height in pixels, or 0 if no screen is found */
        +
        +
      21. DisplayWidthMM / WidthMMOfScreen
      22. +

        + It is the width in millimeters of the screen that you want, and + which is in the structure of the corresponding + XCBSCREEN. +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD32         width_in_millimeters = 0;    /* the returned width in millimeters */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  width_in_millimeters = screen->width_in_millimeters;
        +
        +/* width_in_millimeters contains now the width in millimeters, or 0 if no screen is found */
        +
        +
      23. DisplayHeightMM / HeightMMOfScreen
      24. +

        + It is the height in millimeters of the screen that you want, and + which is in the structure of the corresponding + XCBSCREEN. +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD32         height_in_millimeters = 0;    /* the returned height in millimeters */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  height_in_millimeters = screen->height_in_millimeters;
        +
        +/* height_in_millimeters contains now the height in millimeters, or 0 if no screen is found */
        +
        +
      25. DisplayPlanes / DefaultDepth / DefaultDepthOfScreen / PlanesOfScreen
      26. +

        + It is the depth (in bits) of the root window of the + screen. You get it from the XCBSCREEN structure. +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD8          root_depth = 0;  /* the returned depth of the root window */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  root_depth = screen->root_depth;
        +
        +/* root_depth contains now the depth of the root window, or 0 if no screen is found */
        +
        +
      27. DefaultColormap / DefaultColormapOfScreen
      28. +

        + This is the default colormap of the screen (and not the + (default) colormap of the default screen !). As usual, you + get it from the XCBSCREEN structure: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +XCBCOLORMAP    default_colormap = { 0 };  /* the returned default colormap */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  default_colormap = screen->default_colormap;
        +
        +/* default_colormap contains now the default colormap, or a NULL colormap if no screen is found */
        +
        +
      29. MinCmapsOfScreen
      30. +

        + You get the minimum installed colormaps in the XCBSCREEN structure: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD16         min_installed_maps = 0;  /* the returned minimum installed colormaps */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  min_installed_maps = screen->min_installed_maps;
        +
        +/* min_installed_maps contains now the minimum installed colormaps, or 0 if no screen is found */
        +
        +
      31. MaxCmapsOfScreen
      32. +

        + You get the maximum installed colormaps in the XCBSCREEN structure: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD16         max_installed_maps = 0;  /* the returned maximum installed colormaps */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  max_installed_maps = screen->max_installed_maps;
        +
        +/* max_installed_maps contains now the maximum installed colormaps, or 0 if no screen is found */
        +
        +
      33. DoesSaveUnders
      34. +

        + You know if save_unders is set, + by looking in the XCBSCREEN structure: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +BOOL           save_unders = 0;  /* the returned value of save_unders */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  save_unders = screen->save_unders;
        +
        +/* save_unders contains now the value of save_unders, or FALSE if no screen is found */
        +
        +
      35. DoesBackingStore
      36. +

        + You know the value of backing_stores, + by looking in the XCBSCREEN structure: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +BYTE           backing_stores = 0;  /* the returned value of backing_stores */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  backing_stores = screen->backing_stores;
        +
        +/* backing_stores contains now the value of backing_stores, or FALSE if no screen is found */
        +
        +
      37. EventMaskOfScreen
      38. +

        + To get the current input masks, + you look in the XCBSCREEN structure: +

        +
        +XCBConnection *c;
        +XCBSCREEN     *screen;
        +int            screen_nbr;
        +CARD32         current_input_masks = 0;  /* the returned value of current input masks */
        +
        +/* you init the connection and screen_nbr */
        +
        +screen = ScreenOfDisplay (c, screen_nbr);
        +if (screen)
        +  current_input_masks = screen->current_input_masks;
        +
        +/* current_input_masks contains now the value of the current input masks, or FALSE if no screen is found */
        +
        +
      +
    5. Miscellaneous macros
    6. +
        +
      1. DisplayOfScreen
      2. +

        + in Xlib, the Screen structure + stores its associated Display + structure. This is not the case in the X Window protocol, + hence, it's also not the case in XCB. So you have to store + it by yourself. +

        +
      3. DisplayCells / CellsOfScreen
      4. +

        + To get the colormap entries, + you look in the XCBVISUALTYPE + structure, that you grab like here: +

        +
        +XCBConnection *c;
        +XCBVISUALTYPE *visual_type;
        +CARD16         colormap_entries = 0;  /* the returned value of the colormap entries */
        +
        +/* you init the connection and visual_type */
        +
        +if (visual_type)
        +  colormap_entries = visual_type->colormap_entries;
        +
        +/* colormap_entries contains now the value of the colormap entries, or FALSE if no screen is found */
        +
        +
      +
    +
+
+ + + diff --git a/doc/tutorial/xcb.css b/doc/tutorial/xcb.css new file mode 100755 index 0000000..84352c5 --- /dev/null +++ b/doc/tutorial/xcb.css @@ -0,0 +1,82 @@ +body +{ + background-color: #dddddd; + color: #000000; + padding: 8px; + margin: 0px; +} +div.title +{ + text-align: center; + font-weight: bold; + font-size: 28px; +} +div.emph +{ + text-align: left; + font-weight: bold; +} +div.section li.title +{ + font-weight: bold; + font-size: 22px; +} +div.section li.subtitle +{ + font-weight: bold; + font-size: 18px; +} +div.section li.subsubtitle +{ + font-weight: bold; + font-size: 16px; +} +div.comp +{ + border: thin solid #000000; + background-color: #ffffe0; + padding: 14px; +} +div.comp div.title +{ + font-weight: bold; + font-size: 16px; + text-align: center; +} +div.comp div.xlib +{ + font-family: monospace; + position: absolute; + width: 49%; + margin-left: 0px; + margin-top: 10px; +} +div.comp div.xcb +{ + font-family: monospace; + position: relative; + margin-left: 51%; + margin-top: 10px; +} +pre.code +{ + border: thin solid #000000; + background-color: #efefef; + padding: 4px; + text-align: left; + font-size: 10; +} +pre.text +{ + border: thin solid #000000; + background-color: #efefef; + padding: 4px; + text-align: left; + font-size: 10; +} +span.code +{ + font-family: monospace; + font-size: 10; +} + diff --git a/src/.cvsignore b/src/.cvsignore new file mode 100644 index 0000000..adf4164 --- /dev/null +++ b/src/.cvsignore @@ -0,0 +1,17 @@ +.deps +.libs +Makefile +Makefile.in +config.h +config.h.in +stamp-h1 +*.lo +*.loT +*.la +xproto.c +xproto.h +xcb_types.c +xcb_types.h +extensions +X11 +check_all diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..8d43475 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,83 @@ +lib_LTLIBRARIES = libXCB.la + +EXTHEADERS = \ + extensions/bigreq.h \ + extensions/composite.h \ + extensions/damage.h \ + extensions/glx.h \ + extensions/shm.h \ + extensions/shape.h \ + extensions/randr.h \ + extensions/record.h \ + extensions/render.h \ + extensions/res.h \ + extensions/dpms.h \ + extensions/sync.h \ + extensions/xc_misc.h \ + extensions/xevie.h \ + extensions/xf86dri.h \ + extensions/xfixes.h \ + extensions/xprint.h \ + extensions/xv.h \ + extensions/xvmc.h +EXTSOURCES = \ + extensions/bigreq.c \ + extensions/composite.c \ + extensions/damage.c \ + extensions/glx.c \ + extensions/shm.c \ + extensions/shape.c \ + extensions/randr.c \ + extensions/record.c \ + extensions/render.c \ + extensions/res.c \ + extensions/dpms.c \ + extensions/sync.c \ + extensions/xc_misc.c \ + extensions/xevie.c \ + extensions/xf86dri.c \ + extensions/xfixes.c \ + extensions/xprint.c \ + extensions/xv.c \ + extensions/xvmc.c +EXTENSIONS = $(EXTSOURCES) $(EXTHEADERS) + +COREHEADERS = xproto.h xcb_types.h +CORESOURCES = xproto.c xcb_types.c +COREPROTO = $(CORESOURCES) $(COREHEADERS) + +xcbinclude_HEADERS = xcb.h xcbext.h xcbxlib.h $(COREHEADERS) $(EXTHEADERS) + +CFLAGS = +AM_CFLAGS = -include config.h $(CDEBUGFLAGS) $(XCBPROTO_CFLAGS) $(XPROTO_CFLAGS) $(XAU_CFLAGS) +libXCB_la_LIBADD = $(XCBPROTO_LIBS) $(XPROTO_LIBS) $(XAU_LIBS) +libXCB_la_SOURCES = \ + xcb_conn.c xcb_out.c xcb_in.c xcb_ext.c xcb_xid.c \ + xcb_list.c xcb_util.c xcb_xlib.c xcb_auth.c xcb_des.c \ + $(COREPROTO) $(EXTENSIONS) + +xcb_des.c: + touch xcb_des.c + +BUILT_SOURCES = $(COREPROTO) $(EXTENSIONS) +CLEANFILES = $(COREPROTO) $(EXTENSIONS) +clean-local: + rmdir extensions || true + +vpath %.xml $(XCBPROTO_XCBINCLUDEDIR) $(XCBPROTO_XCBINCLUDEDIR)/extensions + +%.h: %.xml c-client.xsl + @n=`dirname $*`; test -d $$n || (echo mkdir $$n; mkdir $$n) + $(XSLTPROC) --stringparam mode header \ + --stringparam base-path $(XCBPROTO_XCBINCLUDEDIR)/ \ + --stringparam extension-path \ + $(XCBPROTO_XCBINCLUDEDIR)/extensions/ \ + -o $@ $(srcdir)/c-client.xsl $< + +%.c: %.xml c-client.xsl + @n=`dirname $*`; test -d $$n || (echo mkdir $$n; mkdir $$n) + $(XSLTPROC) --stringparam mode source \ + --stringparam base-path $(XCBPROTO_XCBINCLUDEDIR)/ \ + --stringparam extension-path \ + $(XCBPROTO_XCBINCLUDEDIR)/extensions/ \ + -o $@ $(srcdir)/c-client.xsl $< diff --git a/src/c-client.xsl b/src/c-client.xsl new file mode 100644 index 0000000..903895d --- /dev/null +++ b/src/c-client.xsl @@ -0,0 +1,1301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { "" } + + + + return XCBGetExtensionData(c, &XCBId); + + + + + + + + + + + _ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + XCB + + + + + + Multiple definitions of type " + + " found. + + + + + + + + + + + + No definitions of type " + + " found + + , and it is not a known core type + + . + + + + + + + + + + XCB + + + + + + Void + + + Cookie + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + return (XCBRep *) XCBWaitForReply(c, cookie.sequence, e); + + + + + + + + + + + + + XCB ret; + ret.xid = XCBGenerateID(c); + return ret; + + + + + + + union + + + + + + + + + + + + Event + + + Error + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + length + 2 + + + + + + + + + Encountered a list with no length expresssion outside a request or reply. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + const + + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unions must be fixed length. + + + + + + + + + + + + + + + + + + + + + + + static const XCBProtocolRequest xcb_req = { + + /* count */ , + /* ext */ + + &XCB + + Id + + 0 + , + /* opcode */ , + /* isvoid */ + + }; + + + struct iovec xcb_parts[]; + xcb_ret; + xcb_out; + + + + + + xcb_parts[0].iov_base = &xcb_out; + xcb_parts[0].iov_len = sizeof(xcb_out); + + + xcb_parts[].iov_base = (void *) ; + xcb_parts[].iov_len = + * sizeof( + + ) + ; + + + XCBSendRequest(c, &xcb_ret.sequence, xcb_parts, &xcb_req); + return xcb_ret; + + + + + xcb_out. + + = + + ; + + + + + + xcb_out. + + = + + ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + R + 1 + + + + End(Iter(R)) + + + End(R) + + + + + + + + + + + + + + + + + return ( *) (); + + + XCBGenericIter prev = ; + return ( *) ((char *) prev.data + XCB_TYPE_PAD(, prev.index)); + + + + + + + return + + ; + + + + + + Iter i; + + + i.data = ( *) (); + + + XCBGenericIter prev = ; + i.data = ( *) ((char *) prev.data + XCB_TYPE_PAD(, prev.index)); + + + i.rem = + + ; + i.index = (char *) i.data - (char *) R; + return i; + + + + + + char + + + + + + XCBGenericIter i; + + + i.data = (( *) ()) + ( + + ); + + + XCBGenericIter child = ; + i.data = (( *) child.data) + ( + + ); + + + i.rem = 0; + i.index = (char *) i.data - (char *) R; + return i; + + + + + + + + + + *R = i->data; + XCBGenericIter child = ; + --i->rem; + i->data = ( *) child.data; + i->index = child.index; + + + --i->rem; + ++i->data; + i->index += sizeof(); + + + + + + XCBGenericIter ret; + + + while(i.rem > 0) + + Next(&i); + + ret.data = i.data; + ret.rem = i.rem; + ret.index = i.index; + + + ret.data = i.data + i.rem; + ret.index = i.index + ((char *) ret.data - (char *) i.data); + ret.rem = 0; + + + return ret; + + + + + + + + Error: This stylesheet requires the EXSL node-set extension. + + + + Error: Parameter "mode" must be "header" or "source". + + + + + + + ___H + +/* + * This file generated automatically from +.xml by c-client.xsl using XSLT. + * Edit at your peril. + */ + + + +#ifndef +#define + +#include "xcb.h" + +#include ".h" + + + + + + + +#include <assert.h> +#include "xcbext.h" +#include ".h" + + + + + + + +#endif + + + + + + + + + #define + + + + + + + + + + + extern + + const char + + [] + + = " + + " + + ; + + + + + + extern + + + + = + + + ; + + + + + + + + + typedef + + + + ; + + + + + + + + + + + + + typedef + struct + { + + + + + + + ; + + + } + + ; + + + + + + + + typedef enum { + + + , + + + + + + + = + + + + + + + +} ; + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + ) + + ; + + + + + +{ + + + + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + + + + + + + + + ) + + + + + + ( + + + + + + + + + + + ) + + + + + + Invalid element in expression: + + + + + + + + + + + + + + + + + [ + + ] + + + + + + + + + + + pad + + + + + + [ + + ] + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + diff --git a/src/xcb.h b/src/xcb.h new file mode 100644 index 0000000..8dd308a --- /dev/null +++ b/src/xcb.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2001-2004 Bart Massey, Jamey Sharp, and Josh Triplett. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#ifndef __XCB_H +#define __XCB_H +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define deprecated __attribute__((__deprecated__)) +#else +#define deprecated +#endif + +/* Pre-defined constants */ + +/* current protocol version */ +#define X_PROTOCOL 11 + +/* current minor version */ +#define X_PROTOCOL_REVISION 0 + +/* X_TCP_PORT + display number = server port for TCP transport */ +#define X_TCP_PORT 6000 + +#define XCB_TYPE_PAD(T,I) (-(I) & (sizeof(T) > 4 ? 3 : sizeof(T) - 1)) + + +/* Opaque structures */ + +typedef struct XCBConnection XCBConnection; + + +/* Other types */ + +typedef struct { + void *data; + int rem; + int index; +} XCBGenericIter; + +typedef struct { + BYTE response_type; + CARD8 pad0; + CARD16 sequence; + CARD32 length; +} XCBGenericRep; + +typedef struct { + BYTE response_type; + CARD8 pad0; + CARD16 sequence; +} XCBGenericEvent; + +typedef struct { + BYTE response_type; + BYTE error_code; + CARD16 sequence; +} XCBGenericError; + +typedef struct { + unsigned int sequence; +} XCBVoidCookie; + + +/* Include the generated xproto and xcb_types headers. */ +#include "xcb_types.h" +#include "xproto.h" + + +/* xcb_auth.c */ + +typedef struct XCBAuthInfo { + int namelen; + char *name; + int datalen; + char *data; +} XCBAuthInfo; + +int XCBGetAuthInfo(int fd, XCBAuthInfo *info) deprecated; + + +/* xcb_out.c */ + +int XCBFlush(XCBConnection *c); +CARD32 XCBGetMaximumRequestLength(XCBConnection *c); + + +/* xcb_in.c */ + +XCBGenericEvent *XCBWaitEvent(XCBConnection *c) deprecated; +XCBGenericEvent *XCBWaitForEvent(XCBConnection *c); +XCBGenericEvent *XCBPollForEvent(XCBConnection *c, int *error); +unsigned int XCBGetRequestRead(XCBConnection *c); + + +/* xcb_ext.c */ + +typedef struct XCBExtension XCBExtension; + +/* Do not free the returned XCBQueryExtensionRep - on return, it's aliased + * from the cache. */ +const XCBQueryExtensionRep *XCBGetExtensionData(XCBConnection *c, XCBExtension *ext); + +void XCBPrefetchExtensionData(XCBConnection *c, XCBExtension *ext); + + +/* xcb_conn.c */ + +XCBConnSetupSuccessRep *XCBGetSetup(XCBConnection *c); +int XCBGetFileDescriptor(XCBConnection *c); + +XCBConnection *XCBConnectToFD(int fd, XCBAuthInfo *auth_info); +void XCBDisconnect(XCBConnection *c); + + +/* xcb_util.c */ + +int XCBParseDisplay(const char *name, char **host, int *display, int *screen); +int XCBOpen(const char *host, int display) deprecated; +int XCBOpenTCP(const char *host, unsigned short port) deprecated; +int XCBOpenUnix(const char *file) deprecated; + +XCBConnection *XCBConnectBasic(void) deprecated; +XCBConnection *XCBConnect(const char *displayname, int *screenp); +XCBConnection *XCBConnectToDisplayWithAuthInfo(const char *display, XCBAuthInfo *auth, int *screen); + +int XCBSync(XCBConnection *c, XCBGenericError **e); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/xcb_auth.c b/src/xcb_auth.c new file mode 100644 index 0000000..9f2cb5a --- /dev/null +++ b/src/xcb_auth.c @@ -0,0 +1,296 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Authorization systems for the X protocol. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xcb.h" +#include "xcbint.h" + +#ifdef HAS_AUTH_XA1 +#include "xcb_des.h" +#endif + +enum auth_protos { +#ifdef HAS_AUTH_XA1 + AUTH_XA1, +#endif + AUTH_MC1, + N_AUTH_PROTOS +}; + +static char *authnames[N_AUTH_PROTOS] = { +#ifdef HAS_AUTH_XA1 + "XDM-AUTHORIZATION-1", +#endif + "MIT-MAGIC-COOKIE-1", +}; + +#ifdef HAS_AUTH_XA1 + +static int next_nonce(void) +{ + static int nonce = 0; + static pthread_mutex_t nonce_mutex = PTHREAD_MUTEX_INITIALIZER; + int ret; + pthread_mutex_lock(&nonce_mutex); + ret = nonce++; + pthread_mutex_unlock(&nonce_mutex); + return ret; +} + +/* + * This code and the code it calls is taken from libXdmcp, + * specifically from Wrap.c, Wrap.h, and Wraphelp.c. The US + * has changed, thank goodness, and it should be OK to bury + * DES code in an open source product without a maze of + * twisty wrapper functions stored offshore. Or maybe + * not. --Bart Massey 2003/11/5 + */ + +static void +Wrap ( + des_cblock input, + des_cblock key, + des_cblock output, + int bytes) +{ + int i, j; + int len; + des_cblock tmp; + des_cblock expand_key; + des_key_schedule schedule; + + XCBDESKeyToOddParity (key, expand_key); + XCBDESKeySchedule (expand_key, schedule); + for (j = 0; j < bytes; j += 8) + { + len = 8; + if (bytes - j < len) + len = bytes - j; + /* block chaining */ + for (i = 0; i < len; i++) + { + if (j == 0) + tmp[i] = input[i]; + else + tmp[i] = input[j + i] ^ output[j - 8 + i]; + } + for (; i < 8; i++) + { + if (j == 0) + tmp[i] = 0; + else + tmp[i] = 0 ^ output[j - 8 + i]; + } + XCBDESEncrypt (tmp, (output + j), schedule, 1); + } +} + +#endif + +static size_t memdup(char **dst, void *src, size_t len) +{ + if(len) + *dst = malloc(len); + else + *dst = 0; + if(!*dst) + return 0; + memcpy(*dst, src, len); + return len; +} + +static int authname_match(enum auth_protos kind, char *name, int namelen) +{ + if(strlen(authnames[kind]) != namelen) + return 0; + if(memcmp(authnames[kind], name, namelen)) + return 0; + return 1; +} + +static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen) +{ + char *addr = 0; + int addrlen = 0; + unsigned short family; + char hostnamebuf[256]; /* big enough for max hostname */ + char dispbuf[40]; /* big enough to hold more than 2^64 base 10 */ + char *display; + int authnamelens[N_AUTH_PROTOS]; + int i; + + family = FamilyLocal; /* 256 */ + switch (sockname->sa_family) { + case AF_INET: + /*block*/ { + struct sockaddr_in *si = (struct sockaddr_in *) sockname; + assert(sizeof(*si) == socknamelen); + addr = (char *) &si->sin_addr; + addrlen = 4; + if (ntohl(si->sin_addr.s_addr) != 0x7f000001) + family = FamilyInternet; /* 0 */ + snprintf(dispbuf, sizeof(dispbuf), "%d", ntohs(si->sin_port) - X_TCP_PORT); + display = dispbuf; + } + break; + case AF_UNIX: + /*block*/ { + struct sockaddr_un *su = (struct sockaddr_un *) sockname; + assert(sizeof(*su) >= socknamelen); + display = strrchr(su->sun_path, 'X'); + if (display == 0) + return 0; /* sockname is mangled somehow */ + display++; + } + break; + default: + return 0; /* cannot authenticate this family */ + } + if (family == FamilyLocal) { + if (gethostname(hostnamebuf, sizeof(hostnamebuf)) == -1) + return 0; /* do not know own hostname */ + addr = hostnamebuf; + addrlen = strlen(addr); + } + + for (i = 0; i < N_AUTH_PROTOS; i++) + authnamelens[i] = strlen(authnames[i]); + return XauGetBestAuthByAddr (family, + (unsigned short) addrlen, addr, + (unsigned short) strlen(display), display, + N_AUTH_PROTOS, authnames, authnamelens); +} + +#ifdef HAS_AUTH_XA1 +static void do_append(char *buf, int *idxp, void *val, size_t valsize) { + memcpy(buf + *idxp, val, valsize); + *idxp += valsize; +} +#endif + +static int compute_auth(XCBAuthInfo *info, Xauth *authptr, struct sockaddr *sockname) +{ + if (authname_match(AUTH_MC1, authptr->name, authptr->name_length)) { + info->datalen = memdup(&info->data, authptr->data, authptr->data_length); + if(!info->datalen) + return 0; + return 1; + } +#ifdef HAS_AUTH_XA1 +#define APPEND(buf,idx,val) do_append((buf),&(idx),(val),sizeof(val)) + if (authname_match(AUTH_XA1, authptr->name, authptr->name_length)) { + int j; + + info->data = malloc(192 / 8); + if(!info->data) + return 0; + + for (j = 0; j < 8; j++) + info->data[j] = authptr->data[j]; + switch(sockname->sa_family) { + case AF_INET: + /*block*/ { + struct sockaddr_in *si = (struct sockaddr_in *) sockname; + APPEND(info->data, j, si->sin_addr.s_addr); + APPEND(info->data, j, si->sin_port); + } + break; + case AF_UNIX: + /*block*/ { + long fakeaddr = htonl(0xffffffff - next_nonce()); + short fakeport = htons(getpid()); + APPEND(info->data, j, fakeaddr); + APPEND(info->data, j, fakeport); + } + break; + default: + free(info->data); + return 0; /* do not know how to build this */ + } + { + long now; + time(&now); + now = htonl(now); + APPEND(info->data, j, now); + } + assert(j <= 192 / 8); + while (j < 192 / 8) + info->data[j++] = 0; + info->datalen = j; + Wrap (info->data, authptr->data + 8, info->data, info->datalen); + return 1; + } +#undef APPEND +#endif + + return 0; /* Unknown authorization type */ +} + +int XCBGetAuthInfo(int fd, XCBAuthInfo *info) +{ + /* code adapted from Xlib/ConnDis.c, xtrans/Xtranssocket.c, + xtrans/Xtransutils.c */ + char sockbuf[sizeof(struct sockaddr) + MAXPATHLEN]; + unsigned int socknamelen = sizeof(sockbuf); /* need extra space */ + struct sockaddr *sockname = (struct sockaddr *) &sockbuf; + Xauth *authptr = 0; + int ret = 1; + + /* ensure info has reasonable contents */ + /* XXX This should be removed, but Jamey depends on it + somehow but can't remember how. Principle: don't touch + someone else's data if you're borken. */ + info->namelen = info->datalen = 0; + info->name = info->data = 0; + + if (getpeername(fd, sockname, &socknamelen) == -1) + return 0; /* can only authenticate sockets */ + + authptr = get_authptr(sockname, socknamelen); + if (authptr == 0) + return 0; /* cannot find good auth data */ + + info->namelen = memdup(&info->name, authptr->name, authptr->name_length); + if(info->namelen) + ret = compute_auth(info, authptr, sockname); + if(!ret) + { + free(info->name); + info->name = 0; + info->namelen = 0; + } + XauDisposeAuth(authptr); + return ret; +} diff --git a/src/xcb_conn.c b/src/xcb_conn.c new file mode 100644 index 0000000..0148abf --- /dev/null +++ b/src/xcb_conn.c @@ -0,0 +1,239 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Connection management: the core of XCB. */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xcb.h" +#include "xcbint.h" + +static int write_setup(XCBConnection *c, XCBAuthInfo *auth_info) +{ + XCBConnSetupReq out; + struct iovec parts[3]; + int count = 0; + int endian = 0x01020304; + int ret; + + memset(&out, 0, sizeof(out)); + + /* B = 0x42 = MSB first, l = 0x6c = LSB first */ + if(htonl(endian) == endian) + out.byte_order = 0x42; + else + out.byte_order = 0x6c; + out.protocol_major_version = X_PROTOCOL; + out.protocol_minor_version = X_PROTOCOL_REVISION; + out.authorization_protocol_name_len = 0; + out.authorization_protocol_data_len = 0; + parts[count].iov_len = sizeof(XCBConnSetupReq); + parts[count++].iov_base = &out; + + if(auth_info) + { + parts[count].iov_len = out.authorization_protocol_name_len = auth_info->namelen; + parts[count++].iov_base = auth_info->name; + parts[count].iov_len = out.authorization_protocol_data_len = auth_info->datalen; + parts[count++].iov_base = auth_info->data; + } + + pthread_mutex_lock(&c->iolock); + _xcb_out_write_block(c, parts, count); + ret = _xcb_out_flush(c); + pthread_mutex_unlock(&c->iolock); + if(ret <= 0) + return 0; + return 1; +} + +static int read_setup(XCBConnection *c) +{ + /* Read the server response */ + c->setup = malloc(sizeof(XCBConnSetupGenericRep)); + if(!c->setup) + return 0; + + if(_xcb_read_block(c->fd, c->setup, sizeof(XCBConnSetupGenericRep)) != sizeof(XCBConnSetupGenericRep)) + return 0; + + { + void *tmp = realloc(c->setup, c->setup->length * 4 + sizeof(XCBConnSetupGenericRep)); + if(!tmp) + return 0; + c->setup = tmp; + } + + if(_xcb_read_block(c->fd, (char *) c->setup + sizeof(XCBConnSetupGenericRep), c->setup->length * 4) <= 0) + return 0; + + /* 0 = failed, 2 = authenticate, 1 = success */ + switch(c->setup->status) + { + case 0: /* failed */ + { + XCBConnSetupFailedRep *setup = (XCBConnSetupFailedRep *) c->setup; + write(STDERR_FILENO, XCBConnSetupFailedRepReason(setup), XCBConnSetupFailedRepReasonLength(setup)); + return 0; + } + + case 2: /* authenticate */ + { + XCBConnSetupAuthenticateRep *setup = (XCBConnSetupAuthenticateRep *) c->setup; + write(STDERR_FILENO, XCBConnSetupAuthenticateRepReason(setup), XCBConnSetupAuthenticateRepReasonLength(setup)); + return 0; + } + } + + return 1; +} + +/* Public interface */ + +XCBConnSetupSuccessRep *XCBGetSetup(XCBConnection *c) +{ + /* doesn't need locking because it's never written to. */ + return c->setup; +} + +int XCBGetFileDescriptor(XCBConnection *c) +{ + /* doesn't need locking because it's never written to. */ + return c->fd; +} + +XCBConnection *XCBConnectToFD(int fd, XCBAuthInfo *auth_info) +{ + XCBConnection* c; + + c = calloc(1, sizeof(XCBConnection)); + if(!c) + return 0; + + c->fd = fd; + + if(!( + _xcb_set_fd_flags(fd) && + pthread_mutex_init(&c->iolock, 0) == 0 && + _xcb_in_init(&c->in) && + _xcb_out_init(&c->out) && + write_setup(c, auth_info) && + read_setup(c) && + _xcb_ext_init(c) && + _xcb_xid_init(c) + )) + { + XCBDisconnect(c); + return 0; + } + + return c; +} + +void XCBDisconnect(XCBConnection *c) +{ + if(!c) + return; + + free(c->setup); + close(c->fd); + + pthread_mutex_destroy(&c->iolock); + _xcb_in_destroy(&c->in); + _xcb_out_destroy(&c->out); + + _xcb_ext_destroy(c); + _xcb_xid_destroy(c); + + free(c); +} + +/* Private interface */ + +int _xcb_conn_wait(XCBConnection *c, const int should_write, pthread_cond_t *cond) +{ + int ret = 1; + fd_set rfds, wfds; +#if USE_THREAD_ASSERT + static __thread int already_here = 0; + + assert(!already_here); + ++already_here; +#endif + + _xcb_assert_valid_sequence(c); + + /* If the thing I should be doing is already being done, wait for it. */ + if(should_write ? c->out.writing : c->in.reading) + { + pthread_cond_wait(cond, &c->iolock); +#if USE_THREAD_ASSERT + --already_here; +#endif + return 1; + } + + FD_ZERO(&rfds); + FD_SET(c->fd, &rfds); + ++c->in.reading; + + FD_ZERO(&wfds); + if(should_write) + { + FD_SET(c->fd, &wfds); + ++c->out.writing; + } + + pthread_mutex_unlock(&c->iolock); + ret = select(c->fd + 1, &rfds, &wfds, 0, 0); + pthread_mutex_lock(&c->iolock); + + if(ret <= 0) /* error: select failed */ + goto done; + + if(FD_ISSET(c->fd, &rfds)) + if((ret = _xcb_in_read(c)) <= 0) + goto done; + + if(FD_ISSET(c->fd, &wfds)) + if((ret = _xcb_out_write(c)) <= 0) + goto done; + +done: + if(should_write) + --c->out.writing; + --c->in.reading; + +#if USE_THREAD_ASSERT + --already_here; +#endif + return ret; +} diff --git a/src/xcb_ext.c b/src/xcb_ext.c new file mode 100644 index 0000000..46a5519 --- /dev/null +++ b/src/xcb_ext.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* A cache for QueryExtension results. */ + +#include +#include + +#include "xcb.h" +#include "xcbext.h" +#include "xcbint.h" + +typedef struct { + enum { LAZY_COOKIE, LAZY_FORCED } tag; + union { + XCBQueryExtensionCookie cookie; + XCBQueryExtensionRep *reply; + } value; +} lazyreply; + +static lazyreply *get_lazyreply(XCBConnection *c, XCBExtension *ext) +{ + static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; + static int next_global_id; + + lazyreply *data; + + pthread_mutex_lock(&global_lock); + if(!ext->global_id) + ext->global_id = ++next_global_id; + pthread_mutex_unlock(&global_lock); + + data = _xcb_map_get(c->ext.extensions, ext->global_id); + if(!data) + { + /* cache miss: query the server */ + data = malloc(sizeof(lazyreply)); + if(!data) + return 0; + data->tag = LAZY_COOKIE; + data->value.cookie = XCBQueryExtension(c, strlen(ext->name), ext->name); + _xcb_map_put(c->ext.extensions, ext->global_id, data); + } + return data; +} + +static void free_lazyreply(void *p) +{ + lazyreply *data = p; + if(data->tag == LAZY_FORCED) + free(data->value.reply); + free(data); +} + +/* Public interface */ + +/* Do not free the returned XCBQueryExtensionRep - on return, it's aliased + * from the cache. */ +const XCBQueryExtensionRep *XCBGetExtensionData(XCBConnection *c, XCBExtension *ext) +{ + lazyreply *data; + + pthread_mutex_lock(&c->ext.lock); + data = get_lazyreply(c, ext); + if(data && data->tag == LAZY_COOKIE) + { + data->tag = LAZY_FORCED; + data->value.reply = XCBQueryExtensionReply(c, data->value.cookie, 0); + } + pthread_mutex_unlock(&c->ext.lock); + + return data ? data->value.reply : 0; +} + +void XCBPrefetchExtensionData(XCBConnection *c, XCBExtension *ext) +{ + pthread_mutex_lock(&c->ext.lock); + get_lazyreply(c, ext); + pthread_mutex_unlock(&c->ext.lock); +} + +/* Private interface */ + +int _xcb_ext_init(XCBConnection *c) +{ + if(pthread_mutex_init(&c->ext.lock, 0)) + return 0; + + c->ext.extensions = _xcb_map_new(); + if(!c->ext.extensions) + return 0; + + return 1; +} + +void _xcb_ext_destroy(XCBConnection *c) +{ + pthread_mutex_destroy(&c->ext.lock); + _xcb_map_delete(c->ext.extensions, free_lazyreply); +} diff --git a/src/xcb_in.c b/src/xcb_in.c new file mode 100644 index 0000000..c260b7b --- /dev/null +++ b/src/xcb_in.c @@ -0,0 +1,319 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Stuff that reads stuff from the server. */ + +#include +#include +#include +#include +#include + +#include "xcb.h" +#include "xcbext.h" +#include "xcbint.h" + +typedef struct XCBReplyData { + unsigned int request; + void *data; + XCBGenericError **error; +} XCBReplyData; + +static int match_request_error(const void *request, const void *data) +{ + const XCBGenericError *e = data; + return e->response_type == 0 && e->sequence == ((*(unsigned int *) request) & 0xffff); +} + +static int match_reply(const void *request, const void *data) +{ + return ((XCBReplyData *) data)->request == *(unsigned int *) request; +} + +static void wake_up_next_reader(XCBConnection *c) +{ + XCBReplyData *cur = _xcb_list_peek_head(c->in.readers); + int pthreadret; + if(cur) + pthreadret = pthread_cond_signal(cur->data); + else + pthreadret = pthread_cond_signal(&c->in.event_cond); + assert(pthreadret == 0); +} + +/* Public interface */ + +void *XCBWaitForReply(XCBConnection *c, unsigned int request, XCBGenericError **e) +{ + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + XCBReplyData reader; + void *ret = 0; + if(e) + *e = 0; + + pthread_mutex_lock(&c->iolock); + + /* If this request has not been written yet, write it. */ + if((signed int) (c->out.request_written - request) < 0) + if(_xcb_out_flush(c) <= 0) + goto done; /* error */ + + if(_xcb_list_find(c->in.readers, match_reply, &request)) + goto done; /* error */ + + if(e) + { + *e = _xcb_list_remove(c->in.events, match_request_error, &request); + if(*e) + goto done; + } + + reader.request = request; + reader.data = &cond; + reader.error = e; + _xcb_list_append(c->in.readers, &reader); + + /* If this request has not been read yet, wait for it. */ + while(!(e && *e) && ((signed int) (c->in.request_read - request) < 0 || + (c->in.request_read == request && + _xcb_queue_is_empty(c->in.current_reply)))) + if(_xcb_conn_wait(c, /*should_write*/ 0, &cond) <= 0) + goto done; + + if(c->in.request_read != request) + { + _xcb_queue *q = _xcb_map_get(c->in.replies, request); + if(q) + { + ret = _xcb_queue_dequeue(q); + if(_xcb_queue_is_empty(q)) + _xcb_queue_delete(_xcb_map_remove(c->in.replies, request), free); + } + } + else + ret = _xcb_queue_dequeue(c->in.current_reply); + +done: + _xcb_list_remove(c->in.readers, match_reply, &request); + pthread_cond_destroy(&cond); + + wake_up_next_reader(c); + pthread_mutex_unlock(&c->iolock); + return ret; +} + +XCBGenericEvent *XCBWaitEvent(XCBConnection *c) +{ + return XCBWaitForEvent(c); +} + +XCBGenericEvent *XCBWaitForEvent(XCBConnection *c) +{ + XCBGenericEvent *ret; + +#if XCBTRACEEVENT + fprintf(stderr, "Entering XCBWaitEvent\n"); +#endif + + pthread_mutex_lock(&c->iolock); + /* _xcb_list_remove_head returns 0 on empty list. */ + while(!(ret = _xcb_queue_dequeue(c->in.events))) + if(_xcb_conn_wait(c, /*should_write*/ 0, &c->in.event_cond) <= 0) + break; + + wake_up_next_reader(c); + pthread_mutex_unlock(&c->iolock); + +#if XCBTRACEEVENT + fprintf(stderr, "Leaving XCBWaitEvent, event type %d\n", ret ? ret->response_type : -1); +#endif + + return ret; +} + +XCBGenericEvent *XCBPollForEvent(XCBConnection *c, int *error) +{ + XCBGenericEvent *ret = 0; + pthread_mutex_lock(&c->iolock); + if(error) + *error = 0; + /* FIXME: follow X meets Z architecture changes. */ + if(_xcb_in_read(c) >= 0) + ret = _xcb_queue_dequeue(c->in.events); + else if(error) + *error = -1; + else + { + fprintf(stderr, "XCBPollForEvent: I/O error occured, but no handler provided.\n"); + abort(); + } + pthread_mutex_unlock(&c->iolock); + return ret; +} + +unsigned int XCBGetRequestRead(XCBConnection *c) +{ + unsigned int ret; + pthread_mutex_lock(&c->iolock); + /* FIXME: follow X meets Z architecture changes. */ + _xcb_in_read(c); + ret = c->in.request_read; + pthread_mutex_unlock(&c->iolock); + return ret; +} + +/* Private interface */ + +int _xcb_in_init(_xcb_in *in) +{ + if(pthread_cond_init(&in->event_cond, 0)) + return 0; + in->reading = 0; + + in->queue_len = 0; + + in->request_read = 0; + in->current_reply = _xcb_queue_new(); + + in->replies = _xcb_map_new(); + in->events = _xcb_queue_new(); + in->readers = _xcb_list_new(); + if(!in->current_reply || !in->replies || !in->events || !in->readers) + return 0; + + return 1; +} + +void _xcb_in_destroy(_xcb_in *in) +{ + pthread_cond_destroy(&in->event_cond); + _xcb_queue_delete(in->current_reply, free); + _xcb_map_delete(in->replies, free); + _xcb_queue_delete(in->events, free); + _xcb_list_delete(in->readers, 0); +} + +int _xcb_in_expect_reply(XCBConnection *c, unsigned int request) +{ + /* XXX: currently a no-op */ + return 1; +} + +int _xcb_in_read_packet(XCBConnection *c) +{ + XCBGenericRep genrep; + int length = 32; + unsigned char *buf; + + /* Wait for there to be enough data for us to read a whole packet */ + if(c->in.queue_len < length) + return 0; + + /* Get the response type, length, and sequence number. */ + memcpy(&genrep, c->in.queue, sizeof(genrep)); + + /* For reply packets, check that the entire packet is available. */ + if(genrep.response_type == 1) + length += genrep.length * 4; + + buf = malloc(length); + if(!buf) + return 0; + if(_xcb_in_read_block(c, buf, length) <= 0) + { + free(buf); + return 0; + } + + /* Compute 32-bit sequence number of this packet. */ + /* XXX: do "sequence lost" check here */ + if((genrep.response_type & 0x7f) != KeymapNotify) + { + int lastread = c->in.request_read; + c->in.request_read = (lastread & 0xffff0000) | genrep.sequence; + if(c->in.request_read != lastread && !_xcb_queue_is_empty(c->in.current_reply)) + { + _xcb_map_put(c->in.replies, lastread, c->in.current_reply); + c->in.current_reply = _xcb_queue_new(); + } + if(c->in.request_read < lastread) + c->in.request_read += 0x10000; + } + + if(buf[0] == 1) /* response is a reply */ + { + XCBReplyData *reader = _xcb_list_find(c->in.readers, match_reply, &c->in.request_read); + _xcb_queue_enqueue(c->in.current_reply, buf); + if(reader) + pthread_cond_signal(reader->data); + return 1; + } + + if(buf[0] == 0) /* response is an error */ + { + XCBReplyData *reader = _xcb_list_find(c->in.readers, match_reply, &c->in.request_read); + if(reader && reader->error) + { + *reader->error = (XCBGenericError *) buf; + pthread_cond_signal(reader->data); + return 1; + } + } + + /* event, or error without a waiting reader */ + _xcb_queue_enqueue(c->in.events, buf); + pthread_cond_signal(&c->in.event_cond); + return 1; /* I have something for you... */ +} + +int _xcb_in_read(XCBConnection *c) +{ + int n = _xcb_readn(c->fd, c->in.queue, sizeof(c->in.queue), &c->in.queue_len); + if(n < 0 && errno == EAGAIN) + n = 1; + while(_xcb_in_read_packet(c) > 0) + /* empty */; + return n; +} + +int _xcb_in_read_block(XCBConnection *c, void *buf, int len) +{ + int done = c->in.queue_len; + if(len < done) + done = len; + + memcpy(buf, c->in.queue, done); + c->in.queue_len -= done; + memmove(c->in.queue, c->in.queue + done, c->in.queue_len); + + if(len > done) + { + int ret = _xcb_read_block(c->fd, (char *) buf + done, len - done); + if(ret <= 0) + return ret; + } + + return len; +} diff --git a/src/xcb_list.c b/src/xcb_list.c new file mode 100644 index 0000000..5b2edc0 --- /dev/null +++ b/src/xcb_list.c @@ -0,0 +1,215 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* A generic implementation of a list of void-pointers. */ + +#include + +#include "xcb.h" +#include "xcbint.h" + +typedef struct node { + struct node *next; + void *data; +} node; + +struct _xcb_list { + node *head; + node **tail; +}; + +/* Private interface */ + +_xcb_list *_xcb_list_new() +{ + _xcb_list *list; + list = malloc(sizeof(_xcb_list)); + if(!list) + return 0; + list->head = 0; + list->tail = &list->head; + return list; +} + +static void _xcb_list_clear(_xcb_list *list, XCBListFreeFunc do_free) +{ + void *tmp; + while((tmp = _xcb_list_remove_head(list))) + if(do_free) + do_free(tmp); +} + +void _xcb_list_delete(_xcb_list *list, XCBListFreeFunc do_free) +{ + if(!list) + return; + _xcb_list_clear(list, do_free); + free(list); +} + +int _xcb_list_insert(_xcb_list *list, void *data) +{ + node *cur; + cur = malloc(sizeof(node)); + if(!cur) + return 0; + cur->data = data; + + cur->next = list->head; + list->head = cur; + return 1; +} + +int _xcb_list_append(_xcb_list *list, void *data) +{ + node *cur; + cur = malloc(sizeof(node)); + if(!cur) + return 0; + cur->data = data; + cur->next = 0; + + *list->tail = cur; + list->tail = &cur->next; + return 1; +} + +void *_xcb_list_peek_head(_xcb_list *list) +{ + if(!list->head) + return 0; + return list->head->data; +} + +void *_xcb_list_remove_head(_xcb_list *list) +{ + void *ret; + node *tmp = list->head; + if(!tmp) + return 0; + ret = tmp->data; + list->head = tmp->next; + if(!list->head) + list->tail = &list->head; + free(tmp); + return ret; +} + +void *_xcb_list_remove(_xcb_list *list, int (*cmp)(const void *, const void *), const void *data) +{ + node **cur; + for(cur = &list->head; *cur; cur = &(*cur)->next) + if(cmp(data, (*cur)->data)) + { + node *tmp = *cur; + void *ret = (*cur)->data; + *cur = (*cur)->next; + if(!*cur) + list->tail = cur; + + free(tmp); + return ret; + } + return 0; +} + +void *_xcb_list_find(_xcb_list *list, int (*cmp)(const void *, const void *), const void *data) +{ + node *cur; + for(cur = list->head; cur; cur = cur->next) + if(cmp(data, cur->data)) + return cur->data; + return 0; +} + +_xcb_queue *_xcb_queue_new(void) __attribute__ ((alias ("_xcb_list_new"))); +void _xcb_queue_delete(_xcb_queue *q, XCBListFreeFunc do_free) __attribute__ ((alias ("_xcb_list_delete"))); +int _xcb_queue_enqueue(_xcb_queue *q, void *data) __attribute__ ((alias ("_xcb_list_append"))); +void *_xcb_queue_dequeue(_xcb_queue *q) __attribute__ ((alias ("_xcb_list_remove_head"))); + +int _xcb_queue_is_empty(_xcb_queue *q) +{ + return q->head == 0; +} + +typedef struct { + unsigned int key; + void *value; +} map_pair; + +_xcb_map *_xcb_map_new(void) __attribute__ ((alias ("_xcb_list_new"))); + +void _xcb_map_delete(_xcb_map *q, XCBListFreeFunc do_free) +{ + map_pair *tmp; + if(!q) + return; + while((tmp = _xcb_list_remove_head(q))) + { + if(do_free) + do_free(tmp->value); + free(tmp); + } + free(q); +} + +int _xcb_map_put(_xcb_map *q, unsigned int key, void *data) +{ + map_pair *cur = malloc(sizeof(map_pair)); + if(!cur) + return 0; + cur->key = key; + cur->value = data; + if(!_xcb_list_append(q, cur)) + { + free(cur); + return 0; + } + return 1; +} + +static int match_map_pair(const void *key, const void *pair) +{ + return ((map_pair *) pair)->key == *(unsigned int *) key; +} + +void *_xcb_map_get(_xcb_map *q, unsigned int key) +{ + map_pair *cur = _xcb_list_find(q, match_map_pair, &key); + if(!cur) + return 0; + return cur->value; +} + +void *_xcb_map_remove(_xcb_map *q, unsigned int key) +{ + map_pair *cur = _xcb_list_remove(q, match_map_pair, &key); + void *ret; + if(!cur) + return 0; + ret = cur->value; + free(cur); + return ret; +} diff --git a/src/xcb_out.c b/src/xcb_out.c new file mode 100644 index 0000000..b3a556a --- /dev/null +++ b/src/xcb_out.c @@ -0,0 +1,272 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Stuff that sends stuff to the server. */ + +#include +#include +#include +#include + +#include "xcb.h" +#include "xcbext.h" +#include "xcbint.h" +#include "extensions/bigreq.h" + +static int force_sequence_wrap(XCBConnection *c) +{ + int ret = 1; + if((c->out.request - c->in.request_read) > 65530) + { + pthread_mutex_unlock(&c->iolock); + ret = XCBSync(c, 0); + pthread_mutex_lock(&c->iolock); + } + return ret; +} + +/* Public interface */ + +CARD32 XCBGetMaximumRequestLength(XCBConnection *c) +{ + pthread_mutex_lock(&c->out.reqlenlock); + if(!c->out.maximum_request_length) + { + const XCBQueryExtensionRep *ext; + c->out.maximum_request_length = c->setup->maximum_request_length; + ext = XCBGetExtensionData(c, &XCBBigRequestsId); + if(ext && ext->present) + { + XCBBigRequestsEnableRep *r = XCBBigRequestsEnableReply(c, XCBBigRequestsEnable(c), 0); + c->out.maximum_request_length = r->maximum_request_length; + free(r); + } + } + pthread_mutex_unlock(&c->out.reqlenlock); + return c->out.maximum_request_length; +} + +int XCBSendRequest(XCBConnection *c, unsigned int *request, struct iovec *vector, const XCBProtocolRequest *req) +{ + int ret; + int i; + struct iovec prefix[2]; + CARD16 shortlen = 0; + CARD32 longlen = 0; + + assert(c != 0); + assert(request != 0); + assert(vector != 0); + assert(req->count > 0); + + /* put together the length field, possibly using BIGREQUESTS */ + for(i = 0; i < req->count; ++i) + longlen += XCB_CEIL(vector[i].iov_len) >> 2; + + if(longlen > c->setup->maximum_request_length) + { + if(longlen > XCBGetMaximumRequestLength(c)) + return 0; /* server can't take this; maybe need BIGREQUESTS? */ + } + else + { + /* we don't need BIGREQUESTS. */ + shortlen = longlen; + longlen = 0; + } + + /* set the length field. */ + i = 0; + prefix[i].iov_base = vector[0].iov_base; + prefix[i].iov_len = sizeof(CARD32); + vector[0].iov_base = ((char *) vector[0].iov_base) + sizeof(CARD32); + vector[0].iov_len -= sizeof(CARD32); + ((CARD16 *) prefix[i].iov_base)[1] = shortlen; + ++i; + if(!shortlen) + { + ++longlen; + prefix[i].iov_base = &longlen; + prefix[i].iov_len = sizeof(CARD32); + ++i; + } + + /* set the major opcode, and the minor opcode for extensions */ + if(req->ext) + { + const XCBQueryExtensionRep *extension = XCBGetExtensionData(c, req->ext); + /* TODO: better error handling here, please! */ + assert(extension && extension->present); + ((CARD8 *) prefix[0].iov_base)[0] = extension->major_opcode; + ((CARD8 *) prefix[0].iov_base)[1] = req->opcode; + } + else + ((CARD8 *) prefix[0].iov_base)[0] = req->opcode; + + /* get a sequence number and arrange for delivery. */ + pthread_mutex_lock(&c->iolock); + if(req->isvoid && !force_sequence_wrap(c)) + { + pthread_mutex_unlock(&c->iolock); + return -1; + } + + *request = ++c->out.request; + + if(!req->isvoid) + _xcb_in_expect_reply(c, *request); + + ret = _xcb_out_write_block(c, prefix, i); + if(ret > 0) + ret = _xcb_out_write_block(c, vector, req->count); + pthread_mutex_unlock(&c->iolock); + + return ret; +} + +int XCBFlush(XCBConnection *c) +{ + int ret; + pthread_mutex_lock(&c->iolock); + ret = _xcb_out_flush(c); + pthread_mutex_unlock(&c->iolock); + return ret; +} + +/* Private interface */ + +int _xcb_out_init(_xcb_out *out) +{ + if(pthread_cond_init(&out->cond, 0)) + return 0; + out->writing = 0; + + out->queue_len = 0; + out->vec = 0; + out->vec_len = 0; + + out->last_request = 0; + out->request = 0; + out->request_written = 0; + + if(pthread_mutex_init(&out->reqlenlock, 0)) + return 0; + out->maximum_request_length = 0; + + return 1; +} + +void _xcb_out_destroy(_xcb_out *out) +{ + pthread_cond_destroy(&out->cond); + pthread_mutex_destroy(&out->reqlenlock); + free(out->vec); +} + +int _xcb_out_write(XCBConnection *c) +{ + int n; + if(c->out.vec_len) + n = _xcb_writev(c->fd, c->out.vec, c->out.vec_len); + else + n = _xcb_write(c->fd, &c->out.queue, &c->out.queue_len); + + if(n < 0 && errno == EAGAIN) + n = 1; + + if(c->out.vec_len) + { + int i; + for(i = 0; i < c->out.vec_len; ++i) + if(c->out.vec[i].iov_len) + return n; + c->out.vec_len = 0; + } + return n; +} + +int _xcb_out_write_block(XCBConnection *c, struct iovec *vector, size_t count) +{ + static const char pad[3]; + int i; + int len = 0; + + for(i = 0; i < count; ++i) + len += XCB_CEIL(vector[i].iov_len); + + /* Is the queue about to overflow? */ + if(c->out.queue_len + len < sizeof(c->out.queue)) + { + /* No, this will fit. */ + for(i = 0; i < count; ++i) + { + memcpy(c->out.queue + c->out.queue_len, vector[i].iov_base, vector[i].iov_len); + if(vector[i].iov_len & 3) + memset(c->out.queue + c->out.queue_len + vector[i].iov_len, 0, XCB_PAD(vector[i].iov_len)); + c->out.queue_len += XCB_CEIL(vector[i].iov_len); + } + return len; + } + + assert(!c->out.vec_len); + assert(!c->out.vec); + c->out.vec = malloc(sizeof(struct iovec) * (1 + count * 2)); + if(!c->out.vec) + return -1; + if(c->out.queue_len) + { + c->out.vec[c->out.vec_len].iov_base = c->out.queue; + c->out.vec[c->out.vec_len++].iov_len = c->out.queue_len; + c->out.queue_len = 0; + } + for(i = 0; i < count; ++i) + { + if(!vector[i].iov_len) + continue; + c->out.vec[c->out.vec_len].iov_base = vector[i].iov_base; + c->out.vec[c->out.vec_len++].iov_len = vector[i].iov_len; + if(!XCB_PAD(vector[i].iov_len)) + continue; + c->out.vec[c->out.vec_len].iov_base = (void *) pad; + c->out.vec[c->out.vec_len++].iov_len = XCB_PAD(vector[i].iov_len); + } + if(_xcb_out_flush(c) <= 0) + len = -1; + free(c->out.vec); + c->out.vec = 0; + + return len; +} + +int _xcb_out_flush(XCBConnection *c) +{ + int ret = 1; + while(ret > 0 && (c->out.queue_len || c->out.vec_len)) + ret = _xcb_conn_wait(c, /*should_write*/ 1, &c->out.cond); + c->out.last_request = 0; + c->out.request_written = c->out.request; + pthread_cond_broadcast(&c->out.cond); + return ret; +} diff --git a/src/xcb_util.c b/src/xcb_util.c new file mode 100644 index 0000000..b25a2d8 --- /dev/null +++ b/src/xcb_util.c @@ -0,0 +1,279 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Utility functions implementable using only public APIs. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xcb.h" +#include "xcbext.h" + +int XCBPopcount(CARD32 mask) +{ + unsigned long y; + y = (mask >> 1) & 033333333333; + y = mask - y - ((y >> 1) & 033333333333); + return ((y + (y >> 3)) & 030707070707) % 077; +} + +int XCBParseDisplay(const char *name, char **host, int *displayp, int *screenp) +{ + int len, display, screen; + char *colon, *dot, *end; + if(!name || !*name) + name = getenv("DISPLAY"); + if(!name) + return 0; + colon = strrchr(name, ':'); + if(!colon) + return 0; + len = colon - name; + ++colon; + display = strtoul(colon, &dot, 10); + if(dot == colon) + return 0; + if(*dot == '\0') + screen = 0; + else + { + if(*dot != '.') + return 0; + ++dot; + screen = strtoul(dot, &end, 10); + if(end == dot || *end != '\0') + return 0; + } + /* At this point, the display string is fully parsed and valid, but + * the caller's memory is untouched. */ + + *host = malloc(len + 1); + if(!*host) + return 0; + memcpy(*host, name, len); + (*host)[len] = '\0'; + *displayp = display; + if(screenp) + *screenp = screen; + return 1; +} + +int XCBOpen(const char *host, const int display) +{ + int fd; + + if(*host) + { + /* display specifies TCP */ + unsigned short port = X_TCP_PORT + display; + fd = XCBOpenTCP(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 = XCBOpenUnix(file); + } + + return fd; +} + +int XCBOpenTCP(const char *host, const unsigned short port) +{ + int fd; + struct sockaddr_in addr; + struct hostent *hostaddr = gethostbyname(host); + if(!hostaddr) + return -1; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + memcpy(&addr.sin_addr, hostaddr->h_addr_list[0], sizeof(addr.sin_addr)); + + fd = socket(PF_INET, SOCK_STREAM, 0); + if(fd == -1) + return -1; + if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) + return -1; + return fd; +} + +int XCBOpenUnix(const char *file) +{ + int fd; + struct sockaddr_un addr = { AF_UNIX }; + strcpy(addr.sun_path, file); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(fd == -1) + return -1; + if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) + return -1; + return fd; +} + +XCBConnection *XCBConnect(const char *displayname, int *screenp) +{ + int fd, display = 0; + char *host; + XCBConnection *c; + XCBAuthInfo auth; + + if(!XCBParseDisplay(displayname, &host, &display, screenp)) + return 0; + fd = XCBOpen(host, display); + free(host); + if(fd == -1) + return 0; + + XCBGetAuthInfo(fd, &auth); + c = XCBConnectToFD(fd, &auth); + free(auth.name); + free(auth.data); + return c; +} + +XCBConnection *XCBConnectToDisplayWithAuthInfo(const char *displayname, XCBAuthInfo *auth, int *screenp) +{ + int fd, display = 0; + char *host; + + if(!XCBParseDisplay(displayname, &host, &display, screenp)) + return 0; + fd = XCBOpen(host, display); + free(host); + if(fd == -1) + return 0; + + return XCBConnectToFD(fd, auth); +} + +/* backwards compatible interface: remove before 1.0 release */ +XCBConnection *XCBConnectBasic() +{ + XCBConnection *c = XCBConnect(0, 0); + if(c) + return c; + perror("XCBConnect"); + abort(); +} + +int XCBSync(XCBConnection *c, XCBGenericError **e) +{ + XCBGetInputFocusRep *reply = XCBGetInputFocusReply(c, XCBGetInputFocus(c), e); + free(reply); + return reply != 0; +} + +/* The functions beyond this point still use only public interfaces, + * but are not themselves part of the public interface. So their + * prototypes are in xcbint.h. */ + +#include "xcbint.h" + +int _xcb_set_fd_flags(const int fd) +{ + long flags = fcntl(fd, F_GETFL, 0); + if(flags == -1) + return 0; + flags |= O_NONBLOCK; + if(fcntl(fd, F_SETFL, flags) == -1) + return 0; + if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + return 0; + return 1; +} + +int _xcb_readn(const int fd, void *buf, const int buflen, int *count) +{ + int n = read(fd, ((char *) buf) + *count, buflen - *count); + if(n > 0) + *count += n; + return n; +} + +int _xcb_read_block(const int fd, void *buf, const size_t len) +{ + int done = 0; + while(done < len) + { + int ret = _xcb_readn(fd, buf, len, &done); + if(ret < 0 && errno == EAGAIN) + { + fd_set fds; + FD_ZERO(&fds); + FD_SET(fd, &fds); + ret = select(fd + 1, &fds, 0, 0, 0); + } + if(ret <= 0) + return ret; + } + return len; +} + +int _xcb_write(const int fd, char (*buf)[], int *count) +{ + int n = write(fd, *buf, *count); + if(n > 0) + { + *count -= n; + if(*count) + memmove(*buf, *buf + n, *count); + } + return n; +} + +int _xcb_writev(const int fd, struct iovec *vec, int count) +{ + int n = writev(fd, vec, count); + if(n > 0) + { + int rem = n; + for(; count; --count, ++vec) + { + int cur = vec->iov_len; + if(cur > rem) + cur = rem; + vec->iov_len -= cur; + vec->iov_base = (char *) vec->iov_base + cur; + rem -= cur; + if(vec->iov_len) + break; + } + assert(rem == 0); + } + return n; +} diff --git a/src/xcb_xid.c b/src/xcb_xid.c new file mode 100644 index 0000000..7d7f784 --- /dev/null +++ b/src/xcb_xid.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* XID allocators. */ + +#include +#include "xcb.h" +#include "xcbext.h" +#include "xcbint.h" +#include "extensions/xc_misc.h" + +/* Public interface */ + +CARD32 XCBGenerateID(XCBConnection *c) +{ + CARD32 ret; + pthread_mutex_lock(&c->xid.lock); + if(c->xid.last == c->xid.max) + { + XCBXCMiscGetXIDRangeRep *range; + range = XCBXCMiscGetXIDRangeReply(c, XCBXCMiscGetXIDRange(c), 0); + c->xid.last = range->start_id; + c->xid.max = range->start_id + (range->count - 1) * c->xid.inc; + free(range); + } + ret = c->xid.last | c->xid.base; + c->xid.last += c->xid.inc; + pthread_mutex_unlock(&c->xid.lock); + return ret; +} + +/* Private interface */ + +int _xcb_xid_init(XCBConnection *c) +{ + if(pthread_mutex_init(&c->xid.lock, 0)) + return 0; + c->xid.last = 0; + c->xid.base = c->setup->resource_id_base; + c->xid.max = c->setup->resource_id_mask; + c->xid.inc = c->setup->resource_id_mask & -(c->setup->resource_id_mask); + return 1; +} + +void _xcb_xid_destroy(XCBConnection *c) +{ + pthread_mutex_destroy(&c->xid.lock); +} diff --git a/src/xcb_xlib.c b/src/xcb_xlib.c new file mode 100644 index 0000000..8cc6837 --- /dev/null +++ b/src/xcb_xlib.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2005 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#include "xcbxlib.h" +#include "xcbint.h" + +unsigned int XCBGetRequestSent(XCBConnection *c) +{ + unsigned int ret; + pthread_mutex_lock(&c->iolock); + ret = c->out.request; + pthread_mutex_unlock(&c->iolock); + return ret; +} + +pthread_mutex_t *XCBGetIOLock(XCBConnection *c) +{ + return &c->iolock; +} diff --git a/src/xcbext.h b/src/xcbext.h new file mode 100644 index 0000000..c8f532c --- /dev/null +++ b/src/xcbext.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#ifndef __XCBEXT_H +#define __XCBEXT_H + +#include "xcb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* xcb_ext.c */ + +struct XCBExtension { + const char *name; + int global_id; +}; + + +/* xcb_out.c */ + +typedef struct { + size_t count; + XCBExtension *ext; + CARD8 opcode; + BOOL isvoid; +} XCBProtocolRequest; + +int XCBSendRequest(XCBConnection *c, unsigned int *sequence, struct iovec *vector, const XCBProtocolRequest *request); + + +/* xcb_in.c */ + +void *XCBWaitForReply(XCBConnection *c, unsigned int request, XCBGenericError **e); + + +/* xcb_xid.c */ + +CARD32 XCBGenerateID(XCBConnection *c); + + +/* xcb_util.c */ + +int XCBPopcount(CARD32 mask); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/xcbint.h b/src/xcbint.h new file mode 100644 index 0000000..057a315 --- /dev/null +++ b/src/xcbint.h @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#ifndef __XCBINT_H +#define __XCBINT_H + +/* Not simply (a <= b) because eventually the 32-bit sequence number + * will wrap, causing earlier sequence numbers to be higher than later + * ones for a brief but fatal period. (a and b must be unsigned.) */ +#define _xcb_assert_sequence_less(a,b) assert((b) - (a) < 65536) + +#define _xcb_assert_valid_sequence(c) do { \ + _xcb_assert_sequence_less((c)->in.request_read, (c)->out.request_written); \ + _xcb_assert_sequence_less((c)->out.request_written, (c)->out.request); \ +} while(0) + +/* xcb_list.c */ + +typedef struct _xcb_list _xcb_list; +typedef void (*XCBListFreeFunc)(void *); + +_xcb_list *_xcb_list_new(void); +void _xcb_list_delete(_xcb_list *list, XCBListFreeFunc do_free); +int _xcb_list_insert(_xcb_list *list, void *data); +int _xcb_list_append(_xcb_list *list, void *data); +void *_xcb_list_peek_head(_xcb_list *list); +void *_xcb_list_remove_head(_xcb_list *list); +void *_xcb_list_remove(_xcb_list *list, int (*cmp)(const void *, const void *), const void *data); +void *_xcb_list_find(_xcb_list *list, int (*cmp)(const void *, const void *), const void *data); + +typedef _xcb_list _xcb_queue; + +_xcb_queue *_xcb_queue_new(void); +void _xcb_queue_delete(_xcb_queue *q, XCBListFreeFunc do_free); +int _xcb_queue_enqueue(_xcb_queue *q, void *data); +void *_xcb_queue_dequeue(_xcb_queue *q); +int _xcb_queue_is_empty(_xcb_queue *q); + +typedef _xcb_list _xcb_map; + +_xcb_map *_xcb_map_new(void); +void _xcb_map_delete(_xcb_map *q, XCBListFreeFunc do_free); +int _xcb_map_put(_xcb_map *q, unsigned int key, void *data); +void *_xcb_map_get(_xcb_map *q, unsigned int key); +void *_xcb_map_remove(_xcb_map *q, unsigned int key); + + +/* xcb_util.c */ + +/* Index of nearest 4-byte boundary following E. */ +#define XCB_CEIL(E) (((E)+3)&~3) + +#define XCB_PAD(i) ((4 - (i & 3)) & 3) + +int _xcb_set_fd_flags(const int fd); +int _xcb_readn(const int fd, void *buf, const int buflen, int *count); +int _xcb_read_block(const int fd, void *buf, const size_t len); +int _xcb_write(const int fd, char (*buf)[], int *count); +int _xcb_writev(const int fd, struct iovec *vec, int count); + + +/* xcb_out.c */ + +typedef struct _xcb_out { + pthread_cond_t cond; + int writing; + + char queue[4096]; + int queue_len; + struct iovec *vec; + int vec_len; + + void *last_request; + unsigned int request; + unsigned int request_written; + + pthread_mutex_t reqlenlock; + CARD32 maximum_request_length; +} _xcb_out; + +int _xcb_out_init(_xcb_out *out); +void _xcb_out_destroy(_xcb_out *out); + +int _xcb_out_write(XCBConnection *c); +int _xcb_out_write_block(XCBConnection *c, struct iovec *vector, size_t count); +int _xcb_out_flush(XCBConnection *c); + + +/* xcb_in.c */ + +typedef struct _xcb_in { + pthread_cond_t event_cond; + int reading; + + char queue[4096]; + int queue_len; + + unsigned int request_read; + _xcb_queue *current_reply; + + _xcb_map *replies; + _xcb_queue *events; + _xcb_list *readers; +} _xcb_in; + +int _xcb_in_init(_xcb_in *in); +void _xcb_in_destroy(_xcb_in *in); + +int _xcb_in_expect_reply(XCBConnection *c, unsigned int request); + +int _xcb_in_read_packet(XCBConnection *c); +int _xcb_in_read(XCBConnection *c); +int _xcb_in_read_block(XCBConnection *c, void *buf, int nread); + + +/* xcb_xid.c */ + +typedef struct _xcb_xid { + pthread_mutex_t lock; + CARD32 last; + CARD32 base; + CARD32 max; + CARD32 inc; +} _xcb_xid; + +int _xcb_xid_init(XCBConnection *c); +void _xcb_xid_destroy(XCBConnection *c); + + +/* xcb_ext.c */ + +typedef struct _xcb_ext { + pthread_mutex_t lock; + _xcb_map *extensions; +} _xcb_ext; + +int _xcb_ext_init(XCBConnection *c); +void _xcb_ext_destroy(XCBConnection *c); + + +/* xcb_conn.c */ + +struct XCBConnection { + /* constant data */ + XCBConnSetupSuccessRep *setup; + int fd; + + /* I/O data */ + pthread_mutex_t iolock; + _xcb_in in; + _xcb_out out; + + /* misc data */ + _xcb_ext ext; + _xcb_xid xid; +}; + +int _xcb_conn_wait(XCBConnection *c, const int should_write, pthread_cond_t *cond); +#endif diff --git a/src/xcbxlib.h b/src/xcbxlib.h new file mode 100644 index 0000000..e9f7140 --- /dev/null +++ b/src/xcbxlib.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005 Bart Massey and Jamey Sharp. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#ifndef __XCBXLIB_H +#define __XCBXLIB_H + +#include +#include "xcb.h" + +unsigned int XCBGetRequestSent(XCBConnection *c); + +pthread_mutex_t *XCBGetIOLock(XCBConnection *c); + +#endif diff --git a/tests/.cvsignore b/tests/.cvsignore new file mode 100644 index 0000000..bfa26dd --- /dev/null +++ b/tests/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +CheckLog.html diff --git a/tests/CheckLog.xsl b/tests/CheckLog.xsl new file mode 100644 index 0000000..3daebaa --- /dev/null +++ b/tests/CheckLog.xsl @@ -0,0 +1,104 @@ + + + + + + + + + + Test Suite Results + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
Test PathTest Function LocationC IdentifierTest CaseResult
+
+
+ + + +

Unit Test Statistics

+
    +
  • date/time:
  • +
  • duration:
  • +
+
+
+ + +

Test Suite:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..fceaf13 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,32 @@ +######################## +## tests/Makefile.am +######################## +SUBDIRS = +EXTRA_DIST = CheckLog.xsl +AM_MAKEFLAGS = -k +AM_CFLAGS = -Wall -Werror $(XPROTO_CFLAGS) @CHECK_CFLAGS@ -I$(top_srcdir)/src +LDADD = @CHECK_LIBS@ $(top_builddir)/src/libXCB.la + +if HAVE_CHECK +TESTS = check_all +check_PROGRAMS = check_all +check_all_SOURCES = check_all.c check_suites.h check_public.c + +all-local:: + $(RM) CheckLog*.xml + +check-local: + $(RM) CheckLog.html + if test x$(HTML_CHECK_RESULT) = xtrue; then \ + $(XSLTPROC) $(srcdir)/CheckLog.xsl CheckLog*.xml > CheckLog.html; \ + else \ + touch CheckLog.html; \ + fi + +CheckLog.html: $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check; + +endif + +clean-local:: + $(RM) CheckLog.html CheckLog*.txt CheckLog*.xml diff --git a/tests/check_all.c b/tests/check_all.c new file mode 100644 index 0000000..4393422 --- /dev/null +++ b/tests/check_all.c @@ -0,0 +1,20 @@ +#include +#include "check_suites.h" + +void suite_add_test(Suite *s, TFun tf, const char *name) +{ + TCase *tc = tcase_create(name); + tcase_add_test(tc, tf); + suite_add_tcase(s, tc); +} + +int main(void) +{ + int nf; + SRunner *sr = srunner_create(public_suite()); + srunner_set_xml(sr, "CheckLog_xcb.xml"); + srunner_run_all(sr, CK_NORMAL); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/check_public.c b/tests/check_public.c new file mode 100644 index 0000000..9a32ba9 --- /dev/null +++ b/tests/check_public.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include "check_suites.h" +#include "xcb.h" + +/* XCBParseDisplay tests {{{ */ + +static void parse_display_pass(const char *name, const char *host, const int display, const int screen) +{ + int success; + char *got_host; + int got_display, got_screen; + + got_host = (char *) -1; + got_display = got_screen = -42; + mark_point(); + success = XCBParseDisplay(name, &got_host, &got_display, &got_screen); + fail_unless(success, "unexpected parse failure for '%s'", name); + fail_unless(strcmp(host, got_host) == 0, "parse produced unexpected hostname '%s' for '%s': expected '%s'", got_host, name, host); + fail_unless(display == got_display, "parse produced unexpected display '%d' for '%s': expected '%d'", got_display, name, display); + fail_unless(screen == got_screen, "parse produced unexpected screen '%d' for '%s': expected '%d'", got_screen, name, screen); + + got_host = (char *) -1; + got_display = got_screen = -42; + mark_point(); + success = XCBParseDisplay(name, &got_host, &got_display, 0); + fail_unless(success, "unexpected screenless parse failure for '%s'", name); + fail_unless(strcmp(host, got_host) == 0, "screenless parse produced unexpected hostname '%s' for '%s': expected '%s'", got_host, name, host); + fail_unless(display == got_display, "screenless parse produced unexpected display '%d' for '%s': expected '%d'", got_display, name, display); +} + +static void parse_display_fail(const char *name) +{ + int success; + char *got_host; + int got_display, got_screen; + + got_host = (char *) -1; + got_display = got_screen = -42; + mark_point(); + success = XCBParseDisplay(name, &got_host, &got_display, &got_screen); + fail_unless(!success, "unexpected parse success for '%s'", name); + fail_unless(got_host == (char *) -1, "host changed on failure for '%s': got %p", got_host); + fail_unless(got_display == -42, "display changed on failure for '%s': got %d", got_display); + fail_unless(got_screen == -42, "screen changed on failure for '%s': got %d", got_screen); + + got_host = (char *) -1; + got_display = got_screen = -42; + mark_point(); + success = XCBParseDisplay(name, &got_host, &got_display, 0); + fail_unless(!success, "unexpected screenless parse success for '%s'", name); + fail_unless(got_host == (char *) -1, "host changed on failure for '%s': got %p", got_host); + fail_unless(got_display == -42, "display changed on failure for '%s': got %d", got_display); +} + +START_TEST(parse_display_unix) +{ + parse_display_pass(":0", "", 0, 0); + parse_display_pass(":1", "", 1, 0); + parse_display_pass(":0.1", "", 0, 1); +} +END_TEST + +START_TEST(parse_display_ip) +{ + parse_display_pass("x.org:0", "x.org", 0, 0); + parse_display_pass("expo:0", "expo", 0, 0); + parse_display_pass("bigmachine:1", "bigmachine", 1, 0); + parse_display_pass("hydra:0.1", "hydra", 0, 1); +} +END_TEST + +START_TEST(parse_display_ipv4) +{ + parse_display_pass("198.112.45.11:0", "198.112.45.11", 0, 0); + parse_display_pass("198.112.45.11:0.1", "198.112.45.11", 0, 1); +} +END_TEST + +START_TEST(parse_display_ipv6) +{ + parse_display_pass("::1:0", "::1", 0, 0); + parse_display_pass("::1:0.1", "::1", 0, 1); + parse_display_pass("2002:83fc:d052::1:0", "2002:83fc:d052::1", 0, 0); + parse_display_pass("2002:83fc:d052::1:0.1", "2002:83fc:d052::1", 0, 1); +} +END_TEST + +START_TEST(parse_display_decnet) +{ + parse_display_pass("myws::0", "myws:", 0, 0); + parse_display_pass("big::1", "big:", 1, 0); + parse_display_pass("hydra::0.1", "hydra:", 0, 1); +} +END_TEST + +START_TEST(parse_display_negative) +{ + parse_display_fail(0); + parse_display_fail(""); + parse_display_fail(":"); + parse_display_fail("::"); + parse_display_fail(":."); + parse_display_fail(":a"); + parse_display_fail(":a."); + parse_display_fail(":0."); + parse_display_fail(":0.a"); + parse_display_fail(":0.0."); + + parse_display_fail("localhost"); + parse_display_fail("localhost:"); +} +END_TEST + +/* }}} */ + +Suite *public_suite(void) +{ + Suite *s = suite_create("Public API"); + putenv("DISPLAY"); + suite_add_test(s, parse_display_unix, "XCBParseDisplay unix"); + suite_add_test(s, parse_display_ip, "XCBParseDisplay ip"); + suite_add_test(s, parse_display_ipv4, "XCBParseDisplay ipv4"); + suite_add_test(s, parse_display_ipv6, "XCBParseDisplay ipv6"); + suite_add_test(s, parse_display_decnet, "XCBParseDisplay decnet"); + suite_add_test(s, parse_display_negative, "XCBParseDisplay negative"); + return s; +} diff --git a/tests/check_suites.h b/tests/check_suites.h new file mode 100644 index 0000000..499f1af --- /dev/null +++ b/tests/check_suites.h @@ -0,0 +1,4 @@ +#include + +void suite_add_test(Suite *s, TFun tf, const char *name); +Suite *public_suite(void); diff --git a/xcb.pc.in b/xcb.pc.in new file mode 100644 index 0000000..108165d --- /dev/null +++ b/xcb.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: XCB +Description: X-protocol C Binding +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lXCB @XPROTO_LIBS@ @LIBS@ +Cflags: -I${includedir} @XPROTO_CFLAGS@