summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.cvsignore17
-rw-r--r--src/Makefile.am83
-rw-r--r--src/c-client.xsl1301
-rw-r--r--src/xcb.h165
-rw-r--r--src/xcb_auth.c296
-rw-r--r--src/xcb_conn.c239
-rw-r--r--src/xcb_ext.c122
-rw-r--r--src/xcb_in.c319
-rw-r--r--src/xcb_list.c215
-rw-r--r--src/xcb_out.c272
-rw-r--r--src/xcb_util.c279
-rw-r--r--src/xcb_xid.c70
-rw-r--r--src/xcb_xlib.c41
-rw-r--r--src/xcbext.h75
-rw-r--r--src/xcbint.h183
-rw-r--r--src/xcbxlib.h38
16 files changed, 3715 insertions, 0 deletions
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, &amp;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="&lt;&lt;">
+ <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() &lt; 3]" />
+ <xsl:if test="middle and (count(*[not(self::middle)]) &lt; 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>&amp;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 = &amp;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, &amp;xcb_ret.sequence, xcb_parts, &amp;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(&amp;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 &lt;assert.h&gt;
+#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) &lt; $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) &lt; $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 &gt; 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