diff options
| author | Josh Triplett <josh@freedesktop.org> | 2006-02-18 16:49:41 -0800 | 
|---|---|---|
| committer | Josh Triplett <josh@josh-mobile.localdomain> | 2006-02-18 16:49:41 -0800 | 
| commit | 47ceed78612d48dcda62cc2686fc527d61abe38b (patch) | |
| tree | 06f7f11c92006537925c09440c6b6f9178d2dd4c | |
Remove xcl and CVSROOT.
41 files changed, 8995 insertions, 0 deletions
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 @@ -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  <jamey@minilop.net> + +	* configure.ac: +	Replace obsolete AC_OUTPUT(...) call with AC_CONFIG_FILES(...) +	and the no-argument AC_OUTPUT macro. + +2005-12-24  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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 <twoerner.x@gmail.com> + +	reviewer: Jamey Sharp <jamey@minilop.net> + +	* 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 <twoerner.x@gmail.com> + +	reviewer: Jamey Sharp <jamey@minilop.net> + +	* src/Makefile.am: +	Make builds work when the source and build directories +	are different. + +2005-08-03  Trevor Woerner <twoerner.x@gmail.com> + +	reviewer: Jamey Sharp <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* src/xcb_conn.c: +	Fix one uninitialized memory warning from Valgrind. +	More will have to wait. + +2005-07-21  Jamey Sharp  <jamey@minilop.net> + +	* src/xcb_ext.c: +	Fix memory leak reported by Carl Worth (thanks Carl!). + +2005-05-22  Josh Triplett  <josh@freedesktop.org> + +	* src/c-client.xsl: +	Permit unions to have fixed-length list fields. + +2005-05-21  Josh Triplett  <josh@freedesktop.org> + +	* src/c-client.xsl: +	In function parameters and structure fields, line up field names in +	the same starting column. + +2005-05-17  Josh Triplett  <josh@freedesktop.org> + +	* 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  <josh@freedesktop.org> + +	* src/c-client.xsl: +	Line up function parameters with opening parenthesis. + +2005-05-17  Jamey Sharp  <jamey@minilop.net> + +	* src/c-client.xsl: +	Improve whitespace output on function declarations. + +2005-04-23  Jeremy Kolb  <jkolb@brandeis.edu> +	* src/c-client.xsl: +	Added list support for typedefs. +	GLX now compiles. + +2005-04-23  Josh Triplett  <josh@freedesktop.org> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jkolb@brandeis.edu> + +	* src/c-client.xsl: +	Added support for c types float and double. +	Needed for GLX extension. + +2005-04-02  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* src/xcb_list.c: +	Make the _destroy operations no-op on null pointers. + +2005-03-31  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* src/xcb_in.c: +	Fix X error handling to, uh, not hang. + +2005-03-30  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* src/xcb_list.c, src/xcbint.h: +	Add a map ADT implemented using the list ADT. + +2005-03-28  Vincent Torri  <torri@iecn.u-nancy.fr> + +	* doc/tutorial/index.html, doc/tutorial/xcb.css: +	Add a tutorial + +2005-03-27  Jeremy Kolb  <jkolb@brandeis.edu> + +	* src/Makefile.am: +	Added xf86dri (xcb-proto/src/extensions/xf86dri.h). +	Removed compilation of record as it's broken. + +2005-03-25  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* src/xcb_list.c, src/xcbint.h: +	Add _xcb_queue_is_empty. + +2005-03-25  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <josh@freedesktop.org> + +	* configure.ac: +	Change pdx.freedesktop.org to lists.freedesktop.org in package +	email address. + +2005-03-23  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <josh@freedesktop.org> + +	* 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  <josh@freedesktop.org> + +	* 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  <josh@freedesktop.org> + +	* 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  <josh@freedesktop.org> + +	* src/c-client.xsl: +	Prefix variables in request functions with "xcb_" to avoid +	collisions with field names. + +2004-11-09  Josh Triplett  <josh@freedesktop.org> + +	* 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  <josh@freedesktop.org> + +	* src/c-client.xsl: +	Add support for an <indent> tag in a function body, which indents +	the <l>s it contains. + +	* debian/.cvsignore: +	debian/copyright is a generated file, so add it to +	debian/.cvsignore +	 +2004-11-08  Jamey Sharp  <jamey@minilop.net> + +	* 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  <josh@freedesktop.org> + +	* 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  <josh@freedesktop.org> + +	* 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  <josh@freedesktop.org> + +	* 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  <jamey@minilop.net> + +	* src/xcbext.h: +	* src/xcb_in.c: +	* src/client-c.xcb: +	Renamed XCBWaitReply to XCBWaitForReply for new API. + +2004-09-30  Jamey Sharp  <jamey@minilop.net> + +	* src/Makefile.am: +	Fix build failure when compiling tests. + +2004-09-29  Jamey Sharp  <jamey@minilop.net> + +	* src/xcb.h.m4: +	* src/xcb_in.c: +	Added XCBPollForEvent function from new API. + +2004-09-29  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* src/xcb_util.c: +	* src/xcbext.h: +	Oops, XCBPopcount was supposed to change argument +	types too. + +2004-09-29  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* src/xcb_out.c: +	I misread the BIG-REQUESTS specification. The long +	length field needs to count itself too. + +2004-07-24  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* src/Makefile.am: +	Importing part of patches, adding SYNC, by +	Mikko Markus Torni <mikko.markus.torni@iki.fi>. +	This needed better padding computation in XCB +	before it could be implemented cleanly. + +2004-07-02  Jamey Sharp  <jamey@minilop.net> + +	* src/Makefile.am: +	Importing part of patches, adding XC-MISC, by +	Mikko Markus Torni <mikko.markus.torni@iki.fi>. + +2004-07-02  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* src/client-c.xcb: +	* src/xcb.h.m4: +	XCB headers are now compatible with C++ source. + +2004-07-02  Jamey Sharp  <jamey@minilop.net> + +	* 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  <jamey@minilop.net> + +	* 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  <keithp@keithp.com> + +	* 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... @@ -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 <josh@freedesktop.org>  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 <josh@freedesktop.org>  Fri, 29 Oct 2004 15:11:09 -0700 + +fd.o-xcb (0.8-1) unstable; urgency=low + +  * Initial Release. + + -- Jamey Sharp <sharpone@debian.org>  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 <xcb@lists.freedesktop.org> +Uploaders: Jamey Sharp <sharpone@debian.org>, Josh Triplett <josh@freedesktop.org> +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 <sharpone@debian.org> on +Thu, 18 Mar 2004 00:48:42 -0800, and later updated by Josh Triplett +<josh@freedesktop.org>.  The package is co-maintained by the XCB developers +via the XCB mailing list <xcb@lists.freedesktop.org>. + +It was downloaded from http://xcb.freedesktop.org. + +Upstream Authors: Jamey Sharp <sharpone@debian.org> +                  Josh Triplett <josh@freedesktop.org> + +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 @@ +<!DOCTYPE html public "-//W3C//DTD HTML 4.01 Transitional//EN" +"http://www.w3.org/TR/html4/loose.dtd"> + +<html> + +<head> +  <title>Basic Graphics Programming With The XCB Library</title> +  <link href="xcb.css" rel="stylesheet" type="text/css" /> +</head> + +<body> +  <div class="title"> +    Basic Graphics Programming With The XCB Library +  </div> +  <div class="toc"> +  <ol> +    <li><a class="section" href="#intro">Introduction</a></li> +    <li><a class="section" href="#Xmodel">The client and server model of the X window system</a></li> +    <li><a class="section" href="#asynch">GUI programming: the asynchronous model</a></li> +    <li><a class="section" href="#notions">Basic XCB notions</a></li> +      <ol> +        <li><a class="subsection" href="#conn">The X Connection</a></li> +	<li><a class="subsection" href="#requestsreplies">Requests and replies: the Xlib killers</a></li> +	<li><a class="subsection" href="#gc">The Graphics Context</a></li> +	<li>Object handles</li> +	<li>Memory allocation for XCB structures</li> +	<li><a class="subsection" href="#events">Events</a></li> +      </ol> +    <li><a class="section" href="#use">Using XCB-based programs</a></li> +      <ol> +        <li><a class="subsection" href="#inst">Installation of XCB</a></li> +	<li><a class="subsection" href="#comp">Compiling XCB-based programs</a></li> +      </ol> +    <li><a class="section" href="#openconn">Opening and closing the connection to an X server</a></li> +    <li><a class="section" href="#screen">Checking basic information about a connection</a></li> +    <li><a class="section" href="#helloworld">Creating a basic window - the "hello world" program</a></li> +    <li><a class="section" href="#drawing">Drawing in a window</a></li> +      <ol> +        <li><a class="subsection" href="#allocgc">Allocating a Graphics Context</a></li> +        <li><a class="subsection" href="#changegc">Changing the attributes of a Graphics Context</a></li> +	<li><a class="subsection" href="#drawingprim">Drawing primitives: point, line, box, circle,...</a></li> +      </ol> +    <li><a class="section" href="#xevents">X Events</a></li> +      <ol> +        <li><a class="subsection" href="#register">Registering for event types using event masks</a></li> +	<li><a class="subsection" href="#loop">Receiving events: writing the events loop</a></li> +	<li><a class="subsection" href="#expose">Expose events</a></li> +	<li><a class="subsection" href="#userinput">Getting user input</a></li> +	  <ol> +	    <li><a class="subsubsection" href="#mousepressrelease">Mouse button press and release events</a></li> +	    <li><a class="subsubsection" href="#mousemvnt">Mouse movement events</a></li> +	    <li><a class="subsubsection" href="#mouseenter">Mouse pointer enter and leave events</a></li> +	    <li><a class="subsubsection" href="#focus">The keyboard focus</a></li> +	    <li><a class="subsubsection" href="#keypress">Keyboard press and release events</a></li> +	  </ol> +	<li><a class="subsection" href="#eventex">X events: a complete example</a></li> +      </ol> +    <li><a class="section" href="#font">Handling text and fonts</a></li> +      <ol> +        <li><a class="subsection" href="#fontstruct">The Font structure</a></li> +	<li>Loading a Font</li> +	<li>Assigning a Font to a Graphic Context</li> +	<li>Drawing text in a window</li> +      </ol> +    <li>Windows hierarchy</li> +      <ol> +	<li>Root, parent and child windows</li> +	<li>Events propagation</li> +      </ol> +    <li><a class="section" href="#wm">Interacting with the window manager</a></li> +      <ol> +	<li><a class="subsection" href="#wmprop">Window properties</a></li> +	<li><a class="subsection" href="#wmname">Setting the window name and icon name</a></li> +	<li>Setting preferred window size(s)</li> +	<li>Setting miscellaneous window manager hints</li> +	<li>Setting an application's icon</li> +      </ol> +    <li><a class="section" href="#winop">Simple window operations</a></li> +      <ol> +	<li><a class="subsection" href="#winmap">Mapping and un-mapping a window</a></li> +	<li><a class="subsection" href="#winconf">Configuring a window</a></li> +	<li><a class="subsection" href="#winmove">Moving a window around the screen</a></li> +	<li><a class="subsection" href="#winsize">Resizing a window</a></li> +	<li><a class="subsection" href="#winstack">Changing windows stacking order: raise and lower</a></li> +	<li>Iconifying and de-iconifying a window</li> +	<li><a class="subsection" href="#wingetinfo">Getting informations about a window</a></li> +      </ol> +    <li><a class="section" href="#usecolor">Using colors to paint the rainbow</a></li> +      <ol> +	<li><a class="subsection" href="#colormap">Color maps</a></li> +	<li><a class="subsection" href="#colormapalloc">Allocating and freeing Color Maps</a></li> +	<li><a class="subsection" href="#alloccolor">Allocating and freeing a color entry</a></li> +	<li>Drawing with a color</li> +      </ol> +    <li><a class="section" href="#pixmaps">X Bitmaps and Pixmaps</a></li> +      <ol> +	<li><a class="subsection" href="#pixmapswhat">What is a X Bitmap ? An X Pixmap ?</a></li> +	<li>Loading a bitmap from a file</li> +	<li>Drawing a bitmap in a window</li> +	<li><a class="subsection" href="#pixmapscreate">Creating a pixmap</a></li> +	<li><a class="subsection" href="#pixmapsdraw">Drawing a pixmap in a window</a></li> +	<li><a class="subsection" href="#pixmapsfree">Freeing a pixmap</a></li> +      </ol> +    <li>Messing with the mouse cursor</li> +      <ol> +	<li>Creating and destroying a mouse cursor</li> +	<li>Setting a window's mouse cursor</li> +      </ol> +    <li><a class="subsection" href="#translation">Translation of basic Xlib functions and macros</a></li> +      <ol> +        <li><a class="subsection" href="#displaystructure">Members of the Display structure</a></li> +          <ol> +            <li><a class="subsection" href="#ConnectionNumber">ConnectionNumber</a></li> +            <li><a class="subsection" href="#DefaultScreen">DefaultScreen</a></li> +            <li><a class="subsection" href="#QLength">QLength</a></li> +            <li><a class="subsection" href="#ScreenCount">ScreenCount</a></li> +            <li><a class="subsection" href="#ServerVendor">ServerVendor</a></li> +            <li><a class="subsection" href="#ProtocolVersion">ProtocolVersion</a></li> +            <li><a class="subsection" href="#ProtocolRevision">ProtocolRevision</a></li> +            <li><a class="subsection" href="#VendorRelease">VendorRelease</a></li> +            <li><a class="subsection" href="#DisplayString">DisplayString</a></li> +            <li><a class="subsection" href="#BitmapUnit">BitmapUnit</a></li> +            <li><a class="subsection" href="#BitmapBitOrder">BitmapBitOrder</a></li> +            <li><a class="subsection" href="#BitmapPad">BitmapPad</a></li> +            <li><a class="subsection" href="#ImageByteOrder">ImageByteOrder</a></li> +          </ol> +        <li><a class="subsection" href="#screenofdisplay">ScreenOfDisplay related functions</a></li> +          <ol> +            <li><a class="subsection" href="#ScreenOfDisplay">ScreenOfDisplay</a></li> +            <li><a class="subsection" href="#DefaultScreenOfDisplay">DefaultScreenOfDisplay</a></li> +            <li><a class="subsection" href="#RootWindow">RootWindow / RootWindowOfScreen</a></li> +            <li><a class="subsection" href="#DefaultRootWindow">DefaultRootWindow</a></li> +            <li><a class="subsection" href="#DefaultVisual">DefaultVisual / DefaultVisualOfScreen</a></li> +            <li><a class="subsection" href="#DefaultGC">DefaultGC / DefaultGCOfScreen</a></li> +            <li><a class="subsection" href="#BlackPixel">BlackPixel / BlackPixelOfScreen</a></li> +            <li><a class="subsection" href="#WhitePixel">WhitePixel / WhitePixelOfScreen</a></li> +            <li><a class="subsection" href="#DisplayWidth">DisplayWidth / WidthOfScreen</a></li> +            <li><a class="subsection" href="#DisplayHeight">DisplayHeight / HeightOfScreen</a></li> +            <li><a class="subsection" href="#DisplayWidthMM">DisplayWidthMM / WidthMMOfScreen</a></li> +            <li><a class="subsection" href="#DisplayHeightMM">DisplayHeightMM / HeightMMOfScreen</a></li> +            <li><a class="subsection" href="#DisplayPlanes">DisplayPlanes / DefaultDepth / DefaultDepthOfScreen / PlanesOfScreen</a></li> +            <li><a class="subsection" href="#DefaultColormap">DefaultColormap / DefaultColormapOfScreen</a></li> +            <li><a class="subsection" href="#MinCmapsOfScreen">MinCmapsOfScreen</a></li> +            <li><a class="subsection" href="#MaxCmapsOfScreen">MaxCmapsOfScreen</a></li> +            <li><a class="subsection" href="#DoesSaveUnders">DoesSaveUnders</a></li> +            <li><a class="subsection" href="#DoesBackingStore">DoesBackingStore</a></li> +            <li><a class="subsection" href="#EventMaskOfScreen">EventMaskOfScreen</a></li> +          </ol> +        <li><a class="subsection" href="#misc">Miscellaneaous macros</a></li> +          <ol> +            <li><a class="subsection" href="#DisplayOfScreen">DisplayOfScreen</a></li> +            <li><a class="subsection" href="#DisplayCells">DisplayCells / CellsOfScreen</a></li> +          </ol> +      </ol> +  </ol> +  </div> +  <div class="section"> +    <ol> +      <li class="title"><a name="intro">Introduction</a></li> +      <p> +      This tutorial is based on the +      <a href="http://users.actcom.co.il/~choo/lupg/tutorials/xlib-programming/xlib-programming.html">Xlib Tutorial</a> +      written by <a href="mailto:choor@atcom.co.il">Guy Keren</a>. The +      author allowed me to take some parts of his text, mainly the text which +      deals with the X Windows generality. +      </p> +      <p> +      This tutorial is intended to people who want to start to program +      with the <a href="http://xcb.freedesktop.org">XCB</a> +      library. As for the <a href="http://tronche.com/gui/x/xlib/introduction">Xlib</a> +      library, it is useless and a real X  +      programmer should use a much higher level of abstraction, such +      as using Motif, +      <a href="http://www.lesstif.org">LessTiff</a>, +      <a href="http://www.gtk.org">GTK</a>, +      <a href="http://www.trolltech.com">QT</a> or +      <a href="http://www.enlightenment.org">EWL</a>. However, +      we need to start somewhere. More than this, knowing how things +      work down below is never a bad idea. +      </p> +      <p> +      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. +      </p> +      <p> +      But what is XCB ? Xlib has been +      the standard C binding for the <a href="http://www.xfree86.org">X +      Window System</a> protocol for many years now. It is an +      excellent piece of work, but there are applications for which it +      is not ideal, for example +      <ul> +        <li><b>Small platforms</b>: Xlib is a large piece of code, and +	it's difficult to make it smaller</li> +        <li><b>Latency hiding</b>: Xlib requests requiring a reply are +	effectively synchronous: they block until the reply appears, +	whether the result is needed immediately or not.</li> +	<li><b>Direct access to the protocol</b>: 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.</li> +	<li><b>Threaded applications</b>: While Xlib does attempt to +	support multithreading, the API makes this difficult and +	error-prone.</li> +	<li><b>New extensions</b>: The Xlib infrastructure provides +	limited support for the new creation of X extension client side +	code.</li> +      </ul> +      </p> +      <p> +      For these reasons, among others, XCB, an X C binding, has been +      designed to solve the above problems and thus provide a base for +      <ul> +        <li>Toolkit implementation.</li> +	<li>Direct protocol-level programming.</li> +	<li>Lightweight emulation of commonly used portions of the +	Xlib API (in progress)</li> +      </ul> +      </p> +      <p></p> +      <li class="title"><a name="Xmodel">The client and server model of the X window system</a></li> +      <p> +      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. +      </p> +      <p> +      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. +      </p> +      <p> +      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). +      </p> +      <li class="title"><a name="asynch">GUI programming: the asynchronous model</a></li> +      <p> +      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). +      </p> +      <p> +      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. +      </p> +      <p> +      So the way a GUI program looks is something like that: +      <ol> +        <li>Perform initialization routines.</li> +	<li>Connect to the X server.</li> +	<li>Perform X-related initialization.</li> +	<li>While not finished:</li> +	  <ol> +  	    <li>Receive the next event from the X server.</li> +	    <li>Handle the event, possibly sending various drawing +	    requests to the X server.</li> +	    <li>If the event was a quit message, exit the loop.</li> +	  </ol> +	<li>Close down the connection to the X server. </li> +	<li>Perform cleanup operations.</li> +      </ol> +      </p> +      <p></p> +      <li class="title"><a name="notions">Basic XCB notions</a></li> +      <p> +      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. +      </p> +      <ol> +        <li class="subtitle"><a name="conn">The X Connection</a></li> +	<p> +	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. +	</p> +        <li class="subtitle"><a name="requestsreplies">Requests and +        replies: the Xlib killers</a></li> +	<p> +        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 +        <b>T_round_trip</b> that is 5 times long as the time required +        to write or read a request/reply (<b>T_write/T_read</b>): +	</p> +	<pre class="text"> +  W-----RW-----RW-----RW-----R +</pre> +        <ul> +          <li>W: Writing request</li> +          <li>-: Stalled, waiting for data</li> +          <li>R: Reading reply</li> +        </ul> +        <p> +        The total time is N * (T_write + T_round_trip + T_read). +        </p> +        <p> +        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 <b>cookie</b>, which is an +        identifier. Then, later, we ask for a reply using this +        <b>cookie</b> 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: +        </p> +	<pre class="text"> +  WWWW--RRRR +</pre> +        <p> +        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. +        </p> +        <p> +        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. +        </p> +      <pre class="code"> +#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; +} +</pre> +        <li class="subtitle"><a name="gc">The Graphic Context</a></li> +	<p> +	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. +	</p> +        <p> +        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. +        </p> +        <li class="subtitle"><a name="events">Events</a></li> +	<p> +	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. +	</p> +      </ol> +      <p></p> +      <li class="title"><a name="use">Using XCB-based programs</a></li> +      <p></p> +      <ol> +        <li class="subtitle"><a name="inst">Installation of XCB</a></li> +	<p> +	To build XCB from source, you need to have installed at +	least: +	</p> +	<ul> +	  <li>pkgconfig 0.15.0</li> +	  <li>automake 1.7</li> +	  <li>autoconf 2.50</li> +	  <li><a href="http://www.check.org">check</a></li> +	  <li><a href="http://xmlsoft.org/XSLT/">xsltproc</a></li> +	</ul> +	<p> +	You have to checkout in CVS the following modules: +	</p> +	<ul> +          <li>Xproto from xlibs</li> +	  <li>Xau from xlibs</li> +	  <li>xcb-proto</li> +	  <li>xcb</li> +	</ul> +	<p> +	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. +	</p> +	<li class="subtitle"><a name="comp">Compiling XCB-based programs</a></li> +	<p> +	Compiling XCB-based programs requires linking them with the XCB +	library. This is easily done thanks to pkgconfig: +	</p> +	<pre class="text"> +gcc -Wall prog.c -o prog `pkg-config --cflags --libs xcb` +</pre> +      </ol> +      <li class="title"><a name="openconn">Opening and closing the connection to an X server</a></li> +      <p> +      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. +      </p> +      <pre class="code"> +XCBConnection *XCBConnect (const char *displayname, +                           int        *screenp); +</pre> +      <p> +      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: +      </p> +      <pre class="code"> +#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; +} +</pre> +      <p> +      To close a connection, it suffices to use: +      </p> +      <pre class="code"> +void XCBDisconnect (XCBConnection *c); +</pre> +      <div class="comp"> +        <div class="title"> +	Comparison Xlib/XCB +	</div> +	<div class="xlib"> +	<ul> +	  <li>XOpenDisplay ()</li> +	</ul> +	</div> +	<div class="xcb"> +	<ul> +  	  <li>XCBConnect ()</li> +	</ul> +	</div> +	<div class="xlib"> +	<ul> +	  <li>XCloseDisplay ()</li> +	</ul> +	</div> +	<div class="xcb"> +	<ul> +  	  <li>XCBDisconnect ()</li> +	</ul> +	</div> +      </div> +      <p> +      </p> +      <li class="title"><a name="screen">Checking basic information about a connection</a></li> +      <p> +      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: +      </p> +      <pre class="code"> +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; +</pre> +      <p> +      We could retrieve the first screen of the connection by using the +      following function: +      </p> +      <pre class="code"> +XCBSCREENIter XCBConnSetupSuccessRepRootsIter (XCBConnSetupSuccessRep *R); +</pre> +      <p> +      Here is a small program that shows how to use this function: +      </p> +      <pre class="code"> +#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; +} +</pre> +      <li class="title"><a name="helloworld">Creating a basic window - the "hello world" program</a></li> +      <p> +      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: +      </p> +      <pre class="code"> +typedef struct { +    CARD32 xid; +} XCBWINDOW; +</pre> +      <p> +      We first ask for a new Id for our window, with this function: +      </p> +      <pre class="code"> +XCBWINDOW XCBWINDOWNew(XCBConnection *c); +</pre> +      <p> +      Then, XCB supplies the following function to create new windows: +      </p> +      <pre class="code"> +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); +</pre> +      <p> +      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 <span class="code">XCBMapWindow()</span>, whose +      prototype is +      </p> +      <pre class="code"> +XCBVoidCookie XCBMapWindow (XCBConnection *c, XCBWINDOW window); +</pre> +      <p> +      Finally, here is a small program to create a window of size +      150x150 pixels, positioned at the top-left corner of the screen: +      </p> +      <pre class="code"> +#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; +} +</pre> +      <p> +      In this code, you see one more function - <span class="code">XCBSync()</span>, 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 <span class="code">XCBFlush()</span>: +      </p> +      <pre class="code"> +int XCBFlush (XCBConnection *c); +</pre> +      <p> +      This function flushes all pending requests to the X server (much +      like the <span class="code">fflush()</span> function is used to +      flush standard output). The second function is  +      <span class="code">XCBSync()</span>: +      </p> +      <pre class="code"> +int XCBSync(XCBConnection *c, XCBGenericError **e); +</pre> +      <p> +      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.  +      </p> +      <p> +      The window that is created by the above code has a default +      background (gray). This one can be set to a specific color, +      thanks to the two last parameters of +      <span class="code">XCBCreateWindow()</span>, which are not +      described yet. See the subsections +      <a href="#winconf">Configuring a window</a> or +      <a href="#winconf">Registering for event types using event masks</a> +      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. +      </p> +      <p> +      <b>TODO</b>: one should tell what these functions return and +      about the generic error +      </p> +      <div class="comp"> +        <div class="title"> +	Comparison Xlib/XCB +	</div> +	<div class="xlib"> +	<ul> +	  <li>XCreateWindow ()</li> +	</ul> +	</div> +	<div class="xcb"> +	<ul> +  	  <li>XCBWINDOWNew ()</li> +	  <li>XCBCreateWindow ()</li> +	</ul> +	</div> +      </div> +      <p></p> +      <li class="title"><a name="drawing">Drawing in a window</a></li> +      <p> +      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. +      </p> +      <ol> +        <li class="subtitle"><a name="allocgc">Allocating a Graphics Context</a></li> +        <p> +	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: +        </p> +	<pre class="code"> +typedef struct { +    CARD32 xid; +} XCBGCONTEXT; +</pre> +        <p> +        We first ask the X server to attribute an Id to our graphic +	context with this function: +        </p> +	<pre class="code"> +XCBGCONTEXT XCBGCONTEXTNew (XCBConnection *c); +</pre> +        <p> +        Then, we set the attributes of the graphic context with this function: +        </p> +	<pre class="code"> +XCBVoidCookie XCBCreateGC (XCBConnection *c, +                           XCBGCONTEXT    cid, +			   XCBDRAWABLE    drawable, +			   CARD32         value_mask, +			   const CARD32  *value_list); +</pre> +        <p> +	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. +        </p>		    +        <pre class="code"> +#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; +} +</pre> +        <p> +        Note should be taken regarding the role of "value_mask" and +	"value_list" in the prototype of <span class="code">XCBCreateGC()</span>. 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 +	<span class="code">XCBCreateGC()</span> 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. +        </p> +	<p> +	See the next Subsection for more details. +	</p> +        <div class="comp"> +          <div class="title"> +	  Comparison Xlib/XCB +	  </div> +	  <div class="xlib"> +	  <ul> +	    <li>XCreateGC ()</li> +	  </ul> +	  </div> +	  <div class="xcb"> +	  <ul> +  	    <li>XCBGCONTEXTNew ()</li> +	    <li>XCBCreateGC ()</li> +	  </ul> +	  </div> +        </div> +        <p></p> +        <li class="subtitle"><a name="changegc">Changing the attributes of a Graphics Context</a></li> +        <p> +	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: +	</p> +	<pre class="code"> +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 */ +</pre> +        <p> +	The <span class="code">value_mask</span> parameter could take +	these values: +	</p> +	<ul> +	  <li>GCFunction</li> +	  <li>GCPlaneMask</li> +	  <li>GCForeground</li> +	  <li>GCBackground</li> +	  <li>GCLineWidth</li> +	  <li>GCLineStyle</li> +	  <li>GCCapStyle</li> +	  <li>GCJoinStyle</li> +	  <li>GCFillStyle</li> +	  <li>GCFillRule</li> +	  <li>GCTile</li> +	  <li>GCStipple</li> +	  <li>GCTileStipXOrigin</li> +	  <li>GCTileStipYOrigin</li> +	  <li>GCFont</li> +	  <li>GCSubwindowMode</li> +	  <li>GCGraphicsExposures</li> +	  <li>GCClipXOrigin</li> +	  <li>GCClipYOrigin</li> +	  <li>GCClipMask</li> +	  <li>GCDashOffset</li> +	  <li>GCDashList</li> +	  <li>GCArcMode</li> +	</ul> +	<p> +	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 <span class="code">value_mask</span>. Then +	<span class="code">value_list</span> has to be an array which +	lists the value for the respective attributes. See Subsection +	Drawing with a color to have an example. +	</p> +	<p> +	<b>TODO</b>: set the links of the 3 subsections, once they will +	be written :) +	</p> +	<p> +	<b>TODO</b>: give an example which sets several attributes. +	</p> +        <li class="subtitle"><a name="drawingprim">Drawing primitives: point, line, box, circle,...</a></li> +        <p> +	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. +	</p> +	<p> +	To draw a point, or several points, we use +	</p> +	<pre class="code"> +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 */ +</pre> +	<p> +	The <span class="code">coordinate_mode</span> parameter +	specifies the coordinate mode.  Available values are +	</p> +	<ul> +	  <li><span class="code">CoordModeOrigin</span></li> +	  <li><span class="code">CoordModePrevious</span></li> +	</ul> +	<p> +	The <span class="code">XCBPOINT</span> type is just a +	structure with two fields (the coordinates of the point): +	</p> +	<pre class="code"> +typedef struct { +    INT16 x; +    INT16 y; +} XCBPOINT; +</pre> +        <p> +	You could see an example in xpoints.c. <b>TODO</b> Set the link. +	</p> +	<p> +	To draw a line, or a polygonal line, we use +	</p> +	<pre class="code"> +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 */ +</pre> +	<p> +	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. +	</p> +	<p> +	To draw a segment, or several segments, we use +	</p> +	<pre class="code"> +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 */ +</pre> +	<p> +	The <span class="code">XCBSEGMENT</span> type is just a +	structure with four fields (the coordinates of the two points +	that define the segment): +	</p> +	<pre class="code"> +typedef struct { +    INT16 x1; +    INT16 y1; +    INT16 x2; +    INT16 y2; +} XCBSEGMENT; +</pre> +	<p> +	To draw a rectangle, or several rectangles, we use +	</p> +	<pre class="code"> +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 */ +</pre> +	<p> +	The <span class="code">XCBRECTANGLE</span> type is just a +	structure with four fields (the coordinates of the top-left +	corner of the rectangle, and its width and height): +	</p> +	<pre class="code"> +typedef struct { +    INT16 x; +    INT16 y; +    CARD16 width; +    CARD16 height; +} XCBRECTANGLE; +</pre> +	<p> +	<b>TODO</b>: there's no coordinate_mode. Is it normal ? +	</p> +	<p> +	To draw an elliptical arc, or several elliptical arcs, we use +	</p> +	<pre class="code"> +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 */ +</pre> +	<p> +	The <span class="code">XCBARC</span> type is a structure with +	six fields: +	</p> +	<pre class="code"> +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; +</pre> +	<div class="emph"> +	<p> +	Note: the angles are expressed in units of 1/64 of a degree, +	so to have an angle of 90 degrees, starting at 0, +	<span class="code">angle1 = 0</span> and +	<span class="code">angle2 = 90 << 6</span>. Positive angles +	indicate counterclockwise motion, while  negative angles +	indicate clockwise motion. +	</p> +	</div> +	<p> +	<b>TODO</b>: there's no coordinate_mode. Is it normal ? +	</p> +	<p> +	<b>TODO</b>: I think that (x,y) should be the center of the +	ellipse, and (width, height) the radius. It's more logical. +	</p> +	<p> +	The corresponding function which fill inside the geometrical +	object are listed below, without  further explanation, as they +	are used as the above functions. +	</p> +	<p> +	To Fill a polygon defined by the points given as arguments , +	we use +	</p> +	<pre class="code"> +XCBVoidCookie XCBFillPoly (XCBConnection  *c, +                           XCBDRAWABLE     drawable, +			   XCBGCONTEXT     gc, +			   CARD8           shape, +			   CARD8           coordinate_mode, +			   CARD32          points_len, +			   const XCBPOINT *points); +</pre> +	<p> +	The <span class="code">shape</span> parameter specifies a +	shape that helps the server to improve performance. Available +	values are +	</p> +	<ul> +	  <li><span class="code">Complex</span></li> +	  <li><span class="code">Convex</span></li> +	  <li><span class="code">Nonconvex</span></li> +	</ul> +	<p> +	To fill one or several rectangles, we use +	</p> +	<pre class="code"> +XCBVoidCookie XCBPolyFillRectangle (XCBConnection      *c, +                                    XCBDRAWABLE         drawable, +				    XCBGCONTEXT         gc, +				    CARD32              rectangles_len, +				    const XCBRECTANGLE *rectangles); +</pre> +	<p> +	To fill one or several arcs, we use +	</p> +	<pre class="code"> +XCBVoidCookie XCBPolyFillArc (XCBConnection *c, +                              XCBDRAWABLE    drawable, +			      XCBGCONTEXT    gc, +			      CARD32         arcs_len, +			      const XCBARC  *arcs); +</pre> +        <p></p> +	<p> +	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. +	</p> +	<pre class="code"> +#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; +} +</pre> +      </ol> +      <li class="title"><a name="xevents">X Events</a></li> +      <p> +      In an X program, everything is driven by events. Event painting +      on the screen is sometimes done as a response to an event (an +      <span class="code">Expose</span> 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. +      </p> +      <ol> +        <li class="subtitle"><a name="register">Registering for event types using event masks</a></li> +	<p> +	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 ?) +	</p> +	<p> +	In XCB, you use the "value_mask" and "value_list" data in the +	<span class="code">XCBCreateWindow()</span> function to +	register for events. Here is how we register for +	<span class="code">Expose</span> event when creating a window: +	</p> +	<pre class="code"> +  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); +</pre> +        <p> +	<span class="code">ExposureMask</span> 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: +	</p> +	<pre class="code"> +  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); +</pre> +	<p> +	This registers for <span class="code">Expose</span> events as +	well as for mouse button presses insode the created +	window. You should note that a mask may represent several +	event sub-types. +	</p> +	<p> +	The values that a mask could take are given +	by the <span class="code">XCBCW</span> enumeration: +	</p> +	<pre class="code"> +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; +</pre> +	<div class="emph"> +        <p>Note: we must be careful when setting the values of the valwin +        parameter, as they have to follow the order the +	<span class="code">XCBCW</span> enumeration. Here is an +        example: +	</p> +	</div> +	<pre class="code"> +  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 */ +</pre> +	<p> +	If the window has already been created, we can use the +	<span class="code">XCBConfigureWindow()</span> function to set +	the events that the window will receive. The subsection +	<a href="#winconf">Configuring a window</a> shows its +	prototype. As an example, here is a piece of code that +	configures the window to receive the +	<span class="code">Expose</span> and +	<span class="code">ButtonPressMask</span> events: +	</p> +	<pre class="code"> +const static CARD32 values[] = { ExposureMask | ButtonPressMask }; + +/* The connection c and the window win are supposed to be defined */ + +XCBConfigureWindow (c, win, XCBCWEventMask, values); +</pre> +	<div class="emph"> +	<p> +	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. +	</p> +	</div> +        <li class="subtitle"><a name="loop">Receiving events: writing the events loop</a></li> +	<p> +	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: +	</p> +	<ul> +	  <li> +	  <span class="code">XCBWaitEvent (XCBConnection *c)</span> +	  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 +	  <span class="code">NULL</span> if an error occurs. +	  </li> +	  <br /> +	  <li> +	  <span class="code">XCBPollForEvent (XCBConnection *c, int +	  *error)</span> 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 <span class="code">NULL</span> if there is +	  no event. If an error occurs, the parameter <span +	  class="code">error</span> will be filled with the error +	  status. +	  </li>  +	</ul> +	<p> +	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 <span class="code">XCBWaitEvent</span>, which +	is similar to an event Xlib loop using only <span +	class="code">XNextEvent</span>: +	</p> +	<pre class="code"> +  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); +    } +</pre> +	<p> +	You will certainly want to use <span +	class="code">XCBPollForEvent(XCBConnection *c, int +	*error)</span> if, in Xlib, you use <span +	class="code">XPending</span>: +	</p> +	<pre class="code"> +  while (XPending (display)) +    { +      XEvent ev; + +      XNextEvent(d, &ev); +       +      /* Manage your event */ +    } +</pre> +        <p> +	Such a loop in XCB looks like: +	</p> +	<pre class="code"> +  XCBGenericEvent *ev; + +  while ((ev = XCBPollForEvent (conn, 0))) +    { +      /* Manage your event */ +    } +</pre> +	<p> +	The events are managed in the same way as with <span +	class="code">XCBWaitEvent</span>. +	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. +	</p> +	<div class="comp"> +	  <div class="title"> +	    Comparison Xlib/XCB +	  </div> +	  <div class="xlib"> +	    <ul> +	      <li>XNextEvent ()</li> +	      </ul> +	  </div> +	  <div class="xcb"> +	    <ul> +	      <li>XCBWaitEvent ()</li> +	    </ul> +	  </div> +	  <div class="xlib"> +	    <ul> +	      <li>XPending ()</li> +	      <li>XNextEvent ()</li> +	    </ul> +	  </div> +	  <div class="xcb"> +	    <ul> +	      <li>XCBPollForEvent ()</li> +	      <br /> +	    </ul> +	  </div> +	</div> +	<p /> +        <li class="subtitle"><a name="expose">Expose events</a></li> +	<p> +	The <span class="code">Expose</span> 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: +	  <ul> +  	    <li>A window that covered part of our window has moved +	    away, exposing part (or all) of our window.</li> +	    <li>Our window was raised above other windows.</li> +	    <li>Our window mapped for the first time.</li> +	    <li>Our window was de-iconified.</li> +	  </ul> +	</p> +	<p> +	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. +	</p> +	<p> +	When we get an <span class="code">Expose</span> event, we +	should take the event's data from the members of the following +	structure: +	</p> +	<pre class="code"> +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; +</pre> +        <li class="subtitle"><a name="userinput">Getting user input</a></li> +	<p> +	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. +	</p> +	<ol> +  	  <li class="subsubtitle"><a name="mousepressrelease">Mouse button press and release events</a></li> +	  <p> +	  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: +	  </p> +	  <ul> +	    <li><span class="code">ButtonPressMask</span>: notify us +	    of any button that was pressed in one of our windows.</li> +	    <li><span class="code">ButtonReleaseMask</span>: notify us +	    of any button that was released in one of our windows.</li> +	  </ul> +	  <p> +	  The structure to be checked for in our events loop is the +	  same for these two events, and is the following: +	  </p> +	  <pre class="code"> +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; +</pre> +          <p> +	  The <span class="code">time</span> 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). +	  </p> +          <p> +	  The <span class="code">state</span> field is a mask of the buttons held down during +	  the event. It is a bitwise OR of any of the following: +	  </p> +	  <ul> +	    <li><span class="code">Button1Mask</span></li> +	    <li><span class="code">Button2Mask</span></li> +	    <li><span class="code">Button3Mask</span></li> +	    <li><span class="code">Button4Mask</span></li> +	    <li><span class="code">Button5Mask</span></li> +	    <li><span class="code">ShiftMask</span></li> +	    <li><span class="code">LockMask</span></li> +	    <li><span class="code">ControlMask</span></li> +	    <li><span class="code">Mod1Mask</span></li> +	    <li><span class="code">Mod2Mask</span></li> +	    <li><span class="code">Mod3Mask</span></li> +	    <li><span class="code">Mod4Mask</span></li> +	    <li><span class="code">Mod5Mask</span></li> +	  </ul> +	  <p> +	  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). +	  </p> +	  <p> +	  <b>TODO:</b> Problem: it seems that the state does not +	  change when clicking with various buttons. +	  </p> +  	  <li class="subsubtitle"><a name="mousemvnt">Mouse movement events</a></li> +	  <p>  +	  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: +	  </p> +	  <ul> +	    <li><span class="code">PointerMotionMask</span>: events of +	    the pointer moving in one of the windows controlled by our +	    application, while no mouse button is held pressed.</li> +	    <li><span class="code">ButtonMotionMask</span>: Events of +	    the pointer moving while one or more of the mouse buttons +	    is held pressed.</li> +	    <li><span class="code">Button1MotionMask</span>: same as +	    <span class="code">ButtonMotionMask</span>, but only when +	    the 1st mouse button is held pressed.</li> +	    <li><span class="code">Button2MotionMask</span>, +	    <span class="code">Button3MotionMask</span>, +	    <span class="code">Button4MotionMask</span>, +	    <span class="code">Button5MotionMask</span>: same as +	    <span class="code">Button1MotionMask</span>, but +	    respectively for 2nd, 3rd, 4th and 5th mouse button.</li> +	  </ul> +	  <p> +	  The structure to be checked for in our events loop is the +	  same for these events, and is the following: +	  </p> +	  <pre class="code"> +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; +</pre> +  	  <li class="subsubtitle"><a name="mouseenter">Mouse pointer enter and leave events</a></li> +	  <p> +	  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: +	  </p> +	  <ul> +	    <li><span class="code">EnterWindowMask</span>: notify us +	    when the mouse pointer enters any of our controlled +	    windows.</li> +	    <li><span class="code">LeaveWindowMask</span>: notify us +	    when the mouse pointer leaves any of our controlled +	    windows.</li> +	  </ul> +	  <p> +	  The structure to be checked for in our events loop is the +	  same for these two events, and is the following: +	  </p> +	  <pre class="code"> +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; +</pre> +  	  <li class="subsubtitle"><a name="focus">The keyboard focus</a></li> +	  <p> +	  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...). +	  </p> +  	  <li class="subsubtitle"><a name="keypress">Keyboard press and release events</a></li> +	  <p> +	  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: +	  </p> +	  <ul> +	    <li><span class="code">KeyPressMask</span>: notify us when +	    a key was pressed while any of our controlled windows had +	    the keyboard focus.</li> +	    <li><span class="code">KeyReleaseMask</span>: notify us +	    when a key was released while any of our controlled +	    windows had the keyboard focus.</li> +	  </ul> +	  <p> +	  The structure to be checked for in our events loop is the +	  same for these two events, and is the following: +	  </p> +	  <pre class="code"> +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; +</pre> +        <p> +	The <span class="code">detail</span> field refer to the +	physical key on the keyboard. +	</p> +	<p> +        <b>TODO:</b> Talk about getting the ASCII code from the key code. +	</p> +	</ol> +        <li class="subtitle"><a name="eventex">X events: a complete example</a></li> +	<p> +	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. +	</p> +        <pre class="code"> +#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; +} +</pre> +      </ol> +      <li class="title"><a name="font">Handling text and fonts</a></li> +      <p> +      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. +      </p> +      <ol> +        <li class="subtitle"><a name="fontstruct">The Font structure</a></li> +	<p> +	In order to support flexible fonts, a font structure is +	defined. You know what ? Its an Id: +	</p> +	<pre class="code"> +typedef struct { +    CARD32 xid; +} XCBFONT; +</pre> +	<p> +	It is used to contain information about a font, and is passed +	to several functions that handle fonts selection and text drawing. +	</p> +      </ol> +      <li class="title"><a name="wm">Interacting with the window manager</a></li> +      <p> +      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. +      </p> +      <ol> +        <li class="subtitle"><a name="wmprop">Window properties</a></li> +	<p> +	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). +	</p> +	<p> +	The property and its type (a string, an integer, etc) are +	Id. Their type are <span class="code">XCBATOM</span>: +	</p> +	<pre class="code"> +typedef struct { +    CARD32 xid; +} XCBATOM; +</pre> +	<p> +	To change the property of a window, we use the following +	function: +	</p> +	<pre class="code"> +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 */ +</pre> +	<p> +	The <span class="code">mode</span> parameter coud be one of +	the following value (defined in the X.h header file): +	</p> +	<ul> +	  <li>PropModeReplace</li> +	  <li>PropModePrepend</li> +	  <li>PropModeAppend</li> +	</ul> +	<p></p> +        <li class="subtitle"><a name="wmname">Setting the window name and icon name</a></li> +	<p> +	The firt thing we want to do would be to set the name for our +	window. This is done using the +	<span class="code">XCBChangeProperty()</span> 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 +	<span class="code">WM_NAME</span> (and +	<span class="code">WM_ICON_NAME</span> for the iconified +	window) and its type is <span class="code">STRING</span>. Here +	is an example of utilization: +	</p> +	<pre class="code"> +#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; +} +</pre> +	<div class="emph"> +        <p>Note: the use of the atoms needs our program to be compiled +        and linked against xcb_atom, so that we have to use +	</p> +	</div> +	<pre class="text"> +gcc prog.c -o prog `pkg-config --cflags --libs xcb_atom` +</pre> +	<div class="emph"> +        <p> +	for the program to compile fine. +	</p> +	</div> +      </ol> +      <li class="title"><a name="winop">Simple window operations</a></li> +      <p> +      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. +      </p> +      <ol> +        <li class="subtitle"><a name="winmap">Mapping and un-mapping a window</a></li> +	<p> +	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. +	</p> +	<p> +	To map a window, you use the following function: +	</p> +	<pre class="code"> +XCBVoidCookie XCBMapWindow(XCBConnection *c, XCBWINDOW window); +</pre> +        <p> +	To have a simple example, see the <a href="#helloworld">example</a> +	above. The mapping operation will cause an +	<span class="code">Expose</span> event to be sent to our +	application, unless the window is completely covered by other +	windows. +	</p> +	<p> +	Un-mapping a window is also simple. You use the function +	</p> +	<pre class="code"> +XCBVoidCookie XCBUnmapWindow(XCBConnection *c, XCBWINDOW window); +</pre> +	<p> +	The utilization of this function is the same as +	<span class="code">XCBMapWindow()</span>. +	</p> +        <li class="subtitle"><a name="winconf">Configuring a window</a></li> +	<p> +	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: +	</p> +	<pre class="code"> +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 */ +</pre> +        <p> +	We set the <span class="code">value_mask</span> to one or +	several mask values that are in the X.h header: +	<ul> + 	  <li><span class="code">CWX</span>: new x coordinate of the window's top left corner</li> +	  <li><span class="code">CWY</span>: new y coordinate of the window's top left corner</li> +	  <li><span class="code">CWWidth</span>: new width of the window</li> +	  <li><span class="code">CWHeight</span>: new height of the window</li> +	  <li><span class="code">CWBorderWidth</span>: new width of the border of the window</li> +	  <li><span class="code">CWSibling</span></li> +	  <li><span class="code">CWStackMode</span>: the new stacking order</li> +	</ul> +	</p> +	<p> +	We then give to <span class="code">value_mask</span> the new +	value. We now describe how to use +	<span class="code">XCBConfigureWindow</span> in some useful +	situations. +	</p> +        <li class="subtitle"><a name="winmove">Moving a window around the screen</a></li> +	<p> +	An operation we might want to do with windows is to move them +	to a different location. This can be done like this: +	</p> +	<pre class="code"> +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); +</pre> +	<p> +	Note that when the window is moved, it might get partially +	exposed or partially hidden by other windows, and thus we +	might get <span class="code">Expose</span> events due to this +	operation. +	</p> +        <li class="subtitle"><a name="winsize">Resizing a window</a></li> +	<p> +	Yet another operation we can do is to change the size of a +	window. This is done using the following code: +	</p> +	<pre class="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); +</pre> +	<p> +	We can also combine the move and resize operations using one +	single call to <span class="code">XCBConfigureWindow</span>: +	</p> +	<pre class="code"> +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); +</pre> +        <li class="subtitle"><a name="winstack">Changing windows stacking order: raise and lower</a></li> +	<p> +	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: +	</p> +	<pre class="code"> +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); +</pre> +	<pre class="code"> +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); +</pre> +        <li class="subtitle"><a name="wingetinfo">Getting information about a window</a></li> +	<p> +	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 +	</p> +	<pre class="code"> +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; +</pre> +        <p> +	XCB fill this structure with two functions: +	</p> +	<pre class="code"> +XCBGetGeometryCookie  XCBGetGeometry      (XCBConnection         *c, +                                           XCBDRAWABLE            drawable); +XCBGetGeometryRep    *XCBGetGeometryReply (XCBConnection         *c, +                                           XCBGetGeometryCookie   cookie, +                                           XCBGenericError      **e); +</pre> +        <p> +	You use them as follows: +	</p> +	<pre class="code"> +  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); +</pre> +        <p> +	Remark that you have to free the structure, as +	<span class="code">XCBGetGeometryReply</span> allocates a +	newly one. +	</p> +        <p> +	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. +	</p> +	<p> +	To get the Id of the parent window, we need this structure: +	</p> +	<pre class="code"> +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; +</pre> +        <p> +	To fill this structure, we use these two functions: +	</p> +	<pre class="code"> +XCBQueryTreeCookie XCBQueryTree      (XCBConnection       *c, +                                      XCBWINDOW            window); +XCBQueryTreeRep   *XCBQueryTreeReply (XCBConnection       *c, +                                      XCBQueryTreeCookie   cookie, +				      XCBGenericError    **e); +</pre> +        <p> +	The translated coordinates will be found in this structure: +	</p> +	<pre class="code"> +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; +</pre> +        <p> +	As usual, we need two functions to fill this structure: +	</p> +	<pre class="code"> +XCBTranslateCoordinatesCookie XCBTranslateCoordinates      (XCBConnection                  *c, +                                                            XCBWINDOW                       src_window, +							    XCBWINDOW                       dst_window, +							    INT16                           src_x, +							    INT16                           src_y); +XCBTranslateCoordinatesRep   *XCBTranslateCoordinatesReply (XCBConnection                 *c, +							    XCBTranslateCoordinatesCookie   cookie, +							    XCBGenericError               **e); +</pre> +        <p> +	We use them as follows: +	</p> +	<pre class="code"> +  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); +</pre> +        <p> +	Of course, as for <span class="code">geom</span>, +	<span class="code">tree</span> and +	<span class="code">trans</span> have to be freed. +	</p> +	<p> +	The work is a bit hard, but XCB is a very low-level library. +	</p> +	<p> +	<b>TODO:</b> the utilization of these functions should be a +	prog, which displays the coordinates of the window. +	</p> +	<p> +	There is another structure that gives informations about our window: +	</p> +	<pre class="code"> +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; +</pre> +        <p> +	XCB supplies these two functions to fill it: +	</p> +	<pre class="code"> +XCBGetWindowAttributesCookie XCBGetWindowAttributes      (XCBConnection                 *c,  +                                                          XCBWINDOW                      window); +XCBGetWindowAttributesRep   *XCBGetWindowAttributesReply (XCBConnection                 *c,  +                                                          XCBGetWindowAttributesCookie   cookie, +							  XCBGenericError              **e); +</pre> +        <p> +	You use them as follows: +	</p> +	<pre class="code"> +  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); +</pre> +        <p> +	As for <span class="code">geom</span>, +	<span class="code">attr</span> has to be freed. +	</p> +      </ol> +      <li class="title"><a name="usecolor">Using colors to paint the rainbow</a></li> +      <p> +      Up until now, all our painting operation were done using black +      and white. We will (finally) see now how to draw using colors. +      </p> +      <ol> +        <li class="subtitle"><a name="colormap">Color maps</a></li> +	<p> +	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. +	</p>       +	<p> +	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. +	</p> +	<p> +	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. +	</p> +	<p> +	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. +	</p> +        <li class="subtitle"><a name="colormapalloc">Allocating and freeing Color Maps</a></li> +	<p> +	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. +	</p> +	<p> +	In XCB, a color map is (as often in X) an Id: +	</p> +	<pre class="code"> +typedef struct { +    CARD32 xid; +} XCBCOLORMAP; +</pre> +	<p> +	In order to access the screen's default color map, you just +	have to retrieve the <span class="code">default_colormap</span>  +	field of the <span class="code">XCBSCREEN</span> structure +	(see Section +	<a href="#screen">Checking basic information about a connection</a>): +	</p> +	<pre class="code"> +#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; +} +</pre> +	<p> +	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). +	</p> +	<p> +	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: +	</p> +	<pre class="code"> +XCBCOLORMAP XCBCOLORMAPNew (XCBConnection *c); +</pre> +	<p> +	Then, we create the color map with +	</p> +	<pre class="code"> +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 */ +</pre> +	<p> +	Here is an example of creation of a new color map: +	</p> +	<pre class="code"> +#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; +} +</pre> +        <p> +	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. +	</p> +	<p> +	To free  a color map, it suffices to use this function: +	</p> +	<pre class="code"> +XCBVoidCookie XCBFreeColormap (XCBConnection *c,   /* The connection */ +                               XCBCOLORMAP cmap);  /* The color map */ +</pre> +        <div class="comp"> +          <div class="title"> +	    Comparison Xlib/XCB +          </div> +  	  <div class="xlib"> +	  <ul> +	    <li>XCreateColormap ()</li> +	  </ul> +	  </div> +	  <div class="xcb"> +	  <ul> +            <li>XCBCOLORMAPNew ()</li> +	    <li>XCBCreateColormap ()</li> +	  </ul> +	  </div> +	  <div class="xlib"> +	  <ul> +	    <li>XFreeColormap ()</li> +	  </ul> +	  </div> +  	  <div class="xcb"> +	  <ul> +	    <li>XCBFreeColormap ()</li> +	  </ul> +	  </div> +        </div> +	<p></p> +        <li class="subtitle"><a name="alloccolor">Allocating and freeing a color entry</a></li> +	<p> +	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: +	</p> +	<pre class="code"> +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; +</pre> +      <p> +      XCB supplies these two functions to fill it: +      </p> +      <pre class="code"> +XCBAllocColorCookie XCBAllocColor      (XCBConnection *c, +                                        XCBCOLORMAP    cmap, +				        CARD16         red, +			                CARD16         green, +				        CARD16         blue); +XCBAllocColorRep   *XCBAllocColorReply (XCBConnection        *c, +                                        XCBAllocColorCookie   cookie, +					XCBGenericError     **e); +</pre> +      <p> +      The fuction <span class="code">XCBAllocColor()</span> takes the +      3 RGB components as parameters (red, green and blue). Here is an +      example of using these functions: +      </p> +      <pre class="code"> +#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; +} +</pre> +      <p> +      As <span class="code">XCBAllocColorReply()</span> allocates +      memory, you have to free <span class="code">rep</span>. +      </p> +      <p> +      <b>TODO</b>: Talk about freeing colors. +      </p> +      </ol> +      <li class="title"><a name="pixmaps">X Bitmaps and Pixmaps</a></li> +      <p> +      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. +      </p> +      <p> +      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). +      </p> +      <ol> +        <li class="subtitle"><a name="pixmapswhat">What is a X Bitmap ? An X Pixmap ?</a></li> +	<p> +	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). +	</p> +	<p> +	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. +	</p> +	<p> +	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: +	</p> +	<pre class="code"> +typedef struct { +    CARD32 xid; +} XCBPIXMAP; +</pre> +	<p> +	In order to make the difference between a window and a pixmap, +	XCB introduces a drawable type, which is a <b>union</b> +	</p> +	<pre class="code"> +typedef union { +    XCBWINDOW window; +    XCBPIXMAP pixmap; +} XCBDRAWABLE; +</pre> +        <p> +	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 <span class="code">XCBDRAWABLE</span> +	</p> +	<div class="emph"> +	<p> +	Remark: In Xlib, there is no specific difference between a +	<span class="code">Drawable</span>, a +	<span class="code">Pixmap</span> or a +	<span class="code">Window</span>: all are 32 bit long +	integer. +	</p> +	</div> +        <li class="subtitle"><a name="pixmapscreate">Creating a pixmap</a></li> +	<p> +	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. +	</p> +	<p> +	To create a new pixmap, we first ask the X server to give an +	Id to our pixmap, with this function:  +	</p> +	<pre class="code"> +XCBPIXMAP XCBPIXMAPNew (XCBConnection *c); +</pre> +        <p> +	 Then, XCB supplies the following function to create new pixmaps: +	</p> +	<pre class="code"> +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) */ +</pre> +        <p> +	<b>TODO</b>: Explain the drawable parameter, and give an +	example (like xpoints.c) +	</p> +        <li class="subtitle"><a name="pixmapsdraw"></a>Drawing a pixmap in a window</li> +	<p> +	Once we got a handle to a pixmap, we can draw it on some +	window, using the following function: +	</p> +	<pre class="code"> +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 */ +</pre> +	<p> +	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. +	</p> +	<p> +	<b>One important note should be made</b>: 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 +	<span class="code">XCBCopyPlane</span> 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. +	</p> +        <li class="subtitle"><a name="pixmapsfree"></a>Freeing a pixmap</li> +	<p> +	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: +	</p> +	<pre class="code"> +XCBVoidCookie XCBFreePixmap (XCBConnection *c,        /* Pointer to the XCBConnection structure */ +                             XCBPIXMAP      pixmap);  /* A given pixmap */ +</pre> +	<p> +	Of course, after having freed it, we must not try accessing +	the pixmap again. +	</p> +	<p> +	<b>TODO</b>: Give an example, or a link to xpoints.c +	</p> +      </ol> +      <li class="title"><a name="translation">Translation of basic Xlib functions and macros</a></li> +      <p> +      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. +      </p> +      <ol> +        <li class="subtitle"><a name="displaystructure">Members of the Display structure</a></li> +        In this section, we look at how to translate the macros that +        returns some members of the <span class="code">Display</span> +        structure. They are obtain by using a function that requires a +        <span class="code">XCBConnection *</span> or a member of the +        <span class="code">XCBConnSetupSuccessRep</span> structure +        (via the function <span class="code">XCBGetSetup</span>), or +        a function that requires that structure. +        <ol> +          <li class="subtitle"><a name="ConnectionNumber">ConnectionNumber</a></li> +          <p> +          This number is the file descriptor that connects the client +          to the server. You just have to use that function: +          </p> +          <pre class="code"> +int XCBGetFileDescriptor(XCBConnection *c); +</pre> +          <li class="subtitle"><a name="DefaultScreen"></a>DefaultScreen</li> +          <p> +          That number is not stored by XCB. It is returned in the +          second parameter of the function <span class="code"><a href="#openconn">XCBConnect</a></span>. +          Hence, you have to store it yourself if you want to use +          it. Then, to get the <span class="code">XCBSCREEN</span> +          structure, you have to iterate on the screens. +          The equivalent function of the Xlib's +          <span class="code">ScreenOfDisplay</span> function can be +          found <a href="#ScreenOfDisplay">below</a>. OK, here is the +          small piece of code to get that number: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="QLength"></a>QLength</li> +          <p> +          Not documented yet. +          </p> +          <li class="subtitle"><a name="ScreenCount"></a>ScreenCount</li> +          <p> +          You get the count of screens with the functions +          <span class="code">XCBGetSetup</span> +          and +          <span class="code">XCBConnSetupSuccessRepRootsIter</span> +          (if you need to iterate): +          </p> +          <pre class="code"> +XCBConnection *c; +int            screen_count; + +/* you init the connection */ + +screen_count = XCBConnSetupSuccessRepRootsIter (XCBGetSetup (c)).rem; + +/* screen_count contains now the count of screens */ +</pre> +          <p> +          If you don't want to iterate over the screens, a better way +          to get that number is to use +          <span class="code">XCBConnSetupSuccessRepRootsLength</span>: +          </p> +          <pre class="code"> +XCBConnection *c; +int            screen_count; + +/* you init the connection */ + +screen_count = XCBConnSetupSuccessRepRootsLength (XCBGetSetup (c)); + +/* screen_count contains now the count of screens */ +</pre> +          <li class="subtitle"><a name="ServerVendor"></a>ServerVendor</li> +          <p> +          You get the name of the vendor of the server hardware with +          the functions <span class="code">XCBGetSetup</span> +          and +          <span +          class="code">XCBConnSetupSuccessRepVendor</span>. Beware +          that, unlike Xlib, the string returned by XCB is not +          necessarily null-terminaled: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="ProtocolVersion"></a>ProtocolVersion</li> +          <p> +          You get the major version of the protocol in the +          <span class="code">XCBConnSetupSuccessRep</span> +          structure, with the function <span class="code">XCBGetSetup</span>: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="ProtocolRevision"></a>ProtocolRevision</li> +          <p> +          You get the minor version of the protocol in the +          <span class="code">XCBConnSetupSuccessRep</span> +          structure, with the function <span class="code">XCBGetSetup</span>: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="VendorRelease"></a>VendorRelease</li> +          <p> +          You get the number of the release of the server hardware in the +          <span class="code">XCBConnSetupSuccessRep</span> +          structure, with the function <span class="code">XCBGetSetup</span>: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DisplayString"></a>DisplayString</li> +          <p> +          The name of the display is not stored in XCB. You have to +          store it by yourself. +          </p> +          <li class="subtitle"><a name="BitmapUnit"></a>BitmapUnit</li> +          <p> +          You get the bitmap scanline unit in the +          <span class="code">XCBConnSetupSuccessRep</span> +          structure, with the function <span class="code">XCBGetSetup</span>: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="BitmapBitOrder"></a>BitmapBitOrder</li> +          <p> +          You get the bitmap bit order in the +          <span class="code">XCBConnSetupSuccessRep</span> +          structure, with the function <span class="code">XCBGetSetup</span>: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="BitmapPad"></a>BitmapPad</li> +          <p> +          You get the bitmap scanline pad in the +          <span class="code">XCBConnSetupSuccessRep</span> +          structure, with the function <span class="code">XCBGetSetup</span>: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="ImageByteOrder"></a>ImageByteOrder</li> +          <p> +          You get the image byte order in the +          <span class="code">XCBConnSetupSuccessRep</span> +          structure, with the function <span class="code">XCBGetSetup</span>: +          </p> +          <pre class="code"> +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 */ +</pre> +        </ol> +      <li class="subtitle"><a name="screenofdisplay">ScreenOfDisplay related functions</a></li> +      <p> +      in Xlib, <span class="code">ScreenOfDisplay</span> returns a +      <span class="code">Screen</span> structure that contains +      several characteristics of your screen. XCB has a similar +      structure (<span class="code">XCBSCREEN</span>), +      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 <a href="#ScreenOfDisplay">ScreenOfDisplay</a> just below. +      </p> +      <p> +      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 <span class="code">ScreenOfDisplay</span>, +      and the other that uses the <span class="code">Screen</span> structure. +      This might be a bit confusing. As mentioned above, with XCB, it +      is better to store the <span class="code">XCBSCREEN</span> +      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. +      </p> +        <ol> +          <li class="subtitle"><a name="ScreenOfDisplay">ScreenOfDisplay</a></li> +          <p> +          This function returns the Xlib <span class="code">Screen</span> +          structure. With XCB, you iterate over all thee screens and +          once you get the one you want, you return it: +          </p> +          <pre class="code"><a name="ScreenOfDisplay"></a> +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; +} +</pre> +          <p> +          As mentioned above, you might want to store the value +          returned by this function. +          </p> +          <p> +          All the functions below will use the result of that +          fonction, as they just grab a specific member of the +          <span class="code">XCBSCREEN</span> structure. +          </p> +          <li class="subtitle"><a name="DefaultScreenOfDisplay"></a>DefaultScreenOfDisplay</li> +          <p> +          It is the default screen that you obtain when you connect to +          the X server. It suffices to call the <a href="#ScreenOfDisplay">ScreenOfDisplay</a> +          function above with the connection and the number of the +          default screen. +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="RootWindow">RootWindow / RootWindowOfScreen</a></li> +          <p> +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DefaultRootWindow">DefaultRootWindow</a></li> +          <p> +          It is the root window of the default screen. So, you call +          <a name="ScreenOfDisplay">ScreenOfDisplay</a> with the +          default screen number and you get the +          <a href="#RootWindow">root window</a> as above: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DefaultVisual">DefaultVisual / DefaultVisualOfScreen</a></li> +          <p> +          While a Visual is, in Xlib, a structure, in XCB, there are +          two types: <span class="code">XCBVISUALID</span>, which is +          the Id of the visual, and <span class="code">XCBVISUALTYPE</span>, +          which corresponds to the Xlib Visual. To get the Id of the +          visual of a screen, just get the +           <span class="code">root_visual</span> +           member of a <span class="code">XCBSCREEN</span>: +          </p> +          <pre class="code"> +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 */ +</pre> +          <p> +          To get the <span class="code">XCBVISUALTYPE</span> +          structure, it's a bit less easier. You have to get the +          <span class="code">XCBSCREEN</span> structure that you want, +          get its <span class="code">root_visual</span> member, +          then iterate on the <span class="code">XCBDEPTH</span>s +          and the <span class="code">XCBVISUALTYPE</span>s, and compare +          the <span class="code">XCBVISUALID</span> of these <span class="code">XCBVISUALTYPE</span>s: +          with <span class="code">root_visual</span>: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DefaultGC">DefaultGC / DefaultGCOfScreen</a></li> +          <p> +          This default Graphic Context is just a newly created Graphic +          Context, associated to the root window of a +          <span class="code">XCBSCREEN</span>, +          using the black white pixels of that screen: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="BlackPixel">BlackPixel / BlackPixelOfScreen</a></li> +          <p> +          It is the Id of the black pixel, which is in the structure +          of an <span class="code">XCBSCREEN</span>. +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="WhitePixel">WhitePixel / WhitePixelOfScreen</a></li> +          <p> +          It is the Id of the white pixel, which is in the structure +          of an <span class="code">XCBSCREEN</span>. +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DisplayWidth">DisplayWidth / WidthOfScreen</a></li> +          <p> +          It is the width in pixels of the screen that you want, and +          which is in the structure of the corresponding +          <span class="code">XCBSCREEN</span>. +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DisplayHeight">DisplayHeight / HeightOfScreen</a></li> +          <p> +          It is the height in pixels of the screen that you want, and +          which is in the structure of the corresponding +          <span class="code">XCBSCREEN</span>. +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DisplayWidthMM">DisplayWidthMM / WidthMMOfScreen</a></li> +          <p> +          It is the width in millimeters of the screen that you want, and +          which is in the structure of the corresponding +          <span class="code">XCBSCREEN</span>. +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DisplayHeightMM">DisplayHeightMM / HeightMMOfScreen</a></li> +          <p> +          It is the height in millimeters of the screen that you want, and +          which is in the structure of the corresponding +          <span class="code">XCBSCREEN</span>. +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DisplayPlanes">DisplayPlanes / DefaultDepth / DefaultDepthOfScreen / PlanesOfScreen</a></li> +          <p> +          It is the depth (in bits) of the root window of the +          screen. You get it from the <span class="code">XCBSCREEN</span> structure. +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DefaultColormap">DefaultColormap / DefaultColormapOfScreen</a></li> +          <p> +          This is the default colormap of the screen (and not the +          (default) colormap of the default screen !). As usual, you +          get it from the <span class="code">XCBSCREEN</span> structure: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="MinCmapsOfScreen"></a>MinCmapsOfScreen</li> +          <p> +          You get the minimum installed colormaps in the <span class="code">XCBSCREEN</span> structure: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="MaxCmapsOfScreen"></a>MaxCmapsOfScreen</li> +          <p> +          You get the maximum installed colormaps in the <span class="code">XCBSCREEN</span> structure: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DoesSaveUnders"></a>DoesSaveUnders</li> +          <p> +          You know if <span class="code">save_unders</span> is set, +          by looking in the <span class="code">XCBSCREEN</span> structure: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="DoesBackingStore"></a>DoesBackingStore</li> +          <p> +          You know the value of <span class="code">backing_stores</span>, +          by looking in the <span class="code">XCBSCREEN</span> structure: +          </p> +          <pre class="code"> +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 */ +</pre> +          <li class="subtitle"><a name="EventMaskOfScreen"></a>EventMaskOfScreen</li> +          <p> +          To get the current input masks, +          you look in the <span class="code">XCBSCREEN</span> structure: +          </p> +          <pre class="code"> +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 */ +</pre> +        </ol> +      <li class="subtitle"><a name="misc">Miscellaneous macros</a></li> +        <ol> +          <li class="subtitle"><a name="DisplayOfScreen"></a>DisplayOfScreen</li> +          <p>  +          in Xlib, the <span class="code">Screen</span> structure +          stores its associated <span class="code">Display</span> +          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. +          </p> +          <li class="subtitle"><a name="DisplayCells"></a>DisplayCells / CellsOfScreen</li> +          <p> +          To get the colormap entries, +          you look in the <span class="code">XCBVISUALTYPE</span> +          structure, that you grab like <a class="subsection" href="#DefaultVisual">here</a>: +          </p> +          <pre class="code"> +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 */ +</pre> +        </ol> +      </ol> +    </ol> +  </div> +</body> + +</html> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2004 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. +--> +<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +               version="1.0" +               xmlns:e="http://exslt.org/common"> +   +  <xsl:output method="text" /> + +  <xsl:strip-space elements="*" /> + +  <!-- "header" or "source" --> +  <xsl:param name="mode" /> + +  <!-- Path to the core protocol descriptions. --> +  <xsl:param name="base-path" /> + +  <!-- Path to the extension protocol descriptions. --> +  <xsl:param name="extension-path" select="$base-path" /> + +  <xsl:variable name="h" select="$mode = 'header'" /> +  <xsl:variable name="c" select="$mode = 'source'" /> +   +  <!-- String used to indent lines of code. --> +  <xsl:variable name="indent-string" select="'    '" /> + +  <xsl:variable name="ucase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" /> +  <xsl:variable name="lcase" select="'abcdefghijklmnopqrstuvwxyz'" /> + +  <xsl:variable name="header" select="/xcb/@header" /> +  <xsl:variable name="ucase-header" +                select="translate($header,$lcase,$ucase)" /> + +  <xsl:variable name="ext" select="/xcb/@extension-name" /> + +  <!-- Other protocol descriptions to search for types in, after checking the +       current protocol description. --> +  <xsl:variable name="search-path-rtf"> +    <xsl:for-each select="/xcb/import"> +      <path><xsl:value-of select="concat($extension-path, ., '.xml')" /></path> +    </xsl:for-each> +    <xsl:choose> +      <xsl:when test="$header='xproto'"> +        <path><xsl:value-of select="concat($base-path, +                                           'xcb_types.xml')" /></path> +      </xsl:when> +      <xsl:when test="$header='xcb_types'" /> +      <xsl:otherwise> +        <path><xsl:value-of select="concat($base-path, +                                           'xproto.xml')" /></path> +        <path><xsl:value-of select="concat($base-path, +                                           'xcb_types.xml')" /></path> +      </xsl:otherwise> +    </xsl:choose> +  </xsl:variable> +  <xsl:variable name="search-path" select="e:node-set($search-path-rtf)/path"/> + +  <xsl:variable name="root" select="/" /> +   +  <!-- First pass: Store everything in a variable. --> +  <xsl:variable name="pass1-rtf"> +    <xsl:apply-templates select="/" mode="pass1" /> +  </xsl:variable> +  <xsl:variable name="pass1" select="e:node-set($pass1-rtf)" /> +   +  <xsl:template match="xcb" mode="pass1"> +    <xcb> +      <xsl:copy-of select="@*" /> +      <xsl:if test="$ext"> +        <constant type="XCBExtension" name="XCB{$ext}Id"> +          <xsl:attribute name="value">{ "<xsl:value-of select="@extension-xname" />" }</xsl:attribute> +        </constant> +        <function type="const XCBQueryExtensionRep *" name="XCB{$ext}Init"> +          <field type="XCBConnection *" name="c" /> +          <l>return XCBGetExtensionData(c, &XCB<!-- +          --><xsl:value-of select="$ext" />Id);</l> +        </function> +      </xsl:if> +      <xsl:apply-templates mode="pass1" /> +    </xcb> +  </xsl:template> + +  <!-- Modify names that conflict with C++ keywords by prefixing them with an +       underscore.  If the name parameter is not specified, it defaults to the +       value of the name attribute on the context node. --> +  <xsl:template name="canonical-var-name"> +    <xsl:param name="name" select="@name" /> +    <xsl:if test="$name='new' or $name='delete' +                  or $name='class' or $name='operator'"> +      <xsl:text>_</xsl:text> +    </xsl:if> +    <xsl:value-of select="$name" /> +  </xsl:template> + +  <!-- List of core types, for use in canonical-type-name. --> +  <xsl:variable name="core-types-rtf"> +    <type name="BOOL" /> +    <type name="BYTE" /> +    <type name="CARD8" /> +    <type name="CARD16" /> +    <type name="CARD32" /> +    <type name="INT8" /> +    <type name="INT16" /> +    <type name="INT32" /> + +    <type name="char" /> +    <type name="void" /> +    <type name="float" /> +    <type name="double" /> +    <type name="XID" /> +  </xsl:variable> +  <xsl:variable name="core-types" select="e:node-set($core-types-rtf)" /> + +  <!-- +    Output the canonical name for a type.  This will be +    XCB{extension-containing-Type-if-any}Type, wherever the type is found in +    the search path, or just Type if not found.  If the type parameter is not +    specified, it defaults to the value of the type attribute on the context +    node. +  --> +  <xsl:template name="canonical-type-name"> +    <xsl:param name="type" select="string(@type)" /> + +    <xsl:variable name="is-unqualified" select="not(contains($type, ':'))"/> +    <xsl:variable name="namespace" select="substring-before($type, ':')" /> +    <xsl:variable name="unqualified-type"> +      <xsl:choose> +        <xsl:when test="$is-unqualified"> +          <xsl:value-of select="$type" /> +        </xsl:when> +        <xsl:otherwise> +          <xsl:value-of select="substring-after($type, ':')" /> +        </xsl:otherwise> +      </xsl:choose> +    </xsl:variable> + +    <xsl:choose> +      <xsl:when test="$is-unqualified and $core-types/type[@name=$type]"> +        <xsl:value-of select="$type" /> +      </xsl:when> +      <xsl:otherwise> +        <xsl:variable name="type-definitions" +                      select="(/xcb|document($search-path)/xcb +                              )[$is-unqualified or @header=$namespace] +                               /*[((self::struct or self::union +                                    or self::xidtype or self::enum +                                    or self::event or self::eventcopy +                                    or self::error or self::errorcopy) +                                   and @name=$unqualified-type) +                                  or (self::typedef +                                      and @newname=$unqualified-type)]" /> +        <xsl:choose> +          <xsl:when test="count($type-definitions) = 1"> +            <xsl:for-each select="$type-definitions"> +              <xsl:text>XCB</xsl:text> +              <xsl:value-of select="concat(/xcb/@extension-name, +                                           $unqualified-type)" /> +            </xsl:for-each> +          </xsl:when> +          <xsl:when test="count($type-definitions) > 1"> +            <xsl:message terminate="yes"> +              <xsl:text>Multiple definitions of type "</xsl:text> +              <xsl:value-of select="$type" /> +              <xsl:text>" found.</xsl:text> +              <xsl:if test="$is-unqualified"> +                <xsl:for-each select="$type-definitions"> +                  <xsl:text> +    </xsl:text> +                  <xsl:value-of select="concat(/xcb/@header, ':', $type)" /> +                </xsl:for-each> +              </xsl:if> +            </xsl:message> +          </xsl:when> +          <xsl:otherwise> +            <xsl:message terminate="yes"> +              <xsl:text>No definitions of type "</xsl:text> +              <xsl:value-of select="$type" /> +              <xsl:text>" found</xsl:text> +              <xsl:if test="$is-unqualified"> +                <xsl:text>, and it is not a known core type</xsl:text> +              </xsl:if> +              <xsl:text>.</xsl:text> +            </xsl:message> +          </xsl:otherwise> +        </xsl:choose> 	 +      </xsl:otherwise> +    </xsl:choose> +  </xsl:template> +   +  <!-- Helper template for requests, that outputs the cookie type.  The +       context node must be the request. --> +  <xsl:template name="cookie-type"> +    <xsl:text>XCB</xsl:text> +    <xsl:choose> +      <xsl:when test="reply"> +        <xsl:value-of select="concat($ext, @name)" /> +      </xsl:when> +      <xsl:otherwise> +        <xsl:text>Void</xsl:text> +      </xsl:otherwise> +    </xsl:choose> +    <xsl:text>Cookie</xsl:text> +  </xsl:template> + +  <xsl:template match="request" mode="pass1"> +    <xsl:if test="reply"> +      <struct name="XCB{$ext}{@name}Cookie"> +        <field type="unsigned int" name="sequence" /> +      </struct> +    </xsl:if> +    <struct name="XCB{$ext}{@name}Req"> +      <field type="CARD8" name="major_opcode" no-assign="true" /> +      <xsl:if test="$ext"> +        <field type="CARD8" name="minor_opcode" no-assign="true" /> +      </xsl:if> +      <xsl:apply-templates select="*[not(self::reply)]" mode="field" /> +      <middle> +        <field type="CARD16" name="length" no-assign="true" /> +      </middle> +    </struct> +    <function name="XCB{$ext}{@name}"> +      <xsl:attribute name="type"> +        <xsl:call-template name="cookie-type" /> +      </xsl:attribute> +      <field type="XCBConnection *" name="c" /> +      <xsl:apply-templates select="*[not(self::reply)]" mode="param" /> +      <do-request ref="XCB{$ext}{@name}Req" opcode="{@opcode}"> +        <xsl:if test="reply"> +          <xsl:attribute name="has-reply">true</xsl:attribute> +        </xsl:if> +      </do-request> +    </function> +    <xsl:if test="reply"> +      <struct name="XCB{$ext}{@name}Rep"> +        <field type="BYTE" name="response_type" /> +        <xsl:apply-templates select="reply/*" mode="field" /> +        <middle> +          <field type="CARD16" name="sequence" /> +          <field type="CARD32" name="length" /> +        </middle> +      </struct> +      <iterator-functions ref="XCB{$ext}{@name}" kind="Rep" /> +      <function type="XCB{$ext}{@name}Rep *" name="XCB{$ext}{@name}Reply"> +        <field type="XCBConnection *" name="c" /> +        <field name="cookie"> +          <xsl:attribute name="type"> +            <xsl:call-template name="cookie-type" /> +          </xsl:attribute> +        </field> +        <field type="XCBGenericError **" name="e" /> +        <l>return (XCB<xsl:value-of select="concat($ext, @name)" />Rep *)<!-- +        --> XCBWaitForReply(c, cookie.sequence, e);</l> +      </function> +    </xsl:if> +  </xsl:template> + +  <xsl:template match="xidtype" mode="pass1"> +    <struct name="XCB{$ext}{@name}"> +      <field type="CARD32" name="xid" /> +    </struct> +    <iterator ref="XCB{$ext}{@name}" /> +    <iterator-functions ref="XCB{$ext}{@name}" /> +    <function type="XCB{$ext}{@name}" name="XCB{$ext}{@name}New"> +      <field type="XCBConnection *" name="c" /> +      <l>XCB<xsl:value-of select="concat($ext, @name)" /> ret;</l> +      <l>ret.xid = XCBGenerateID(c);</l> +      <l>return ret;</l> +    </function> +  </xsl:template> + +  <xsl:template match="struct|union" mode="pass1"> +    <struct name="XCB{$ext}{@name}"> +      <xsl:if test="self::union"> +        <xsl:attribute name="kind">union</xsl:attribute> +      </xsl:if> +      <xsl:apply-templates select="*" mode="field" /> +    </struct> +    <iterator ref="XCB{$ext}{@name}" /> +    <iterator-functions ref="XCB{$ext}{@name}" /> +  </xsl:template> + +  <xsl:template match="event|eventcopy|error|errorcopy" mode="pass1"> +    <xsl:variable name="suffix"> +      <xsl:choose> +        <xsl:when test="self::event|self::eventcopy"> +          <xsl:text>Event</xsl:text> +        </xsl:when> +        <xsl:when test="self::error|self::errorcopy"> +          <xsl:text>Error</xsl:text> +        </xsl:when> +      </xsl:choose> +    </xsl:variable> +    <constant type="number" name="XCB{$ext}{@name}" value="{@number}" /> +    <xsl:choose> +      <xsl:when test="self::event|self::error"> +        <struct name="XCB{$ext}{@name}{$suffix}"> +          <field type="BYTE" name="response_type" /> +          <xsl:if test="self::error"> +            <field type="BYTE" name="error_code" /> +          </xsl:if> +          <xsl:apply-templates select="*" mode="field" /> +          <xsl:if test="not(self::event and boolean(@no-sequence-number))"> +            <middle> +              <field type="CARD16" name="sequence" /> +            </middle> +          </xsl:if> +        </struct> +      </xsl:when> +      <xsl:when test="self::eventcopy|self::errorcopy"> +        <typedef newname="XCB{$ext}{@name}{$suffix}"> +          <xsl:attribute name="oldname"> +            <xsl:call-template name="canonical-type-name"> +              <xsl:with-param name="type" select="@ref" /> +            </xsl:call-template> +            <xsl:value-of select="$suffix" /> +          </xsl:attribute> +        </typedef> +      </xsl:when> +    </xsl:choose> +  </xsl:template> + +  <xsl:template match="typedef" mode="pass1"> +    <typedef> +      <xsl:attribute name="oldname"> +        <xsl:call-template name="canonical-type-name"> +          <xsl:with-param name="type" select="@oldname" /> +        </xsl:call-template> +      </xsl:attribute> +      <xsl:attribute name="newname"> +        <xsl:call-template name="canonical-type-name"> +          <xsl:with-param name="type" select="@newname" /> +        </xsl:call-template> +      </xsl:attribute> +    </typedef> +    <iterator ref="XCB{$ext}{@newname}" /> +    <iterator-functions ref="XCB{$ext}{@newname}" /> +  </xsl:template> + +  <xsl:template match="enum" mode="pass1"> +    <enum name="XCB{$ext}{@name}"> +      <xsl:for-each select="item"> +        <item name="XCB{$ext}{../@name}{@name}"> +          <xsl:copy-of select="*" /> +        </item> +      </xsl:for-each> +    </enum> +  </xsl:template> + +  <!-- +    Templates for processing fields. +  --> + +  <xsl:template match="pad" mode="field"> +    <xsl:copy-of select="." /> +  </xsl:template> +   +  <xsl:template match="field|exprfield" mode="field"> +    <xsl:copy> +      <xsl:attribute name="type"> +        <xsl:call-template name="canonical-type-name" /> +      </xsl:attribute> +      <xsl:attribute name="name"> +        <xsl:call-template name="canonical-var-name" /> +      </xsl:attribute> +      <xsl:copy-of select="*" /> +    </xsl:copy> +  </xsl:template> + +  <xsl:template match="list" mode="field"> +    <xsl:variable name="type"><!-- +      --><xsl:call-template name="canonical-type-name" /><!-- +    --></xsl:variable> +    <list type="{$type}"> +      <xsl:attribute name="name"> +        <xsl:call-template name="canonical-var-name" /> +      </xsl:attribute> +      <xsl:if test="not(parent::request) and node() +                    and not(.//*[not(self::value or self::op)])"> +        <xsl:attribute name="fixed">true</xsl:attribute> +      </xsl:if> +      <!-- Handle lists with no length expressions. --> +      <xsl:if test="not(node())"> +        <xsl:choose> +          <!-- In a request, refer to an implicit localparam for length. --> +          <xsl:when test="parent::request"> +            <fieldref> +              <xsl:value-of select="concat(@name, '_len')" /> +            </fieldref> +          </xsl:when> +          <!-- In a reply, use the length of the reply to determine the length +               of the list. --> +          <xsl:when test="parent::reply"> +            <op op="/"> +              <op op="<<"> +                <fieldref>length</fieldref> +                <value>2</value> +              </op> +              <function-call name="sizeof"> +                <param><xsl:value-of select="$type" /></param> +              </function-call> +            </op> +          </xsl:when> +          <!-- Other cases generate an error. --> +          <xsl:otherwise> +            <xsl:message terminate="yes"><!-- +              -->Encountered a list with no length expresssion outside a<!-- +              --> request or reply.<!-- +            --></xsl:message> +          </xsl:otherwise> +        </xsl:choose> +      </xsl:if> +      <xsl:copy-of select="*" /> +    </list> +  </xsl:template> + +  <xsl:template match="valueparam" mode="field"> +    <field> +      <xsl:attribute name="type"> +        <xsl:call-template name="canonical-type-name"> +          <xsl:with-param name="type" select="@value-mask-type" /> +        </xsl:call-template> +      </xsl:attribute> +      <xsl:attribute name="name"> +        <xsl:call-template name="canonical-var-name"> +          <xsl:with-param name="name" select="@value-mask-name" /> +        </xsl:call-template> +      </xsl:attribute> +    </field> +    <list type="CARD32"> +      <xsl:attribute name="name"> +        <xsl:call-template name="canonical-var-name"> +          <xsl:with-param name="name" select="@value-list-name" /> +        </xsl:call-template> +      </xsl:attribute> +      <function-call name="XCBPopcount"> +        <param> +          <fieldref> +            <xsl:call-template name="canonical-var-name"> +              <xsl:with-param name="name" select="@value-mask-name" /> +            </xsl:call-template> +          </fieldref> +        </param> +      </function-call> +    </list> +  </xsl:template> + +  <xsl:template match="field|localfield" mode="param"> +    <field> +      <xsl:attribute name="type"> +        <xsl:call-template name="canonical-type-name" /> +      </xsl:attribute> +      <xsl:attribute name="name"> +        <xsl:call-template name="canonical-var-name" /> +      </xsl:attribute> +    </field> +  </xsl:template> + +  <xsl:template match="list" mode="param"> +    <!-- If no length expression is provided, use a CARD32 localfield. --> +    <xsl:if test="not(node())"> +      <field type="CARD32" name="{@name}_len" /> +    </xsl:if> +    <field> +      <xsl:attribute name="type"> +        <xsl:text>const </xsl:text> +        <xsl:call-template name="canonical-type-name" /> +        <xsl:text> *</xsl:text> +      </xsl:attribute> +      <xsl:attribute name="name"> +        <xsl:call-template name="canonical-var-name" /> +      </xsl:attribute> +    </field> +  </xsl:template> + +  <xsl:template match="valueparam" mode="param"> +    <field> +      <xsl:attribute name="type"> +        <xsl:call-template name="canonical-type-name"> +          <xsl:with-param name="type" select="@value-mask-type" /> +        </xsl:call-template> +      </xsl:attribute> +      <xsl:attribute name="name"> +        <xsl:call-template name="canonical-var-name"> +          <xsl:with-param name="name" select="@value-mask-name" /> +        </xsl:call-template> +      </xsl:attribute> +    </field> +    <field type="const CARD32 *"> +      <xsl:attribute name="name"> +        <xsl:call-template name="canonical-var-name"> +          <xsl:with-param name="name" select="@value-list-name" /> +        </xsl:call-template> +      </xsl:attribute> +    </field> +  </xsl:template> + +  <!-- Second pass: Process the variable. --> +  <xsl:variable name="result-rtf"> +    <xsl:apply-templates select="$pass1/*" mode="pass2" /> +  </xsl:variable> +  <xsl:variable name="result" select="e:node-set($result-rtf)" /> + +  <xsl:template match="xcb" mode="pass2"> +    <xcb> +      <xsl:copy-of select="@*" /> +      <xsl:apply-templates mode="pass2" +                           select="constant|enum|struct|typedef|iterator" /> +      <xsl:apply-templates mode="pass2" +                           select="function|iterator-functions" /> +    </xcb> +  </xsl:template> + +  <!-- Generic rules for nodes that don't need further processing: copy node +       with attributes, and recursively process the child nodes. --> +  <xsl:template match="*" mode="pass2"> +    <xsl:copy> +      <xsl:copy-of select="@*" /> +      <xsl:apply-templates mode="pass2" /> +    </xsl:copy> +  </xsl:template> + +  <xsl:template match="struct" mode="pass2"> +    <xsl:if test="@kind='union' and list[not(@fixed)]"> +      <xsl:message terminate="yes">Unions must be fixed length.</xsl:message> +    </xsl:if> +    <struct name="{@name}"> +      <xsl:if test="@kind"> +        <xsl:attribute name="kind"> +          <xsl:value-of select="@kind" /> +        </xsl:attribute> +      </xsl:if> +      <!-- FIXME: This should go by size, not number of fields. --> +      <xsl:copy-of select="node()[not(self::middle) +                   and position() < 3]" /> +      <xsl:if test="middle and (count(*[not(self::middle)]) < 2)"> +        <pad bytes="{2 - count(*[not(self::middle)])}" /> +      </xsl:if> +      <xsl:copy-of select="middle/*" /> +      <xsl:copy-of select="node()[not(self::middle) and (position() > 2)]" /> +    </struct> +  </xsl:template> + +  <xsl:template match="do-request" mode="pass2"> +    <xsl:variable name="struct" +                  select="$pass1/xcb/struct[@name=current()/@ref]" /> + +    <xsl:variable name="num-parts" select="1+count($struct/list)" /> + +    <l>static const XCBProtocolRequest xcb_req = {</l> +    <indent> +      <l>/* count */ <xsl:value-of select="$num-parts" />,</l> +      <l>/* ext */ <xsl:choose> +                     <xsl:when test="$ext"> +                       <xsl:text>&XCB</xsl:text> +                       <xsl:value-of select="$ext" /> +                       <xsl:text>Id</xsl:text> +                     </xsl:when> +                     <xsl:otherwise>0</xsl:otherwise> +                   </xsl:choose>,</l> +      <l>/* opcode */ <xsl:value-of select="@opcode" />,</l> +      <l>/* isvoid */ <xsl:value-of select="1-boolean(@has-reply)" /></l> +    </indent> +    <l>};</l> + +    <l /> +    <l>struct iovec xcb_parts[<xsl:value-of select="$num-parts" />];</l> +    <l><xsl:value-of select="../@type" /> xcb_ret;</l> +    <l><xsl:value-of select="@ref" /> xcb_out;</l> + +    <l /> +    <xsl:apply-templates select="$struct//*[(self::field or self::exprfield) +                                            and not(boolean(@no-assign))]" +                         mode="assign" /> + +    <l /> +    <l>xcb_parts[0].iov_base = &xcb_out;</l> +    <l>xcb_parts[0].iov_len = sizeof(xcb_out);</l> + +    <xsl:for-each select="$struct/list"> +      <l>xcb_parts[<xsl:number />].iov_base = (void *) <!-- +      --><xsl:value-of select="@name" />;</l> +      <l>xcb_parts[<xsl:number />].iov_len = <!-- +      --><xsl:apply-templates mode="output-expression" /><!-- +      --><xsl:if test="not(@type = 'void')"> +        <xsl:text> * sizeof(</xsl:text> +        <xsl:value-of select="@type" /> +        <xsl:text>)</xsl:text> +      </xsl:if>;</l> +    </xsl:for-each> + +    <l>XCBSendRequest(c, &xcb_ret.sequence, xcb_parts, &xcb_req);</l> +    <l>return xcb_ret;</l> +  </xsl:template> + +  <xsl:template match="field" mode="assign"> +    <l> +      <xsl:text>xcb_out.</xsl:text> +      <xsl:value-of select="@name" /> +      <xsl:text> = </xsl:text> +      <xsl:value-of select="@name" /> +      <xsl:text>;</xsl:text> +    </l> +  </xsl:template> + +  <xsl:template match="exprfield" mode="assign"> +    <l> +      <xsl:text>xcb_out.</xsl:text> +      <xsl:value-of select="@name" /> +      <xsl:text> = </xsl:text> +      <xsl:apply-templates mode="output-expression" /> +      <xsl:text>;</xsl:text> +    </l> +  </xsl:template> + +  <xsl:template match="iterator" mode="pass2"> +    <struct name="{@ref}Iter"> +      <field type="{@ref} *" name="data" /> +      <field type="int" name="rem" /> +      <field type="int" name="index" /> +    </struct> +  </xsl:template> + +  <!-- Change a_name_like_this to ANameLikeThis.  If the parameter name is not +       given, it defaults to the name attribute of the context node. --> +  <xsl:template name="capitalize"> +    <xsl:param name="name" select="string(@name)" /> +    <xsl:if test="$name"> +      <xsl:value-of select="translate(substring($name,1,1), $lcase, $ucase)" /> +      <xsl:choose> +        <xsl:when test="contains($name, '_')"> +          <xsl:value-of select="substring(substring-before($name, '_'), 2)" /> +          <xsl:call-template name="capitalize"> +            <xsl:with-param name="name" select="substring-after($name, '_')" /> +          </xsl:call-template> +        </xsl:when> +        <xsl:otherwise> +          <xsl:value-of select="substring($name, 2)" /> +        </xsl:otherwise> +      </xsl:choose> +    </xsl:if> +  </xsl:template> + +  <xsl:template match="iterator-functions" mode="pass2"> +    <xsl:variable name="ref" select="@ref" /> +    <xsl:variable name="kind" select="@kind" /> +    <xsl:variable name="struct" +                  select="$pass1/xcb/struct[@name=concat($ref,$kind)]" /> +    <xsl:variable name="nextfields-rtf"> +      <nextfield>R + 1</nextfield> +      <xsl:for-each select="$struct/list[not(@fixed)]"> +        <xsl:choose> +          <xsl:when test="substring(@type, 1, 3) = 'XCB'"> +            <nextfield><xsl:value-of select="@type" />End(<!-- +            --><xsl:value-of select="$ref" /><!-- +            --><xsl:call-template name="capitalize" />Iter(R))</nextfield> +          </xsl:when> +          <xsl:otherwise> +            <nextfield><xsl:value-of select="$ref" /><!-- +            --><xsl:call-template name="capitalize" />End(R)</nextfield> +          </xsl:otherwise> +        </xsl:choose> +      </xsl:for-each> +    </xsl:variable> +    <xsl:variable name="nextfields" select="e:node-set($nextfields-rtf)" /> +    <xsl:for-each select="$struct/list[not(@fixed)]"> +      <xsl:variable name="number" +                    select="1+count(preceding-sibling::list[not(@fixed)])" /> +      <xsl:variable name="nextfield" select="$nextfields/nextfield[$number]" /> +      <xsl:variable name="is-first" +                    select="not(preceding-sibling::list[not(@fixed)])" /> +      <xsl:variable name="field-name"><!-- +        --><xsl:call-template name="capitalize" /><!-- +      --></xsl:variable> +      <xsl:variable name="is-variable" +                    select="$pass1/xcb/struct[@name=current()/@type]/list +                            or document($search-path)/xcb +                               /struct[concat('XCB', +                                              ancestor::xcb/@extension-name, +                                              @name) = current()/@type] +                               /*[self::valueparam or self::list]" /> +      <xsl:if test="not($is-variable)"> +        <function type="{@type} *" name="{$ref}{$field-name}"> +          <field type="{$ref}{$kind} *" name="R" /> +          <xsl:choose> +            <xsl:when test="$is-first"> +              <l>return (<xsl:value-of select="@type" /> *) <!-- +              -->(<xsl:value-of select="$nextfield" />);</l> +            </xsl:when> +            <xsl:otherwise> +              <l>XCBGenericIter prev = <!-- +              --><xsl:value-of select="$nextfield" />;</l> +              <l>return (<xsl:value-of select="@type" /> *) <!-- +              -->((char *) prev.data + XCB_TYPE_PAD(<!-- +              --><xsl:value-of select="@type" />, prev.index));</l> +            </xsl:otherwise> +          </xsl:choose> +        </function> +      </xsl:if> +      <function type="int" name="{$ref}{$field-name}Length"> +        <field type="{$ref}{$kind} *" name="R" /> +        <l>return <xsl:apply-templates mode="output-expression"> +                    <xsl:with-param name="field-prefix" select="'R->'" /> +                  </xsl:apply-templates>;</l> +      </function> +      <xsl:choose> +        <xsl:when test="substring(@type, 1, 3) = 'XCB'"> +          <function type="{@type}Iter" name="{$ref}{$field-name}Iter"> +            <field type="{$ref}{$kind} *" name="R" /> +            <l><xsl:value-of select="@type" />Iter i;</l> +            <xsl:choose> +              <xsl:when test="$is-first"> +                <l>i.data = (<xsl:value-of select="@type" /> *) <!-- +                -->(<xsl:value-of select="$nextfield" />);</l> +              </xsl:when> +              <xsl:otherwise> +                <l>XCBGenericIter prev = <!-- +                --><xsl:value-of select="$nextfield" />;</l> +                <l>i.data = (<xsl:value-of select="@type" /> *) <!-- +                -->((char *) prev.data + XCB_TYPE_PAD(<!-- +                --><xsl:value-of select="@type" />, prev.index));</l> +              </xsl:otherwise> +            </xsl:choose> +            <l>i.rem = <xsl:apply-templates mode="output-expression"> +                         <xsl:with-param name="field-prefix" select="'R->'" /> +                       </xsl:apply-templates>;</l> +            <l>i.index = (char *) i.data - (char *) R;</l> +            <l>return i;</l> +          </function> +        </xsl:when> +        <xsl:otherwise> +          <xsl:variable name="cast"> +            <xsl:choose> +              <xsl:when test="@type='void'">char</xsl:when> +              <xsl:otherwise><xsl:value-of select="@type" /></xsl:otherwise> +            </xsl:choose> +          </xsl:variable> +          <function type="XCBGenericIter" name="{$ref}{$field-name}End"> +            <field type="{$ref}{$kind} *" name="R" /> +            <l>XCBGenericIter i;</l> +            <xsl:choose> +              <xsl:when test="$is-first"> +                <l>i.data = ((<xsl:value-of select="$cast" /> *) <!-- +                -->(<xsl:value-of select="$nextfield" />)) + (<!-- +                --><xsl:apply-templates mode="output-expression"> +                     <xsl:with-param name="field-prefix" select="'R->'" /> +                   </xsl:apply-templates>);</l> +              </xsl:when> +              <xsl:otherwise> +                <l>XCBGenericIter child = <!-- +                --><xsl:value-of select="$nextfield" />;</l> +                <l>i.data = ((<xsl:value-of select="$cast" /> *) <!-- +                -->child.data) + (<!-- +                --><xsl:apply-templates mode="output-expression"> +                     <xsl:with-param name="field-prefix" select="'R->'" /> +                   </xsl:apply-templates>);</l> +              </xsl:otherwise> +            </xsl:choose> +            <l>i.rem = 0;</l> +            <l>i.index = (char *) i.data - (char *) R;</l> +            <l>return i;</l> +          </function> +        </xsl:otherwise> +      </xsl:choose> +    </xsl:for-each> +    <xsl:if test="not($kind)"> +      <function type="void" name="{$ref}Next"> +        <field type="{$ref}Iter *" name="i" /> +        <xsl:choose> +          <xsl:when test="$struct/list[not(@fixed)]"> +            <l><xsl:value-of select="$ref" /> *R = i->data;</l> +            <l>XCBGenericIter child = <!-- +            --><xsl:value-of select="$nextfields/nextfield[last()]" />;</l> +            <l>--i->rem;</l> +            <l>i->data = (<xsl:value-of select="$ref" /> *) child.data;</l> +            <l>i->index = child.index;</l> +          </xsl:when> +          <xsl:otherwise> +            <l>--i->rem;</l> +            <l>++i->data;</l> +            <l>i->index += sizeof(<xsl:value-of select="$ref" />);</l> +          </xsl:otherwise> +        </xsl:choose> +      </function> +      <function type="XCBGenericIter" name="{$ref}End"> +        <field type="{$ref}Iter" name="i" /> +        <l>XCBGenericIter ret;</l> +        <xsl:choose> +          <xsl:when test="$struct/list[not(@fixed)]"> +            <l>while(i.rem > 0)</l> +            <indent> +              <l><xsl:value-of select="$ref" />Next(&i);</l> +            </indent> +            <l>ret.data = i.data;</l> +            <l>ret.rem = i.rem;</l> +            <l>ret.index = i.index;</l> +          </xsl:when> +          <xsl:otherwise> +            <l>ret.data = i.data + i.rem;</l> +            <l>ret.index = i.index + ((char *) ret.data - (char *) i.data);</l> +            <l>ret.rem = 0;</l> +          </xsl:otherwise> +        </xsl:choose> +        <l>return ret;</l> +      </function> +    </xsl:if> +  </xsl:template> + +  <!-- Output the results. --> +  <xsl:template match="/"> +    <xsl:if test="not(function-available('e:node-set'))"> +      <xsl:message terminate="yes"><!-- +        -->Error: This stylesheet requires the EXSL node-set extension.<!-- +      --></xsl:message> +    </xsl:if> + +    <xsl:if test="not($h) and not($c)"> +      <xsl:message terminate="yes"><!-- +        -->Error: Parameter "mode" must be "header" or "source".<!-- +      --></xsl:message> +    </xsl:if> + +    <xsl:apply-templates select="$result/*" mode="output" /> +  </xsl:template> + +  <xsl:template match="xcb" mode="output"> +    <xsl:variable name="guard"><!-- +      -->__<xsl:value-of select="$ucase-header" />_H<!-- +    --></xsl:variable> + +<xsl:text>/* + * This file generated automatically from </xsl:text> +<xsl:value-of select="$header" /><xsl:text>.xml by c-client.xsl using XSLT. + * Edit at your peril. + */ +</xsl:text> + +<xsl:if test="$h"><xsl:text> +#ifndef </xsl:text><xsl:value-of select="$guard" /><xsl:text> +#define </xsl:text><xsl:value-of select="$guard" /><xsl:text> +</xsl:text> +#include "xcb.h" +<xsl:for-each select="$root/xcb/import"> +<xsl:text>#include "</xsl:text><xsl:value-of select="." /><xsl:text>.h" +</xsl:text> +</xsl:for-each> +<xsl:text> +</xsl:text> +</xsl:if> + +<xsl:if test="$c"><xsl:text> +#include <assert.h> +#include "xcbext.h" +#include "</xsl:text><xsl:value-of select="$header" /><xsl:text>.h" + +</xsl:text></xsl:if> + +    <xsl:apply-templates mode="output" /> + +<xsl:if test="$h"> +<xsl:text> +#endif +</xsl:text> +</xsl:if> +  </xsl:template> + +  <xsl:template match="constant" mode="output"> +    <xsl:choose> +      <xsl:when test="@type = 'number'"> +        <xsl:if test="$h"> +          <xsl:text>#define </xsl:text> +          <xsl:value-of select="@name" /> +          <xsl:text> </xsl:text> +          <xsl:value-of select="@value" /> +          <xsl:text> + +</xsl:text> +        </xsl:if> +      </xsl:when> +      <xsl:when test="@type = 'string'"> +        <xsl:if test="$h"> +          <xsl:text>extern </xsl:text> +        </xsl:if> +        <xsl:text>const char </xsl:text> +        <xsl:value-of select="@name" /> +        <xsl:text>[]</xsl:text> +        <xsl:if test="$c"> +          <xsl:text> = "</xsl:text> +          <xsl:value-of select="@value" /> +          <xsl:text>"</xsl:text> +        </xsl:if> +        <xsl:text>; + +</xsl:text> +      </xsl:when> +      <xsl:otherwise> +        <xsl:if test="$h"> +          <xsl:text>extern </xsl:text> +        </xsl:if> +        <xsl:call-template name="type-and-name" /> +        <xsl:if test="$c"> +          <xsl:text> = </xsl:text> +          <xsl:value-of select="@value" /> +        </xsl:if> +        <xsl:text>; + +</xsl:text> +      </xsl:otherwise> +    </xsl:choose> +  </xsl:template> + +  <xsl:template match="typedef" mode="output"> +    <xsl:if test="$h"> +      <xsl:text>typedef </xsl:text> +      <xsl:value-of select="@oldname" /> +      <xsl:text> </xsl:text> +      <xsl:value-of select="@newname" /> +      <xsl:text>; + +</xsl:text> +    </xsl:if> +  </xsl:template> + +  <xsl:template match="struct" mode="output"> +    <xsl:if test="$h"> +      <xsl:variable name="type-lengths"> +        <xsl:call-template name="type-lengths"> +          <xsl:with-param name="items" select="field/@type" /> +        </xsl:call-template> +      </xsl:variable> +      <xsl:text>typedef </xsl:text> +      <xsl:if test="not(@kind)">struct</xsl:if><xsl:value-of select="@kind" /> +      <xsl:text> { +</xsl:text> +      <xsl:for-each select="exprfield|field|list[@fixed]|pad"> +        <xsl:text>    </xsl:text> +        <xsl:apply-templates select="."> +          <xsl:with-param name="type-lengths" select="$type-lengths" /> +        </xsl:apply-templates> +        <xsl:text>; +</xsl:text> +      </xsl:for-each> +      <xsl:text>} </xsl:text> +      <xsl:value-of select="@name" /> +      <xsl:text>; + +</xsl:text> +    </xsl:if> +  </xsl:template> + +  <xsl:template match="enum" mode="output"> +    <xsl:if test="$h"> +      <xsl:text>typedef enum { +    </xsl:text> +      <xsl:call-template name="list"> +        <xsl:with-param name="separator"><xsl:text>, +    </xsl:text></xsl:with-param> +        <xsl:with-param name="items"> +          <xsl:for-each select="item"> +            <item> +              <xsl:value-of select="@name" /> +              <xsl:if test="node()"> <!-- If there is an expression --> +                <xsl:text> = </xsl:text> +                <xsl:apply-templates mode="output-expression" /> +              </xsl:if> +            </item> +          </xsl:for-each> +        </xsl:with-param> +      </xsl:call-template> +      <xsl:text> +} </xsl:text><xsl:value-of select="@name" /><xsl:text>; + +</xsl:text> +    </xsl:if> +  </xsl:template> + +  <xsl:template match="function" mode="output"> +    <xsl:variable name="decl-open" select="concat(@name, ' (')" /> +    <xsl:variable name="type-lengths"> +      <xsl:call-template name="type-lengths"> +        <xsl:with-param name="items" select="field/@type" /> +      </xsl:call-template> +    </xsl:variable> +    <xsl:value-of select="@type" /> +    <xsl:text> +</xsl:text> +    <xsl:value-of select="$decl-open" /> +    <xsl:call-template name="list"> +      <xsl:with-param name="separator"> +        <xsl:text>, +</xsl:text> +        <xsl:call-template name="repeat"> +          <xsl:with-param name="count" select="string-length($decl-open)" /> +        </xsl:call-template> +      </xsl:with-param> +      <xsl:with-param name="items"> +        <xsl:for-each select="field"> +          <item> +            <xsl:apply-templates select="."> +              <xsl:with-param name="type-lengths" select="$type-lengths" /> +            </xsl:apply-templates> +          </item> +        </xsl:for-each> +      </xsl:with-param> +    </xsl:call-template> +    <xsl:text>)</xsl:text> + +    <xsl:if test="$h"><xsl:text>; + +</xsl:text></xsl:if> + +    <xsl:if test="$c"> +      <xsl:text> +{ +</xsl:text> +      <xsl:apply-templates select="l|indent" mode="function-body"> +        <xsl:with-param name="indent" select="$indent-string" /> +      </xsl:apply-templates> +      <xsl:text>} + +</xsl:text> +    </xsl:if> +  </xsl:template> + +  <xsl:template match="l" mode="function-body"> +    <xsl:param name="indent" /> +    <xsl:value-of select="concat($indent, .)" /><xsl:text> +</xsl:text> +  </xsl:template> + +  <xsl:template match="indent" mode="function-body"> +    <xsl:param name="indent" /> +    <xsl:apply-templates select="l|indent" mode="function-body"> +      <xsl:with-param name="indent" select="concat($indent, $indent-string)" /> +    </xsl:apply-templates> +  </xsl:template> + +  <xsl:template match="value" mode="output-expression"> +    <xsl:value-of select="." /> +  </xsl:template> + +  <xsl:template match="fieldref" mode="output-expression"> +    <xsl:param name="field-prefix" /> +    <xsl:value-of select="concat($field-prefix, .)" /> +  </xsl:template> + +  <xsl:template match="op" mode="output-expression"> +    <xsl:param name="field-prefix" /> +    <xsl:text>(</xsl:text> +    <xsl:apply-templates select="node()[1]" mode="output-expression"> +      <xsl:with-param name="field-prefix" select="$field-prefix" /> +    </xsl:apply-templates> +    <xsl:text> </xsl:text> +    <xsl:value-of select="@op" /> +    <xsl:text> </xsl:text> +    <xsl:apply-templates select="node()[2]" mode="output-expression"> +      <xsl:with-param name="field-prefix" select="$field-prefix" /> +    </xsl:apply-templates> +    <xsl:text>)</xsl:text> +  </xsl:template> + +  <xsl:template match="function-call" mode="output-expression"> +    <xsl:param name="field-prefix" /> +    <xsl:value-of select="@name" /> +    <xsl:text>(</xsl:text> +    <xsl:call-template name="list"> +      <xsl:with-param name="separator" select="', '" /> +      <xsl:with-param name="items"> +        <xsl:for-each select="param"> +          <item><xsl:apply-templates mode="output-expression"> +            <xsl:with-param name="field-prefix" select="$field-prefix" /> +          </xsl:apply-templates></item> +        </xsl:for-each> +      </xsl:with-param> +    </xsl:call-template> +    <xsl:text>)</xsl:text> +  </xsl:template> + +  <!-- Catch invalid elements in expressions. --> +  <xsl:template match="*" mode="output-expression"> +    <xsl:message terminate="yes"> +      <xsl:text>Invalid element in expression: </xsl:text> +      <xsl:value-of select="name()" /> +    </xsl:message> +  </xsl:template> + +  <xsl:template match="field|exprfield"> +    <xsl:param name="type-lengths" select="0" /> +    <xsl:call-template name="type-and-name"> +      <xsl:with-param name="type-lengths" select="$type-lengths" /> +    </xsl:call-template> +  </xsl:template> + +  <xsl:template match="list[@fixed]"> +    <xsl:param name="type-lengths" select="0" /> +    <xsl:call-template name="type-and-name"> +      <xsl:with-param name="type-lengths" select="$type-lengths" /> +    </xsl:call-template> +    <xsl:text>[</xsl:text> +    <xsl:apply-templates mode="output-expression" /> +    <xsl:text>]</xsl:text> +  </xsl:template> + +  <xsl:template match="pad"> +    <xsl:param name="type-lengths" select="0" /> + +    <xsl:variable name="padnum"><xsl:number /></xsl:variable> + +    <xsl:call-template name="type-and-name"> +      <xsl:with-param name="type" select="'CARD8'" /> +      <xsl:with-param name="name"> +        <xsl:text>pad</xsl:text> +        <xsl:value-of select="$padnum - 1" /> +      </xsl:with-param> +      <xsl:with-param name="type-lengths" select="$type-lengths" /> +    </xsl:call-template> +    <xsl:if test="@bytes > 1"> +      <xsl:text>[</xsl:text> +      <xsl:value-of select="@bytes" /> +      <xsl:text>]</xsl:text> +    </xsl:if> +  </xsl:template> + +  <!-- Output the given type and name (defaulting to the corresponding +       attributes of the context node), with the appropriate spacing.  The +       type must consist of a base type (which may contain spaces), then +       optionally a single space and a suffix of one or more '*' characters. +       If the type-lengths parameter is provided, use it to line up the base +       types and suffixs of the type declarations. --> +  <xsl:template name="type-and-name"> +    <xsl:param name="type" select="@type" /> +    <xsl:param name="name" select="@name" /> +    <xsl:param name="type-lengths"> +      <max-type-length>0</max-type-length> +      <max-suffix-length>0</max-suffix-length> +    </xsl:param> +     +    <xsl:variable name="type-lengths-ns" select="e:node-set($type-lengths)" /> +    <xsl:variable name="min-type-length" +                  select="$type-lengths-ns/max-type-length" /> +    <xsl:variable name="min-suffix-length" +                  select="$type-lengths-ns/max-suffix-length" /> + +    <xsl:variable name="base-type"> +      <xsl:choose> +        <xsl:when test="contains($type, ' *')"> +          <xsl:value-of select="substring-before($type, ' *')" /> +        </xsl:when> +        <xsl:otherwise> +          <xsl:value-of select="$type" /> +        </xsl:otherwise> +      </xsl:choose> +    </xsl:variable> +    <xsl:variable name="suffix"> +      <xsl:if test="contains($type, ' *')"> +        <xsl:text>*</xsl:text> +        <xsl:value-of select="substring-after($type, ' *')" /> +      </xsl:if> +    </xsl:variable> + +    <xsl:value-of select="$base-type" /> +    <xsl:if test="string-length($base-type) < $min-type-length"> +      <xsl:call-template name="repeat"> +        <xsl:with-param name="count" select="$min-type-length +                                             - string-length($base-type)" /> +      </xsl:call-template> +    </xsl:if> +    <xsl:text> </xsl:text> +    <xsl:if test="string-length($suffix) < $min-suffix-length"> +      <xsl:call-template name="repeat"> +        <xsl:with-param name="count" select="$min-suffix-length +                                             - string-length($suffix)" /> +      </xsl:call-template> +    </xsl:if> +    <xsl:value-of select="$suffix" /> +    <xsl:value-of select="$name" /> +  </xsl:template> + +  <!-- Output a list with a given separator.  Empty items are skipped. --> +  <xsl:template name="list"> +    <xsl:param name="separator" /> +    <xsl:param name="items" /> + +    <xsl:for-each select="e:node-set($items)/*"> +      <xsl:value-of select="." /> +      <xsl:if test="not(position() = last())"> +        <xsl:value-of select="$separator" /> +      </xsl:if> +    </xsl:for-each> +  </xsl:template> + +  <!-- Repeat a string (space by default) a given number of times. --> +  <xsl:template name="repeat"> +    <xsl:param name="str" select="' '" /> +    <xsl:param name="count" /> + +    <xsl:if test="$count > 0"> +      <xsl:value-of select="$str" /> +      <xsl:call-template name="repeat"> +        <xsl:with-param name="str"   select="$str" /> +        <xsl:with-param name="count" select="$count - 1" /> +      </xsl:call-template> +    </xsl:if> +  </xsl:template> + +  <!-- Record the maximum type lengths of a set of types for use as the +       max-type-lengths parameter of type-and-name. --> +  <xsl:template name="type-lengths"> +    <xsl:param name="items" /> +    <xsl:variable name="type-lengths-rtf"> +      <xsl:for-each select="$items"> +        <item> +          <xsl:choose> +            <xsl:when test="contains(., ' *')"> +              <xsl:value-of select="string-length( +                                    substring-before(., ' *'))" /> +            </xsl:when> +            <xsl:otherwise> +              <xsl:value-of select="string-length(.)" /> +            </xsl:otherwise> +          </xsl:choose> +        </item> +      </xsl:for-each> +    </xsl:variable> +    <xsl:variable name="suffix-lengths-rtf"> +      <xsl:for-each select="$items"> +        <item> +          <xsl:choose> +            <xsl:when test="contains(., ' *')"> +              <xsl:value-of select="string-length(substring-after(., ' *')) +                                    + 1" /> +            </xsl:when> +            <xsl:otherwise> +              <xsl:text>0</xsl:text> +            </xsl:otherwise> +          </xsl:choose> +        </item> +      </xsl:for-each> +    </xsl:variable> +    <max-type-length> +      <xsl:call-template name="max"> +        <xsl:with-param name="items" +                        select="e:node-set($type-lengths-rtf)/*" /> +      </xsl:call-template> +    </max-type-length> +    <max-suffix-length> +      <xsl:call-template name="max"> +        <xsl:with-param name="items" +                        select="e:node-set($suffix-lengths-rtf)/*" /> +      </xsl:call-template> +    </max-suffix-length> +  </xsl:template> + +  <!-- Return the maximum number in a set of numbers. --> +  <xsl:template name="max"> +    <xsl:param name="items" /> +    <xsl:choose> +      <xsl:when test="count($items) = 0"> +        <xsl:text>0</xsl:text> +      </xsl:when> +      <xsl:otherwise> +        <xsl:variable name="head" select="number($items[1])" /> +        <xsl:variable name="tail-max"> +          <xsl:call-template name="max"> +            <xsl:with-param name="items" select="$items[position() > 1]" /> +          </xsl:call-template> +        </xsl:variable> +        <xsl:choose> +          <xsl:when test="$head > number($tail-max)"> +            <xsl:value-of select="$head" /> +          </xsl:when> +          <xsl:otherwise> +            <xsl:value-of select="$tail-max" /> +          </xsl:otherwise> +        </xsl:choose> +      </xsl:otherwise> +    </xsl:choose> +  </xsl:template> +</xsl:transform> 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 <X11/Xmd.h> +#include <X11/X.h> +#include <sys/uio.h> +#include <pthread.h> + +#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 <assert.h> +#include <X11/Xauth.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <sys/param.h> +#include <unistd.h> +#include <stdlib.h> + +#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 <assert.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <sys/select.h> + +#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 <stdlib.h> +#include <string.h> + +#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 <assert.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +#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 <stdlib.h> + +#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 <assert.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#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 <assert.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/fcntl.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#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 <stdlib.h> +#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 <pthread.h> +#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 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<xsl:stylesheet +	version="1.0" +	xmlns:check="http://check.sourceforge.net/ns" +	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +	xmlns="http://www.w3.org/TR/REC-html40"> + +<xsl:output method="html"/> + +<xsl:template match="/"> +<html> + <head> +  <title>Test Suite Results</title> + </head> + + <body> +  <xsl:apply-templates/> + </body> +</html> +</xsl:template> + +<xsl:template match="datetime"> + <xsl:apply-templates/> +</xsl:template> + +<xsl:template match="duration"> + <xsl:apply-templates/> +</xsl:template> + +<xsl:template match="check:suite"> + <xsl:apply-templates select="check:title"/> + <center> + <table width="80%" border="1"> +  <thead> +   <tr> +    <td>Test Path</td> +    <td>Test Function Location</td> +    <td>C Identifier</td> +    <td>Test Case</td> +    <td>Result</td> +   </tr> +  </thead> +  <tbody> +   <xsl:apply-templates select="check:test"/> +  </tbody> + </table> + </center> +</xsl:template> + +<xsl:template match="check:testsuites"> + <xsl:apply-templates select="check:suite"/> + <h3>Unit Test Statistics</h3> + <ul> +  <li>date/time: <xsl:apply-templates select="check:datetime"/></li> +  <li>duration: <xsl:apply-templates select="check:duration"/></li> + </ul> + <hr></hr> +</xsl:template> + +<xsl:template match="check:title"> + <h2>Test Suite: <xsl:apply-templates/></h2> +</xsl:template> + +<xsl:template match="check:test[@result='success']"> + <tr bgcolor="lime"> +  <xsl:apply-templates/> + </tr> +</xsl:template> + +<xsl:template match="check:test[@result='failure']"> + <tr bgcolor="red"> +  <xsl:apply-templates/> + </tr> +</xsl:template> + +<xsl:template match="check:test[@result='error']"> + <tr bgcolor="yellow"> +  <xsl:apply-templates/> + </tr> +</xsl:template> + +<xsl:template match="check:path"> + <td><xsl:apply-templates/></td> +</xsl:template> + +<xsl:template match="check:fn"> + <td><xsl:apply-templates/></td> +</xsl:template> + +<xsl:template match="check:id"> + <td><xsl:apply-templates/></td> +</xsl:template> + +<xsl:template match="check:description"> + <td><xsl:apply-templates/></td> +</xsl:template> + +<xsl:template match="check:message"> + <td><xsl:apply-templates/></td> +</xsl:template> + +</xsl:stylesheet> + 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 <stdlib.h> +#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 <check.h> +#include <string.h> +#include <stdlib.h> +#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 <check.h> + +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@  | 
