diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.cvsignore | 17 | ||||
-rw-r--r-- | src/Makefile.am | 83 | ||||
-rw-r--r-- | src/c-client.xsl | 1301 | ||||
-rw-r--r-- | src/xcb.h | 165 | ||||
-rw-r--r-- | src/xcb_auth.c | 296 | ||||
-rw-r--r-- | src/xcb_conn.c | 239 | ||||
-rw-r--r-- | src/xcb_ext.c | 122 | ||||
-rw-r--r-- | src/xcb_in.c | 319 | ||||
-rw-r--r-- | src/xcb_list.c | 215 | ||||
-rw-r--r-- | src/xcb_out.c | 272 | ||||
-rw-r--r-- | src/xcb_util.c | 279 | ||||
-rw-r--r-- | src/xcb_xid.c | 70 | ||||
-rw-r--r-- | src/xcb_xlib.c | 41 | ||||
-rw-r--r-- | src/xcbext.h | 75 | ||||
-rw-r--r-- | src/xcbint.h | 183 | ||||
-rw-r--r-- | src/xcbxlib.h | 38 |
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, &XCB<!-- + --><xsl:value-of select="$ext" />Id);</l> + </function> + </xsl:if> + <xsl:apply-templates mode="pass1" /> + </xcb> + </xsl:template> + + <!-- Modify names that conflict with C++ keywords by prefixing them with an + underscore. If the name parameter is not specified, it defaults to the + value of the name attribute on the context node. --> + <xsl:template name="canonical-var-name"> + <xsl:param name="name" select="@name" /> + <xsl:if test="$name='new' or $name='delete' + or $name='class' or $name='operator'"> + <xsl:text>_</xsl:text> + </xsl:if> + <xsl:value-of select="$name" /> + </xsl:template> + + <!-- List of core types, for use in canonical-type-name. --> + <xsl:variable name="core-types-rtf"> + <type name="BOOL" /> + <type name="BYTE" /> + <type name="CARD8" /> + <type name="CARD16" /> + <type name="CARD32" /> + <type name="INT8" /> + <type name="INT16" /> + <type name="INT32" /> + + <type name="char" /> + <type name="void" /> + <type name="float" /> + <type name="double" /> + <type name="XID" /> + </xsl:variable> + <xsl:variable name="core-types" select="e:node-set($core-types-rtf)" /> + + <!-- + Output the canonical name for a type. This will be + XCB{extension-containing-Type-if-any}Type, wherever the type is found in + the search path, or just Type if not found. If the type parameter is not + specified, it defaults to the value of the type attribute on the context + node. + --> + <xsl:template name="canonical-type-name"> + <xsl:param name="type" select="string(@type)" /> + + <xsl:variable name="is-unqualified" select="not(contains($type, ':'))"/> + <xsl:variable name="namespace" select="substring-before($type, ':')" /> + <xsl:variable name="unqualified-type"> + <xsl:choose> + <xsl:when test="$is-unqualified"> + <xsl:value-of select="$type" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="substring-after($type, ':')" /> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:choose> + <xsl:when test="$is-unqualified and $core-types/type[@name=$type]"> + <xsl:value-of select="$type" /> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="type-definitions" + select="(/xcb|document($search-path)/xcb + )[$is-unqualified or @header=$namespace] + /*[((self::struct or self::union + or self::xidtype or self::enum + or self::event or self::eventcopy + or self::error or self::errorcopy) + and @name=$unqualified-type) + or (self::typedef + and @newname=$unqualified-type)]" /> + <xsl:choose> + <xsl:when test="count($type-definitions) = 1"> + <xsl:for-each select="$type-definitions"> + <xsl:text>XCB</xsl:text> + <xsl:value-of select="concat(/xcb/@extension-name, + $unqualified-type)" /> + </xsl:for-each> + </xsl:when> + <xsl:when test="count($type-definitions) > 1"> + <xsl:message terminate="yes"> + <xsl:text>Multiple definitions of type "</xsl:text> + <xsl:value-of select="$type" /> + <xsl:text>" found.</xsl:text> + <xsl:if test="$is-unqualified"> + <xsl:for-each select="$type-definitions"> + <xsl:text> + </xsl:text> + <xsl:value-of select="concat(/xcb/@header, ':', $type)" /> + </xsl:for-each> + </xsl:if> + </xsl:message> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>No definitions of type "</xsl:text> + <xsl:value-of select="$type" /> + <xsl:text>" found</xsl:text> + <xsl:if test="$is-unqualified"> + <xsl:text>, and it is not a known core type</xsl:text> + </xsl:if> + <xsl:text>.</xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Helper template for requests, that outputs the cookie type. The + context node must be the request. --> + <xsl:template name="cookie-type"> + <xsl:text>XCB</xsl:text> + <xsl:choose> + <xsl:when test="reply"> + <xsl:value-of select="concat($ext, @name)" /> + </xsl:when> + <xsl:otherwise> + <xsl:text>Void</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:text>Cookie</xsl:text> + </xsl:template> + + <xsl:template match="request" mode="pass1"> + <xsl:if test="reply"> + <struct name="XCB{$ext}{@name}Cookie"> + <field type="unsigned int" name="sequence" /> + </struct> + </xsl:if> + <struct name="XCB{$ext}{@name}Req"> + <field type="CARD8" name="major_opcode" no-assign="true" /> + <xsl:if test="$ext"> + <field type="CARD8" name="minor_opcode" no-assign="true" /> + </xsl:if> + <xsl:apply-templates select="*[not(self::reply)]" mode="field" /> + <middle> + <field type="CARD16" name="length" no-assign="true" /> + </middle> + </struct> + <function name="XCB{$ext}{@name}"> + <xsl:attribute name="type"> + <xsl:call-template name="cookie-type" /> + </xsl:attribute> + <field type="XCBConnection *" name="c" /> + <xsl:apply-templates select="*[not(self::reply)]" mode="param" /> + <do-request ref="XCB{$ext}{@name}Req" opcode="{@opcode}"> + <xsl:if test="reply"> + <xsl:attribute name="has-reply">true</xsl:attribute> + </xsl:if> + </do-request> + </function> + <xsl:if test="reply"> + <struct name="XCB{$ext}{@name}Rep"> + <field type="BYTE" name="response_type" /> + <xsl:apply-templates select="reply/*" mode="field" /> + <middle> + <field type="CARD16" name="sequence" /> + <field type="CARD32" name="length" /> + </middle> + </struct> + <iterator-functions ref="XCB{$ext}{@name}" kind="Rep" /> + <function type="XCB{$ext}{@name}Rep *" name="XCB{$ext}{@name}Reply"> + <field type="XCBConnection *" name="c" /> + <field name="cookie"> + <xsl:attribute name="type"> + <xsl:call-template name="cookie-type" /> + </xsl:attribute> + </field> + <field type="XCBGenericError **" name="e" /> + <l>return (XCB<xsl:value-of select="concat($ext, @name)" />Rep *)<!-- + --> XCBWaitForReply(c, cookie.sequence, e);</l> + </function> + </xsl:if> + </xsl:template> + + <xsl:template match="xidtype" mode="pass1"> + <struct name="XCB{$ext}{@name}"> + <field type="CARD32" name="xid" /> + </struct> + <iterator ref="XCB{$ext}{@name}" /> + <iterator-functions ref="XCB{$ext}{@name}" /> + <function type="XCB{$ext}{@name}" name="XCB{$ext}{@name}New"> + <field type="XCBConnection *" name="c" /> + <l>XCB<xsl:value-of select="concat($ext, @name)" /> ret;</l> + <l>ret.xid = XCBGenerateID(c);</l> + <l>return ret;</l> + </function> + </xsl:template> + + <xsl:template match="struct|union" mode="pass1"> + <struct name="XCB{$ext}{@name}"> + <xsl:if test="self::union"> + <xsl:attribute name="kind">union</xsl:attribute> + </xsl:if> + <xsl:apply-templates select="*" mode="field" /> + </struct> + <iterator ref="XCB{$ext}{@name}" /> + <iterator-functions ref="XCB{$ext}{@name}" /> + </xsl:template> + + <xsl:template match="event|eventcopy|error|errorcopy" mode="pass1"> + <xsl:variable name="suffix"> + <xsl:choose> + <xsl:when test="self::event|self::eventcopy"> + <xsl:text>Event</xsl:text> + </xsl:when> + <xsl:when test="self::error|self::errorcopy"> + <xsl:text>Error</xsl:text> + </xsl:when> + </xsl:choose> + </xsl:variable> + <constant type="number" name="XCB{$ext}{@name}" value="{@number}" /> + <xsl:choose> + <xsl:when test="self::event|self::error"> + <struct name="XCB{$ext}{@name}{$suffix}"> + <field type="BYTE" name="response_type" /> + <xsl:if test="self::error"> + <field type="BYTE" name="error_code" /> + </xsl:if> + <xsl:apply-templates select="*" mode="field" /> + <xsl:if test="not(self::event and boolean(@no-sequence-number))"> + <middle> + <field type="CARD16" name="sequence" /> + </middle> + </xsl:if> + </struct> + </xsl:when> + <xsl:when test="self::eventcopy|self::errorcopy"> + <typedef newname="XCB{$ext}{@name}{$suffix}"> + <xsl:attribute name="oldname"> + <xsl:call-template name="canonical-type-name"> + <xsl:with-param name="type" select="@ref" /> + </xsl:call-template> + <xsl:value-of select="$suffix" /> + </xsl:attribute> + </typedef> + </xsl:when> + </xsl:choose> + </xsl:template> + + <xsl:template match="typedef" mode="pass1"> + <typedef> + <xsl:attribute name="oldname"> + <xsl:call-template name="canonical-type-name"> + <xsl:with-param name="type" select="@oldname" /> + </xsl:call-template> + </xsl:attribute> + <xsl:attribute name="newname"> + <xsl:call-template name="canonical-type-name"> + <xsl:with-param name="type" select="@newname" /> + </xsl:call-template> + </xsl:attribute> + </typedef> + <iterator ref="XCB{$ext}{@newname}" /> + <iterator-functions ref="XCB{$ext}{@newname}" /> + </xsl:template> + + <xsl:template match="enum" mode="pass1"> + <enum name="XCB{$ext}{@name}"> + <xsl:for-each select="item"> + <item name="XCB{$ext}{../@name}{@name}"> + <xsl:copy-of select="*" /> + </item> + </xsl:for-each> + </enum> + </xsl:template> + + <!-- + Templates for processing fields. + --> + + <xsl:template match="pad" mode="field"> + <xsl:copy-of select="." /> + </xsl:template> + + <xsl:template match="field|exprfield" mode="field"> + <xsl:copy> + <xsl:attribute name="type"> + <xsl:call-template name="canonical-type-name" /> + </xsl:attribute> + <xsl:attribute name="name"> + <xsl:call-template name="canonical-var-name" /> + </xsl:attribute> + <xsl:copy-of select="*" /> + </xsl:copy> + </xsl:template> + + <xsl:template match="list" mode="field"> + <xsl:variable name="type"><!-- + --><xsl:call-template name="canonical-type-name" /><!-- + --></xsl:variable> + <list type="{$type}"> + <xsl:attribute name="name"> + <xsl:call-template name="canonical-var-name" /> + </xsl:attribute> + <xsl:if test="not(parent::request) and node() + and not(.//*[not(self::value or self::op)])"> + <xsl:attribute name="fixed">true</xsl:attribute> + </xsl:if> + <!-- Handle lists with no length expressions. --> + <xsl:if test="not(node())"> + <xsl:choose> + <!-- In a request, refer to an implicit localparam for length. --> + <xsl:when test="parent::request"> + <fieldref> + <xsl:value-of select="concat(@name, '_len')" /> + </fieldref> + </xsl:when> + <!-- In a reply, use the length of the reply to determine the length + of the list. --> + <xsl:when test="parent::reply"> + <op op="/"> + <op op="<<"> + <fieldref>length</fieldref> + <value>2</value> + </op> + <function-call name="sizeof"> + <param><xsl:value-of select="$type" /></param> + </function-call> + </op> + </xsl:when> + <!-- Other cases generate an error. --> + <xsl:otherwise> + <xsl:message terminate="yes"><!-- + -->Encountered a list with no length expresssion outside a<!-- + --> request or reply.<!-- + --></xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + <xsl:copy-of select="*" /> + </list> + </xsl:template> + + <xsl:template match="valueparam" mode="field"> + <field> + <xsl:attribute name="type"> + <xsl:call-template name="canonical-type-name"> + <xsl:with-param name="type" select="@value-mask-type" /> + </xsl:call-template> + </xsl:attribute> + <xsl:attribute name="name"> + <xsl:call-template name="canonical-var-name"> + <xsl:with-param name="name" select="@value-mask-name" /> + </xsl:call-template> + </xsl:attribute> + </field> + <list type="CARD32"> + <xsl:attribute name="name"> + <xsl:call-template name="canonical-var-name"> + <xsl:with-param name="name" select="@value-list-name" /> + </xsl:call-template> + </xsl:attribute> + <function-call name="XCBPopcount"> + <param> + <fieldref> + <xsl:call-template name="canonical-var-name"> + <xsl:with-param name="name" select="@value-mask-name" /> + </xsl:call-template> + </fieldref> + </param> + </function-call> + </list> + </xsl:template> + + <xsl:template match="field|localfield" mode="param"> + <field> + <xsl:attribute name="type"> + <xsl:call-template name="canonical-type-name" /> + </xsl:attribute> + <xsl:attribute name="name"> + <xsl:call-template name="canonical-var-name" /> + </xsl:attribute> + </field> + </xsl:template> + + <xsl:template match="list" mode="param"> + <!-- If no length expression is provided, use a CARD32 localfield. --> + <xsl:if test="not(node())"> + <field type="CARD32" name="{@name}_len" /> + </xsl:if> + <field> + <xsl:attribute name="type"> + <xsl:text>const </xsl:text> + <xsl:call-template name="canonical-type-name" /> + <xsl:text> *</xsl:text> + </xsl:attribute> + <xsl:attribute name="name"> + <xsl:call-template name="canonical-var-name" /> + </xsl:attribute> + </field> + </xsl:template> + + <xsl:template match="valueparam" mode="param"> + <field> + <xsl:attribute name="type"> + <xsl:call-template name="canonical-type-name"> + <xsl:with-param name="type" select="@value-mask-type" /> + </xsl:call-template> + </xsl:attribute> + <xsl:attribute name="name"> + <xsl:call-template name="canonical-var-name"> + <xsl:with-param name="name" select="@value-mask-name" /> + </xsl:call-template> + </xsl:attribute> + </field> + <field type="const CARD32 *"> + <xsl:attribute name="name"> + <xsl:call-template name="canonical-var-name"> + <xsl:with-param name="name" select="@value-list-name" /> + </xsl:call-template> + </xsl:attribute> + </field> + </xsl:template> + + <!-- Second pass: Process the variable. --> + <xsl:variable name="result-rtf"> + <xsl:apply-templates select="$pass1/*" mode="pass2" /> + </xsl:variable> + <xsl:variable name="result" select="e:node-set($result-rtf)" /> + + <xsl:template match="xcb" mode="pass2"> + <xcb> + <xsl:copy-of select="@*" /> + <xsl:apply-templates mode="pass2" + select="constant|enum|struct|typedef|iterator" /> + <xsl:apply-templates mode="pass2" + select="function|iterator-functions" /> + </xcb> + </xsl:template> + + <!-- Generic rules for nodes that don't need further processing: copy node + with attributes, and recursively process the child nodes. --> + <xsl:template match="*" mode="pass2"> + <xsl:copy> + <xsl:copy-of select="@*" /> + <xsl:apply-templates mode="pass2" /> + </xsl:copy> + </xsl:template> + + <xsl:template match="struct" mode="pass2"> + <xsl:if test="@kind='union' and list[not(@fixed)]"> + <xsl:message terminate="yes">Unions must be fixed length.</xsl:message> + </xsl:if> + <struct name="{@name}"> + <xsl:if test="@kind"> + <xsl:attribute name="kind"> + <xsl:value-of select="@kind" /> + </xsl:attribute> + </xsl:if> + <!-- FIXME: This should go by size, not number of fields. --> + <xsl:copy-of select="node()[not(self::middle) + and position() < 3]" /> + <xsl:if test="middle and (count(*[not(self::middle)]) < 2)"> + <pad bytes="{2 - count(*[not(self::middle)])}" /> + </xsl:if> + <xsl:copy-of select="middle/*" /> + <xsl:copy-of select="node()[not(self::middle) and (position() > 2)]" /> + </struct> + </xsl:template> + + <xsl:template match="do-request" mode="pass2"> + <xsl:variable name="struct" + select="$pass1/xcb/struct[@name=current()/@ref]" /> + + <xsl:variable name="num-parts" select="1+count($struct/list)" /> + + <l>static const XCBProtocolRequest xcb_req = {</l> + <indent> + <l>/* count */ <xsl:value-of select="$num-parts" />,</l> + <l>/* ext */ <xsl:choose> + <xsl:when test="$ext"> + <xsl:text>&XCB</xsl:text> + <xsl:value-of select="$ext" /> + <xsl:text>Id</xsl:text> + </xsl:when> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose>,</l> + <l>/* opcode */ <xsl:value-of select="@opcode" />,</l> + <l>/* isvoid */ <xsl:value-of select="1-boolean(@has-reply)" /></l> + </indent> + <l>};</l> + + <l /> + <l>struct iovec xcb_parts[<xsl:value-of select="$num-parts" />];</l> + <l><xsl:value-of select="../@type" /> xcb_ret;</l> + <l><xsl:value-of select="@ref" /> xcb_out;</l> + + <l /> + <xsl:apply-templates select="$struct//*[(self::field or self::exprfield) + and not(boolean(@no-assign))]" + mode="assign" /> + + <l /> + <l>xcb_parts[0].iov_base = &xcb_out;</l> + <l>xcb_parts[0].iov_len = sizeof(xcb_out);</l> + + <xsl:for-each select="$struct/list"> + <l>xcb_parts[<xsl:number />].iov_base = (void *) <!-- + --><xsl:value-of select="@name" />;</l> + <l>xcb_parts[<xsl:number />].iov_len = <!-- + --><xsl:apply-templates mode="output-expression" /><!-- + --><xsl:if test="not(@type = 'void')"> + <xsl:text> * sizeof(</xsl:text> + <xsl:value-of select="@type" /> + <xsl:text>)</xsl:text> + </xsl:if>;</l> + </xsl:for-each> + + <l>XCBSendRequest(c, &xcb_ret.sequence, xcb_parts, &xcb_req);</l> + <l>return xcb_ret;</l> + </xsl:template> + + <xsl:template match="field" mode="assign"> + <l> + <xsl:text>xcb_out.</xsl:text> + <xsl:value-of select="@name" /> + <xsl:text> = </xsl:text> + <xsl:value-of select="@name" /> + <xsl:text>;</xsl:text> + </l> + </xsl:template> + + <xsl:template match="exprfield" mode="assign"> + <l> + <xsl:text>xcb_out.</xsl:text> + <xsl:value-of select="@name" /> + <xsl:text> = </xsl:text> + <xsl:apply-templates mode="output-expression" /> + <xsl:text>;</xsl:text> + </l> + </xsl:template> + + <xsl:template match="iterator" mode="pass2"> + <struct name="{@ref}Iter"> + <field type="{@ref} *" name="data" /> + <field type="int" name="rem" /> + <field type="int" name="index" /> + </struct> + </xsl:template> + + <!-- Change a_name_like_this to ANameLikeThis. If the parameter name is not + given, it defaults to the name attribute of the context node. --> + <xsl:template name="capitalize"> + <xsl:param name="name" select="string(@name)" /> + <xsl:if test="$name"> + <xsl:value-of select="translate(substring($name,1,1), $lcase, $ucase)" /> + <xsl:choose> + <xsl:when test="contains($name, '_')"> + <xsl:value-of select="substring(substring-before($name, '_'), 2)" /> + <xsl:call-template name="capitalize"> + <xsl:with-param name="name" select="substring-after($name, '_')" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="substring($name, 2)" /> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + </xsl:template> + + <xsl:template match="iterator-functions" mode="pass2"> + <xsl:variable name="ref" select="@ref" /> + <xsl:variable name="kind" select="@kind" /> + <xsl:variable name="struct" + select="$pass1/xcb/struct[@name=concat($ref,$kind)]" /> + <xsl:variable name="nextfields-rtf"> + <nextfield>R + 1</nextfield> + <xsl:for-each select="$struct/list[not(@fixed)]"> + <xsl:choose> + <xsl:when test="substring(@type, 1, 3) = 'XCB'"> + <nextfield><xsl:value-of select="@type" />End(<!-- + --><xsl:value-of select="$ref" /><!-- + --><xsl:call-template name="capitalize" />Iter(R))</nextfield> + </xsl:when> + <xsl:otherwise> + <nextfield><xsl:value-of select="$ref" /><!-- + --><xsl:call-template name="capitalize" />End(R)</nextfield> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + </xsl:variable> + <xsl:variable name="nextfields" select="e:node-set($nextfields-rtf)" /> + <xsl:for-each select="$struct/list[not(@fixed)]"> + <xsl:variable name="number" + select="1+count(preceding-sibling::list[not(@fixed)])" /> + <xsl:variable name="nextfield" select="$nextfields/nextfield[$number]" /> + <xsl:variable name="is-first" + select="not(preceding-sibling::list[not(@fixed)])" /> + <xsl:variable name="field-name"><!-- + --><xsl:call-template name="capitalize" /><!-- + --></xsl:variable> + <xsl:variable name="is-variable" + select="$pass1/xcb/struct[@name=current()/@type]/list + or document($search-path)/xcb + /struct[concat('XCB', + ancestor::xcb/@extension-name, + @name) = current()/@type] + /*[self::valueparam or self::list]" /> + <xsl:if test="not($is-variable)"> + <function type="{@type} *" name="{$ref}{$field-name}"> + <field type="{$ref}{$kind} *" name="R" /> + <xsl:choose> + <xsl:when test="$is-first"> + <l>return (<xsl:value-of select="@type" /> *) <!-- + -->(<xsl:value-of select="$nextfield" />);</l> + </xsl:when> + <xsl:otherwise> + <l>XCBGenericIter prev = <!-- + --><xsl:value-of select="$nextfield" />;</l> + <l>return (<xsl:value-of select="@type" /> *) <!-- + -->((char *) prev.data + XCB_TYPE_PAD(<!-- + --><xsl:value-of select="@type" />, prev.index));</l> + </xsl:otherwise> + </xsl:choose> + </function> + </xsl:if> + <function type="int" name="{$ref}{$field-name}Length"> + <field type="{$ref}{$kind} *" name="R" /> + <l>return <xsl:apply-templates mode="output-expression"> + <xsl:with-param name="field-prefix" select="'R->'" /> + </xsl:apply-templates>;</l> + </function> + <xsl:choose> + <xsl:when test="substring(@type, 1, 3) = 'XCB'"> + <function type="{@type}Iter" name="{$ref}{$field-name}Iter"> + <field type="{$ref}{$kind} *" name="R" /> + <l><xsl:value-of select="@type" />Iter i;</l> + <xsl:choose> + <xsl:when test="$is-first"> + <l>i.data = (<xsl:value-of select="@type" /> *) <!-- + -->(<xsl:value-of select="$nextfield" />);</l> + </xsl:when> + <xsl:otherwise> + <l>XCBGenericIter prev = <!-- + --><xsl:value-of select="$nextfield" />;</l> + <l>i.data = (<xsl:value-of select="@type" /> *) <!-- + -->((char *) prev.data + XCB_TYPE_PAD(<!-- + --><xsl:value-of select="@type" />, prev.index));</l> + </xsl:otherwise> + </xsl:choose> + <l>i.rem = <xsl:apply-templates mode="output-expression"> + <xsl:with-param name="field-prefix" select="'R->'" /> + </xsl:apply-templates>;</l> + <l>i.index = (char *) i.data - (char *) R;</l> + <l>return i;</l> + </function> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="cast"> + <xsl:choose> + <xsl:when test="@type='void'">char</xsl:when> + <xsl:otherwise><xsl:value-of select="@type" /></xsl:otherwise> + </xsl:choose> + </xsl:variable> + <function type="XCBGenericIter" name="{$ref}{$field-name}End"> + <field type="{$ref}{$kind} *" name="R" /> + <l>XCBGenericIter i;</l> + <xsl:choose> + <xsl:when test="$is-first"> + <l>i.data = ((<xsl:value-of select="$cast" /> *) <!-- + -->(<xsl:value-of select="$nextfield" />)) + (<!-- + --><xsl:apply-templates mode="output-expression"> + <xsl:with-param name="field-prefix" select="'R->'" /> + </xsl:apply-templates>);</l> + </xsl:when> + <xsl:otherwise> + <l>XCBGenericIter child = <!-- + --><xsl:value-of select="$nextfield" />;</l> + <l>i.data = ((<xsl:value-of select="$cast" /> *) <!-- + -->child.data) + (<!-- + --><xsl:apply-templates mode="output-expression"> + <xsl:with-param name="field-prefix" select="'R->'" /> + </xsl:apply-templates>);</l> + </xsl:otherwise> + </xsl:choose> + <l>i.rem = 0;</l> + <l>i.index = (char *) i.data - (char *) R;</l> + <l>return i;</l> + </function> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + <xsl:if test="not($kind)"> + <function type="void" name="{$ref}Next"> + <field type="{$ref}Iter *" name="i" /> + <xsl:choose> + <xsl:when test="$struct/list[not(@fixed)]"> + <l><xsl:value-of select="$ref" /> *R = i->data;</l> + <l>XCBGenericIter child = <!-- + --><xsl:value-of select="$nextfields/nextfield[last()]" />;</l> + <l>--i->rem;</l> + <l>i->data = (<xsl:value-of select="$ref" /> *) child.data;</l> + <l>i->index = child.index;</l> + </xsl:when> + <xsl:otherwise> + <l>--i->rem;</l> + <l>++i->data;</l> + <l>i->index += sizeof(<xsl:value-of select="$ref" />);</l> + </xsl:otherwise> + </xsl:choose> + </function> + <function type="XCBGenericIter" name="{$ref}End"> + <field type="{$ref}Iter" name="i" /> + <l>XCBGenericIter ret;</l> + <xsl:choose> + <xsl:when test="$struct/list[not(@fixed)]"> + <l>while(i.rem > 0)</l> + <indent> + <l><xsl:value-of select="$ref" />Next(&i);</l> + </indent> + <l>ret.data = i.data;</l> + <l>ret.rem = i.rem;</l> + <l>ret.index = i.index;</l> + </xsl:when> + <xsl:otherwise> + <l>ret.data = i.data + i.rem;</l> + <l>ret.index = i.index + ((char *) ret.data - (char *) i.data);</l> + <l>ret.rem = 0;</l> + </xsl:otherwise> + </xsl:choose> + <l>return ret;</l> + </function> + </xsl:if> + </xsl:template> + + <!-- Output the results. --> + <xsl:template match="/"> + <xsl:if test="not(function-available('e:node-set'))"> + <xsl:message terminate="yes"><!-- + -->Error: This stylesheet requires the EXSL node-set extension.<!-- + --></xsl:message> + </xsl:if> + + <xsl:if test="not($h) and not($c)"> + <xsl:message terminate="yes"><!-- + -->Error: Parameter "mode" must be "header" or "source".<!-- + --></xsl:message> + </xsl:if> + + <xsl:apply-templates select="$result/*" mode="output" /> + </xsl:template> + + <xsl:template match="xcb" mode="output"> + <xsl:variable name="guard"><!-- + -->__<xsl:value-of select="$ucase-header" />_H<!-- + --></xsl:variable> + +<xsl:text>/* + * This file generated automatically from </xsl:text> +<xsl:value-of select="$header" /><xsl:text>.xml by c-client.xsl using XSLT. + * Edit at your peril. + */ +</xsl:text> + +<xsl:if test="$h"><xsl:text> +#ifndef </xsl:text><xsl:value-of select="$guard" /><xsl:text> +#define </xsl:text><xsl:value-of select="$guard" /><xsl:text> +</xsl:text> +#include "xcb.h" +<xsl:for-each select="$root/xcb/import"> +<xsl:text>#include "</xsl:text><xsl:value-of select="." /><xsl:text>.h" +</xsl:text> +</xsl:for-each> +<xsl:text> +</xsl:text> +</xsl:if> + +<xsl:if test="$c"><xsl:text> +#include <assert.h> +#include "xcbext.h" +#include "</xsl:text><xsl:value-of select="$header" /><xsl:text>.h" + +</xsl:text></xsl:if> + + <xsl:apply-templates mode="output" /> + +<xsl:if test="$h"> +<xsl:text> +#endif +</xsl:text> +</xsl:if> + </xsl:template> + + <xsl:template match="constant" mode="output"> + <xsl:choose> + <xsl:when test="@type = 'number'"> + <xsl:if test="$h"> + <xsl:text>#define </xsl:text> + <xsl:value-of select="@name" /> + <xsl:text> </xsl:text> + <xsl:value-of select="@value" /> + <xsl:text> + +</xsl:text> + </xsl:if> + </xsl:when> + <xsl:when test="@type = 'string'"> + <xsl:if test="$h"> + <xsl:text>extern </xsl:text> + </xsl:if> + <xsl:text>const char </xsl:text> + <xsl:value-of select="@name" /> + <xsl:text>[]</xsl:text> + <xsl:if test="$c"> + <xsl:text> = "</xsl:text> + <xsl:value-of select="@value" /> + <xsl:text>"</xsl:text> + </xsl:if> + <xsl:text>; + +</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:if test="$h"> + <xsl:text>extern </xsl:text> + </xsl:if> + <xsl:call-template name="type-and-name" /> + <xsl:if test="$c"> + <xsl:text> = </xsl:text> + <xsl:value-of select="@value" /> + </xsl:if> + <xsl:text>; + +</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="typedef" mode="output"> + <xsl:if test="$h"> + <xsl:text>typedef </xsl:text> + <xsl:value-of select="@oldname" /> + <xsl:text> </xsl:text> + <xsl:value-of select="@newname" /> + <xsl:text>; + +</xsl:text> + </xsl:if> + </xsl:template> + + <xsl:template match="struct" mode="output"> + <xsl:if test="$h"> + <xsl:variable name="type-lengths"> + <xsl:call-template name="type-lengths"> + <xsl:with-param name="items" select="field/@type" /> + </xsl:call-template> + </xsl:variable> + <xsl:text>typedef </xsl:text> + <xsl:if test="not(@kind)">struct</xsl:if><xsl:value-of select="@kind" /> + <xsl:text> { +</xsl:text> + <xsl:for-each select="exprfield|field|list[@fixed]|pad"> + <xsl:text> </xsl:text> + <xsl:apply-templates select="."> + <xsl:with-param name="type-lengths" select="$type-lengths" /> + </xsl:apply-templates> + <xsl:text>; +</xsl:text> + </xsl:for-each> + <xsl:text>} </xsl:text> + <xsl:value-of select="@name" /> + <xsl:text>; + +</xsl:text> + </xsl:if> + </xsl:template> + + <xsl:template match="enum" mode="output"> + <xsl:if test="$h"> + <xsl:text>typedef enum { + </xsl:text> + <xsl:call-template name="list"> + <xsl:with-param name="separator"><xsl:text>, + </xsl:text></xsl:with-param> + <xsl:with-param name="items"> + <xsl:for-each select="item"> + <item> + <xsl:value-of select="@name" /> + <xsl:if test="node()"> <!-- If there is an expression --> + <xsl:text> = </xsl:text> + <xsl:apply-templates mode="output-expression" /> + </xsl:if> + </item> + </xsl:for-each> + </xsl:with-param> + </xsl:call-template> + <xsl:text> +} </xsl:text><xsl:value-of select="@name" /><xsl:text>; + +</xsl:text> + </xsl:if> + </xsl:template> + + <xsl:template match="function" mode="output"> + <xsl:variable name="decl-open" select="concat(@name, ' (')" /> + <xsl:variable name="type-lengths"> + <xsl:call-template name="type-lengths"> + <xsl:with-param name="items" select="field/@type" /> + </xsl:call-template> + </xsl:variable> + <xsl:value-of select="@type" /> + <xsl:text> +</xsl:text> + <xsl:value-of select="$decl-open" /> + <xsl:call-template name="list"> + <xsl:with-param name="separator"> + <xsl:text>, +</xsl:text> + <xsl:call-template name="repeat"> + <xsl:with-param name="count" select="string-length($decl-open)" /> + </xsl:call-template> + </xsl:with-param> + <xsl:with-param name="items"> + <xsl:for-each select="field"> + <item> + <xsl:apply-templates select="."> + <xsl:with-param name="type-lengths" select="$type-lengths" /> + </xsl:apply-templates> + </item> + </xsl:for-each> + </xsl:with-param> + </xsl:call-template> + <xsl:text>)</xsl:text> + + <xsl:if test="$h"><xsl:text>; + +</xsl:text></xsl:if> + + <xsl:if test="$c"> + <xsl:text> +{ +</xsl:text> + <xsl:apply-templates select="l|indent" mode="function-body"> + <xsl:with-param name="indent" select="$indent-string" /> + </xsl:apply-templates> + <xsl:text>} + +</xsl:text> + </xsl:if> + </xsl:template> + + <xsl:template match="l" mode="function-body"> + <xsl:param name="indent" /> + <xsl:value-of select="concat($indent, .)" /><xsl:text> +</xsl:text> + </xsl:template> + + <xsl:template match="indent" mode="function-body"> + <xsl:param name="indent" /> + <xsl:apply-templates select="l|indent" mode="function-body"> + <xsl:with-param name="indent" select="concat($indent, $indent-string)" /> + </xsl:apply-templates> + </xsl:template> + + <xsl:template match="value" mode="output-expression"> + <xsl:value-of select="." /> + </xsl:template> + + <xsl:template match="fieldref" mode="output-expression"> + <xsl:param name="field-prefix" /> + <xsl:value-of select="concat($field-prefix, .)" /> + </xsl:template> + + <xsl:template match="op" mode="output-expression"> + <xsl:param name="field-prefix" /> + <xsl:text>(</xsl:text> + <xsl:apply-templates select="node()[1]" mode="output-expression"> + <xsl:with-param name="field-prefix" select="$field-prefix" /> + </xsl:apply-templates> + <xsl:text> </xsl:text> + <xsl:value-of select="@op" /> + <xsl:text> </xsl:text> + <xsl:apply-templates select="node()[2]" mode="output-expression"> + <xsl:with-param name="field-prefix" select="$field-prefix" /> + </xsl:apply-templates> + <xsl:text>)</xsl:text> + </xsl:template> + + <xsl:template match="function-call" mode="output-expression"> + <xsl:param name="field-prefix" /> + <xsl:value-of select="@name" /> + <xsl:text>(</xsl:text> + <xsl:call-template name="list"> + <xsl:with-param name="separator" select="', '" /> + <xsl:with-param name="items"> + <xsl:for-each select="param"> + <item><xsl:apply-templates mode="output-expression"> + <xsl:with-param name="field-prefix" select="$field-prefix" /> + </xsl:apply-templates></item> + </xsl:for-each> + </xsl:with-param> + </xsl:call-template> + <xsl:text>)</xsl:text> + </xsl:template> + + <!-- Catch invalid elements in expressions. --> + <xsl:template match="*" mode="output-expression"> + <xsl:message terminate="yes"> + <xsl:text>Invalid element in expression: </xsl:text> + <xsl:value-of select="name()" /> + </xsl:message> + </xsl:template> + + <xsl:template match="field|exprfield"> + <xsl:param name="type-lengths" select="0" /> + <xsl:call-template name="type-and-name"> + <xsl:with-param name="type-lengths" select="$type-lengths" /> + </xsl:call-template> + </xsl:template> + + <xsl:template match="list[@fixed]"> + <xsl:param name="type-lengths" select="0" /> + <xsl:call-template name="type-and-name"> + <xsl:with-param name="type-lengths" select="$type-lengths" /> + </xsl:call-template> + <xsl:text>[</xsl:text> + <xsl:apply-templates mode="output-expression" /> + <xsl:text>]</xsl:text> + </xsl:template> + + <xsl:template match="pad"> + <xsl:param name="type-lengths" select="0" /> + + <xsl:variable name="padnum"><xsl:number /></xsl:variable> + + <xsl:call-template name="type-and-name"> + <xsl:with-param name="type" select="'CARD8'" /> + <xsl:with-param name="name"> + <xsl:text>pad</xsl:text> + <xsl:value-of select="$padnum - 1" /> + </xsl:with-param> + <xsl:with-param name="type-lengths" select="$type-lengths" /> + </xsl:call-template> + <xsl:if test="@bytes > 1"> + <xsl:text>[</xsl:text> + <xsl:value-of select="@bytes" /> + <xsl:text>]</xsl:text> + </xsl:if> + </xsl:template> + + <!-- Output the given type and name (defaulting to the corresponding + attributes of the context node), with the appropriate spacing. The + type must consist of a base type (which may contain spaces), then + optionally a single space and a suffix of one or more '*' characters. + If the type-lengths parameter is provided, use it to line up the base + types and suffixs of the type declarations. --> + <xsl:template name="type-and-name"> + <xsl:param name="type" select="@type" /> + <xsl:param name="name" select="@name" /> + <xsl:param name="type-lengths"> + <max-type-length>0</max-type-length> + <max-suffix-length>0</max-suffix-length> + </xsl:param> + + <xsl:variable name="type-lengths-ns" select="e:node-set($type-lengths)" /> + <xsl:variable name="min-type-length" + select="$type-lengths-ns/max-type-length" /> + <xsl:variable name="min-suffix-length" + select="$type-lengths-ns/max-suffix-length" /> + + <xsl:variable name="base-type"> + <xsl:choose> + <xsl:when test="contains($type, ' *')"> + <xsl:value-of select="substring-before($type, ' *')" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$type" /> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="suffix"> + <xsl:if test="contains($type, ' *')"> + <xsl:text>*</xsl:text> + <xsl:value-of select="substring-after($type, ' *')" /> + </xsl:if> + </xsl:variable> + + <xsl:value-of select="$base-type" /> + <xsl:if test="string-length($base-type) < $min-type-length"> + <xsl:call-template name="repeat"> + <xsl:with-param name="count" select="$min-type-length + - string-length($base-type)" /> + </xsl:call-template> + </xsl:if> + <xsl:text> </xsl:text> + <xsl:if test="string-length($suffix) < $min-suffix-length"> + <xsl:call-template name="repeat"> + <xsl:with-param name="count" select="$min-suffix-length + - string-length($suffix)" /> + </xsl:call-template> + </xsl:if> + <xsl:value-of select="$suffix" /> + <xsl:value-of select="$name" /> + </xsl:template> + + <!-- Output a list with a given separator. Empty items are skipped. --> + <xsl:template name="list"> + <xsl:param name="separator" /> + <xsl:param name="items" /> + + <xsl:for-each select="e:node-set($items)/*"> + <xsl:value-of select="." /> + <xsl:if test="not(position() = last())"> + <xsl:value-of select="$separator" /> + </xsl:if> + </xsl:for-each> + </xsl:template> + + <!-- Repeat a string (space by default) a given number of times. --> + <xsl:template name="repeat"> + <xsl:param name="str" select="' '" /> + <xsl:param name="count" /> + + <xsl:if test="$count > 0"> + <xsl:value-of select="$str" /> + <xsl:call-template name="repeat"> + <xsl:with-param name="str" select="$str" /> + <xsl:with-param name="count" select="$count - 1" /> + </xsl:call-template> + </xsl:if> + </xsl:template> + + <!-- Record the maximum type lengths of a set of types for use as the + max-type-lengths parameter of type-and-name. --> + <xsl:template name="type-lengths"> + <xsl:param name="items" /> + <xsl:variable name="type-lengths-rtf"> + <xsl:for-each select="$items"> + <item> + <xsl:choose> + <xsl:when test="contains(., ' *')"> + <xsl:value-of select="string-length( + substring-before(., ' *'))" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="string-length(.)" /> + </xsl:otherwise> + </xsl:choose> + </item> + </xsl:for-each> + </xsl:variable> + <xsl:variable name="suffix-lengths-rtf"> + <xsl:for-each select="$items"> + <item> + <xsl:choose> + <xsl:when test="contains(., ' *')"> + <xsl:value-of select="string-length(substring-after(., ' *')) + + 1" /> + </xsl:when> + <xsl:otherwise> + <xsl:text>0</xsl:text> + </xsl:otherwise> + </xsl:choose> + </item> + </xsl:for-each> + </xsl:variable> + <max-type-length> + <xsl:call-template name="max"> + <xsl:with-param name="items" + select="e:node-set($type-lengths-rtf)/*" /> + </xsl:call-template> + </max-type-length> + <max-suffix-length> + <xsl:call-template name="max"> + <xsl:with-param name="items" + select="e:node-set($suffix-lengths-rtf)/*" /> + </xsl:call-template> + </max-suffix-length> + </xsl:template> + + <!-- Return the maximum number in a set of numbers. --> + <xsl:template name="max"> + <xsl:param name="items" /> + <xsl:choose> + <xsl:when test="count($items) = 0"> + <xsl:text>0</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="head" select="number($items[1])" /> + <xsl:variable name="tail-max"> + <xsl:call-template name="max"> + <xsl:with-param name="items" select="$items[position() > 1]" /> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$head > number($tail-max)"> + <xsl:value-of select="$head" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$tail-max" /> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:template> +</xsl:transform> diff --git a/src/xcb.h b/src/xcb.h new file mode 100644 index 0000000..8dd308a --- /dev/null +++ b/src/xcb.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2001-2004 Bart Massey, Jamey Sharp, and Josh Triplett. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#ifndef __XCB_H +#define __XCB_H +#include <X11/Xmd.h> +#include <X11/X.h> +#include <sys/uio.h> +#include <pthread.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define deprecated __attribute__((__deprecated__)) +#else +#define deprecated +#endif + +/* Pre-defined constants */ + +/* current protocol version */ +#define X_PROTOCOL 11 + +/* current minor version */ +#define X_PROTOCOL_REVISION 0 + +/* X_TCP_PORT + display number = server port for TCP transport */ +#define X_TCP_PORT 6000 + +#define XCB_TYPE_PAD(T,I) (-(I) & (sizeof(T) > 4 ? 3 : sizeof(T) - 1)) + + +/* Opaque structures */ + +typedef struct XCBConnection XCBConnection; + + +/* Other types */ + +typedef struct { + void *data; + int rem; + int index; +} XCBGenericIter; + +typedef struct { + BYTE response_type; + CARD8 pad0; + CARD16 sequence; + CARD32 length; +} XCBGenericRep; + +typedef struct { + BYTE response_type; + CARD8 pad0; + CARD16 sequence; +} XCBGenericEvent; + +typedef struct { + BYTE response_type; + BYTE error_code; + CARD16 sequence; +} XCBGenericError; + +typedef struct { + unsigned int sequence; +} XCBVoidCookie; + + +/* Include the generated xproto and xcb_types headers. */ +#include "xcb_types.h" +#include "xproto.h" + + +/* xcb_auth.c */ + +typedef struct XCBAuthInfo { + int namelen; + char *name; + int datalen; + char *data; +} XCBAuthInfo; + +int XCBGetAuthInfo(int fd, XCBAuthInfo *info) deprecated; + + +/* xcb_out.c */ + +int XCBFlush(XCBConnection *c); +CARD32 XCBGetMaximumRequestLength(XCBConnection *c); + + +/* xcb_in.c */ + +XCBGenericEvent *XCBWaitEvent(XCBConnection *c) deprecated; +XCBGenericEvent *XCBWaitForEvent(XCBConnection *c); +XCBGenericEvent *XCBPollForEvent(XCBConnection *c, int *error); +unsigned int XCBGetRequestRead(XCBConnection *c); + + +/* xcb_ext.c */ + +typedef struct XCBExtension XCBExtension; + +/* Do not free the returned XCBQueryExtensionRep - on return, it's aliased + * from the cache. */ +const XCBQueryExtensionRep *XCBGetExtensionData(XCBConnection *c, XCBExtension *ext); + +void XCBPrefetchExtensionData(XCBConnection *c, XCBExtension *ext); + + +/* xcb_conn.c */ + +XCBConnSetupSuccessRep *XCBGetSetup(XCBConnection *c); +int XCBGetFileDescriptor(XCBConnection *c); + +XCBConnection *XCBConnectToFD(int fd, XCBAuthInfo *auth_info); +void XCBDisconnect(XCBConnection *c); + + +/* xcb_util.c */ + +int XCBParseDisplay(const char *name, char **host, int *display, int *screen); +int XCBOpen(const char *host, int display) deprecated; +int XCBOpenTCP(const char *host, unsigned short port) deprecated; +int XCBOpenUnix(const char *file) deprecated; + +XCBConnection *XCBConnectBasic(void) deprecated; +XCBConnection *XCBConnect(const char *displayname, int *screenp); +XCBConnection *XCBConnectToDisplayWithAuthInfo(const char *display, XCBAuthInfo *auth, int *screen); + +int XCBSync(XCBConnection *c, XCBGenericError **e); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/xcb_auth.c b/src/xcb_auth.c new file mode 100644 index 0000000..9f2cb5a --- /dev/null +++ b/src/xcb_auth.c @@ -0,0 +1,296 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Authorization systems for the X protocol. */ + +#include <assert.h> +#include <X11/Xauth.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <sys/param.h> +#include <unistd.h> +#include <stdlib.h> + +#include "xcb.h" +#include "xcbint.h" + +#ifdef HAS_AUTH_XA1 +#include "xcb_des.h" +#endif + +enum auth_protos { +#ifdef HAS_AUTH_XA1 + AUTH_XA1, +#endif + AUTH_MC1, + N_AUTH_PROTOS +}; + +static char *authnames[N_AUTH_PROTOS] = { +#ifdef HAS_AUTH_XA1 + "XDM-AUTHORIZATION-1", +#endif + "MIT-MAGIC-COOKIE-1", +}; + +#ifdef HAS_AUTH_XA1 + +static int next_nonce(void) +{ + static int nonce = 0; + static pthread_mutex_t nonce_mutex = PTHREAD_MUTEX_INITIALIZER; + int ret; + pthread_mutex_lock(&nonce_mutex); + ret = nonce++; + pthread_mutex_unlock(&nonce_mutex); + return ret; +} + +/* + * This code and the code it calls is taken from libXdmcp, + * specifically from Wrap.c, Wrap.h, and Wraphelp.c. The US + * has changed, thank goodness, and it should be OK to bury + * DES code in an open source product without a maze of + * twisty wrapper functions stored offshore. Or maybe + * not. --Bart Massey 2003/11/5 + */ + +static void +Wrap ( + des_cblock input, + des_cblock key, + des_cblock output, + int bytes) +{ + int i, j; + int len; + des_cblock tmp; + des_cblock expand_key; + des_key_schedule schedule; + + XCBDESKeyToOddParity (key, expand_key); + XCBDESKeySchedule (expand_key, schedule); + for (j = 0; j < bytes; j += 8) + { + len = 8; + if (bytes - j < len) + len = bytes - j; + /* block chaining */ + for (i = 0; i < len; i++) + { + if (j == 0) + tmp[i] = input[i]; + else + tmp[i] = input[j + i] ^ output[j - 8 + i]; + } + for (; i < 8; i++) + { + if (j == 0) + tmp[i] = 0; + else + tmp[i] = 0 ^ output[j - 8 + i]; + } + XCBDESEncrypt (tmp, (output + j), schedule, 1); + } +} + +#endif + +static size_t memdup(char **dst, void *src, size_t len) +{ + if(len) + *dst = malloc(len); + else + *dst = 0; + if(!*dst) + return 0; + memcpy(*dst, src, len); + return len; +} + +static int authname_match(enum auth_protos kind, char *name, int namelen) +{ + if(strlen(authnames[kind]) != namelen) + return 0; + if(memcmp(authnames[kind], name, namelen)) + return 0; + return 1; +} + +static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen) +{ + char *addr = 0; + int addrlen = 0; + unsigned short family; + char hostnamebuf[256]; /* big enough for max hostname */ + char dispbuf[40]; /* big enough to hold more than 2^64 base 10 */ + char *display; + int authnamelens[N_AUTH_PROTOS]; + int i; + + family = FamilyLocal; /* 256 */ + switch (sockname->sa_family) { + case AF_INET: + /*block*/ { + struct sockaddr_in *si = (struct sockaddr_in *) sockname; + assert(sizeof(*si) == socknamelen); + addr = (char *) &si->sin_addr; + addrlen = 4; + if (ntohl(si->sin_addr.s_addr) != 0x7f000001) + family = FamilyInternet; /* 0 */ + snprintf(dispbuf, sizeof(dispbuf), "%d", ntohs(si->sin_port) - X_TCP_PORT); + display = dispbuf; + } + break; + case AF_UNIX: + /*block*/ { + struct sockaddr_un *su = (struct sockaddr_un *) sockname; + assert(sizeof(*su) >= socknamelen); + display = strrchr(su->sun_path, 'X'); + if (display == 0) + return 0; /* sockname is mangled somehow */ + display++; + } + break; + default: + return 0; /* cannot authenticate this family */ + } + if (family == FamilyLocal) { + if (gethostname(hostnamebuf, sizeof(hostnamebuf)) == -1) + return 0; /* do not know own hostname */ + addr = hostnamebuf; + addrlen = strlen(addr); + } + + for (i = 0; i < N_AUTH_PROTOS; i++) + authnamelens[i] = strlen(authnames[i]); + return XauGetBestAuthByAddr (family, + (unsigned short) addrlen, addr, + (unsigned short) strlen(display), display, + N_AUTH_PROTOS, authnames, authnamelens); +} + +#ifdef HAS_AUTH_XA1 +static void do_append(char *buf, int *idxp, void *val, size_t valsize) { + memcpy(buf + *idxp, val, valsize); + *idxp += valsize; +} +#endif + +static int compute_auth(XCBAuthInfo *info, Xauth *authptr, struct sockaddr *sockname) +{ + if (authname_match(AUTH_MC1, authptr->name, authptr->name_length)) { + info->datalen = memdup(&info->data, authptr->data, authptr->data_length); + if(!info->datalen) + return 0; + return 1; + } +#ifdef HAS_AUTH_XA1 +#define APPEND(buf,idx,val) do_append((buf),&(idx),(val),sizeof(val)) + if (authname_match(AUTH_XA1, authptr->name, authptr->name_length)) { + int j; + + info->data = malloc(192 / 8); + if(!info->data) + return 0; + + for (j = 0; j < 8; j++) + info->data[j] = authptr->data[j]; + switch(sockname->sa_family) { + case AF_INET: + /*block*/ { + struct sockaddr_in *si = (struct sockaddr_in *) sockname; + APPEND(info->data, j, si->sin_addr.s_addr); + APPEND(info->data, j, si->sin_port); + } + break; + case AF_UNIX: + /*block*/ { + long fakeaddr = htonl(0xffffffff - next_nonce()); + short fakeport = htons(getpid()); + APPEND(info->data, j, fakeaddr); + APPEND(info->data, j, fakeport); + } + break; + default: + free(info->data); + return 0; /* do not know how to build this */ + } + { + long now; + time(&now); + now = htonl(now); + APPEND(info->data, j, now); + } + assert(j <= 192 / 8); + while (j < 192 / 8) + info->data[j++] = 0; + info->datalen = j; + Wrap (info->data, authptr->data + 8, info->data, info->datalen); + return 1; + } +#undef APPEND +#endif + + return 0; /* Unknown authorization type */ +} + +int XCBGetAuthInfo(int fd, XCBAuthInfo *info) +{ + /* code adapted from Xlib/ConnDis.c, xtrans/Xtranssocket.c, + xtrans/Xtransutils.c */ + char sockbuf[sizeof(struct sockaddr) + MAXPATHLEN]; + unsigned int socknamelen = sizeof(sockbuf); /* need extra space */ + struct sockaddr *sockname = (struct sockaddr *) &sockbuf; + Xauth *authptr = 0; + int ret = 1; + + /* ensure info has reasonable contents */ + /* XXX This should be removed, but Jamey depends on it + somehow but can't remember how. Principle: don't touch + someone else's data if you're borken. */ + info->namelen = info->datalen = 0; + info->name = info->data = 0; + + if (getpeername(fd, sockname, &socknamelen) == -1) + return 0; /* can only authenticate sockets */ + + authptr = get_authptr(sockname, socknamelen); + if (authptr == 0) + return 0; /* cannot find good auth data */ + + info->namelen = memdup(&info->name, authptr->name, authptr->name_length); + if(info->namelen) + ret = compute_auth(info, authptr, sockname); + if(!ret) + { + free(info->name); + info->name = 0; + info->namelen = 0; + } + XauDisposeAuth(authptr); + return ret; +} diff --git a/src/xcb_conn.c b/src/xcb_conn.c new file mode 100644 index 0000000..0148abf --- /dev/null +++ b/src/xcb_conn.c @@ -0,0 +1,239 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Connection management: the core of XCB. */ + +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <sys/select.h> + +#include "xcb.h" +#include "xcbint.h" + +static int write_setup(XCBConnection *c, XCBAuthInfo *auth_info) +{ + XCBConnSetupReq out; + struct iovec parts[3]; + int count = 0; + int endian = 0x01020304; + int ret; + + memset(&out, 0, sizeof(out)); + + /* B = 0x42 = MSB first, l = 0x6c = LSB first */ + if(htonl(endian) == endian) + out.byte_order = 0x42; + else + out.byte_order = 0x6c; + out.protocol_major_version = X_PROTOCOL; + out.protocol_minor_version = X_PROTOCOL_REVISION; + out.authorization_protocol_name_len = 0; + out.authorization_protocol_data_len = 0; + parts[count].iov_len = sizeof(XCBConnSetupReq); + parts[count++].iov_base = &out; + + if(auth_info) + { + parts[count].iov_len = out.authorization_protocol_name_len = auth_info->namelen; + parts[count++].iov_base = auth_info->name; + parts[count].iov_len = out.authorization_protocol_data_len = auth_info->datalen; + parts[count++].iov_base = auth_info->data; + } + + pthread_mutex_lock(&c->iolock); + _xcb_out_write_block(c, parts, count); + ret = _xcb_out_flush(c); + pthread_mutex_unlock(&c->iolock); + if(ret <= 0) + return 0; + return 1; +} + +static int read_setup(XCBConnection *c) +{ + /* Read the server response */ + c->setup = malloc(sizeof(XCBConnSetupGenericRep)); + if(!c->setup) + return 0; + + if(_xcb_read_block(c->fd, c->setup, sizeof(XCBConnSetupGenericRep)) != sizeof(XCBConnSetupGenericRep)) + return 0; + + { + void *tmp = realloc(c->setup, c->setup->length * 4 + sizeof(XCBConnSetupGenericRep)); + if(!tmp) + return 0; + c->setup = tmp; + } + + if(_xcb_read_block(c->fd, (char *) c->setup + sizeof(XCBConnSetupGenericRep), c->setup->length * 4) <= 0) + return 0; + + /* 0 = failed, 2 = authenticate, 1 = success */ + switch(c->setup->status) + { + case 0: /* failed */ + { + XCBConnSetupFailedRep *setup = (XCBConnSetupFailedRep *) c->setup; + write(STDERR_FILENO, XCBConnSetupFailedRepReason(setup), XCBConnSetupFailedRepReasonLength(setup)); + return 0; + } + + case 2: /* authenticate */ + { + XCBConnSetupAuthenticateRep *setup = (XCBConnSetupAuthenticateRep *) c->setup; + write(STDERR_FILENO, XCBConnSetupAuthenticateRepReason(setup), XCBConnSetupAuthenticateRepReasonLength(setup)); + return 0; + } + } + + return 1; +} + +/* Public interface */ + +XCBConnSetupSuccessRep *XCBGetSetup(XCBConnection *c) +{ + /* doesn't need locking because it's never written to. */ + return c->setup; +} + +int XCBGetFileDescriptor(XCBConnection *c) +{ + /* doesn't need locking because it's never written to. */ + return c->fd; +} + +XCBConnection *XCBConnectToFD(int fd, XCBAuthInfo *auth_info) +{ + XCBConnection* c; + + c = calloc(1, sizeof(XCBConnection)); + if(!c) + return 0; + + c->fd = fd; + + if(!( + _xcb_set_fd_flags(fd) && + pthread_mutex_init(&c->iolock, 0) == 0 && + _xcb_in_init(&c->in) && + _xcb_out_init(&c->out) && + write_setup(c, auth_info) && + read_setup(c) && + _xcb_ext_init(c) && + _xcb_xid_init(c) + )) + { + XCBDisconnect(c); + return 0; + } + + return c; +} + +void XCBDisconnect(XCBConnection *c) +{ + if(!c) + return; + + free(c->setup); + close(c->fd); + + pthread_mutex_destroy(&c->iolock); + _xcb_in_destroy(&c->in); + _xcb_out_destroy(&c->out); + + _xcb_ext_destroy(c); + _xcb_xid_destroy(c); + + free(c); +} + +/* Private interface */ + +int _xcb_conn_wait(XCBConnection *c, const int should_write, pthread_cond_t *cond) +{ + int ret = 1; + fd_set rfds, wfds; +#if USE_THREAD_ASSERT + static __thread int already_here = 0; + + assert(!already_here); + ++already_here; +#endif + + _xcb_assert_valid_sequence(c); + + /* If the thing I should be doing is already being done, wait for it. */ + if(should_write ? c->out.writing : c->in.reading) + { + pthread_cond_wait(cond, &c->iolock); +#if USE_THREAD_ASSERT + --already_here; +#endif + return 1; + } + + FD_ZERO(&rfds); + FD_SET(c->fd, &rfds); + ++c->in.reading; + + FD_ZERO(&wfds); + if(should_write) + { + FD_SET(c->fd, &wfds); + ++c->out.writing; + } + + pthread_mutex_unlock(&c->iolock); + ret = select(c->fd + 1, &rfds, &wfds, 0, 0); + pthread_mutex_lock(&c->iolock); + + if(ret <= 0) /* error: select failed */ + goto done; + + if(FD_ISSET(c->fd, &rfds)) + if((ret = _xcb_in_read(c)) <= 0) + goto done; + + if(FD_ISSET(c->fd, &wfds)) + if((ret = _xcb_out_write(c)) <= 0) + goto done; + +done: + if(should_write) + --c->out.writing; + --c->in.reading; + +#if USE_THREAD_ASSERT + --already_here; +#endif + return ret; +} diff --git a/src/xcb_ext.c b/src/xcb_ext.c new file mode 100644 index 0000000..46a5519 --- /dev/null +++ b/src/xcb_ext.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* A cache for QueryExtension results. */ + +#include <stdlib.h> +#include <string.h> + +#include "xcb.h" +#include "xcbext.h" +#include "xcbint.h" + +typedef struct { + enum { LAZY_COOKIE, LAZY_FORCED } tag; + union { + XCBQueryExtensionCookie cookie; + XCBQueryExtensionRep *reply; + } value; +} lazyreply; + +static lazyreply *get_lazyreply(XCBConnection *c, XCBExtension *ext) +{ + static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; + static int next_global_id; + + lazyreply *data; + + pthread_mutex_lock(&global_lock); + if(!ext->global_id) + ext->global_id = ++next_global_id; + pthread_mutex_unlock(&global_lock); + + data = _xcb_map_get(c->ext.extensions, ext->global_id); + if(!data) + { + /* cache miss: query the server */ + data = malloc(sizeof(lazyreply)); + if(!data) + return 0; + data->tag = LAZY_COOKIE; + data->value.cookie = XCBQueryExtension(c, strlen(ext->name), ext->name); + _xcb_map_put(c->ext.extensions, ext->global_id, data); + } + return data; +} + +static void free_lazyreply(void *p) +{ + lazyreply *data = p; + if(data->tag == LAZY_FORCED) + free(data->value.reply); + free(data); +} + +/* Public interface */ + +/* Do not free the returned XCBQueryExtensionRep - on return, it's aliased + * from the cache. */ +const XCBQueryExtensionRep *XCBGetExtensionData(XCBConnection *c, XCBExtension *ext) +{ + lazyreply *data; + + pthread_mutex_lock(&c->ext.lock); + data = get_lazyreply(c, ext); + if(data && data->tag == LAZY_COOKIE) + { + data->tag = LAZY_FORCED; + data->value.reply = XCBQueryExtensionReply(c, data->value.cookie, 0); + } + pthread_mutex_unlock(&c->ext.lock); + + return data ? data->value.reply : 0; +} + +void XCBPrefetchExtensionData(XCBConnection *c, XCBExtension *ext) +{ + pthread_mutex_lock(&c->ext.lock); + get_lazyreply(c, ext); + pthread_mutex_unlock(&c->ext.lock); +} + +/* Private interface */ + +int _xcb_ext_init(XCBConnection *c) +{ + if(pthread_mutex_init(&c->ext.lock, 0)) + return 0; + + c->ext.extensions = _xcb_map_new(); + if(!c->ext.extensions) + return 0; + + return 1; +} + +void _xcb_ext_destroy(XCBConnection *c) +{ + pthread_mutex_destroy(&c->ext.lock); + _xcb_map_delete(c->ext.extensions, free_lazyreply); +} diff --git a/src/xcb_in.c b/src/xcb_in.c new file mode 100644 index 0000000..c260b7b --- /dev/null +++ b/src/xcb_in.c @@ -0,0 +1,319 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Stuff that reads stuff from the server. */ + +#include <assert.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +#include "xcb.h" +#include "xcbext.h" +#include "xcbint.h" + +typedef struct XCBReplyData { + unsigned int request; + void *data; + XCBGenericError **error; +} XCBReplyData; + +static int match_request_error(const void *request, const void *data) +{ + const XCBGenericError *e = data; + return e->response_type == 0 && e->sequence == ((*(unsigned int *) request) & 0xffff); +} + +static int match_reply(const void *request, const void *data) +{ + return ((XCBReplyData *) data)->request == *(unsigned int *) request; +} + +static void wake_up_next_reader(XCBConnection *c) +{ + XCBReplyData *cur = _xcb_list_peek_head(c->in.readers); + int pthreadret; + if(cur) + pthreadret = pthread_cond_signal(cur->data); + else + pthreadret = pthread_cond_signal(&c->in.event_cond); + assert(pthreadret == 0); +} + +/* Public interface */ + +void *XCBWaitForReply(XCBConnection *c, unsigned int request, XCBGenericError **e) +{ + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + XCBReplyData reader; + void *ret = 0; + if(e) + *e = 0; + + pthread_mutex_lock(&c->iolock); + + /* If this request has not been written yet, write it. */ + if((signed int) (c->out.request_written - request) < 0) + if(_xcb_out_flush(c) <= 0) + goto done; /* error */ + + if(_xcb_list_find(c->in.readers, match_reply, &request)) + goto done; /* error */ + + if(e) + { + *e = _xcb_list_remove(c->in.events, match_request_error, &request); + if(*e) + goto done; + } + + reader.request = request; + reader.data = &cond; + reader.error = e; + _xcb_list_append(c->in.readers, &reader); + + /* If this request has not been read yet, wait for it. */ + while(!(e && *e) && ((signed int) (c->in.request_read - request) < 0 || + (c->in.request_read == request && + _xcb_queue_is_empty(c->in.current_reply)))) + if(_xcb_conn_wait(c, /*should_write*/ 0, &cond) <= 0) + goto done; + + if(c->in.request_read != request) + { + _xcb_queue *q = _xcb_map_get(c->in.replies, request); + if(q) + { + ret = _xcb_queue_dequeue(q); + if(_xcb_queue_is_empty(q)) + _xcb_queue_delete(_xcb_map_remove(c->in.replies, request), free); + } + } + else + ret = _xcb_queue_dequeue(c->in.current_reply); + +done: + _xcb_list_remove(c->in.readers, match_reply, &request); + pthread_cond_destroy(&cond); + + wake_up_next_reader(c); + pthread_mutex_unlock(&c->iolock); + return ret; +} + +XCBGenericEvent *XCBWaitEvent(XCBConnection *c) +{ + return XCBWaitForEvent(c); +} + +XCBGenericEvent *XCBWaitForEvent(XCBConnection *c) +{ + XCBGenericEvent *ret; + +#if XCBTRACEEVENT + fprintf(stderr, "Entering XCBWaitEvent\n"); +#endif + + pthread_mutex_lock(&c->iolock); + /* _xcb_list_remove_head returns 0 on empty list. */ + while(!(ret = _xcb_queue_dequeue(c->in.events))) + if(_xcb_conn_wait(c, /*should_write*/ 0, &c->in.event_cond) <= 0) + break; + + wake_up_next_reader(c); + pthread_mutex_unlock(&c->iolock); + +#if XCBTRACEEVENT + fprintf(stderr, "Leaving XCBWaitEvent, event type %d\n", ret ? ret->response_type : -1); +#endif + + return ret; +} + +XCBGenericEvent *XCBPollForEvent(XCBConnection *c, int *error) +{ + XCBGenericEvent *ret = 0; + pthread_mutex_lock(&c->iolock); + if(error) + *error = 0; + /* FIXME: follow X meets Z architecture changes. */ + if(_xcb_in_read(c) >= 0) + ret = _xcb_queue_dequeue(c->in.events); + else if(error) + *error = -1; + else + { + fprintf(stderr, "XCBPollForEvent: I/O error occured, but no handler provided.\n"); + abort(); + } + pthread_mutex_unlock(&c->iolock); + return ret; +} + +unsigned int XCBGetRequestRead(XCBConnection *c) +{ + unsigned int ret; + pthread_mutex_lock(&c->iolock); + /* FIXME: follow X meets Z architecture changes. */ + _xcb_in_read(c); + ret = c->in.request_read; + pthread_mutex_unlock(&c->iolock); + return ret; +} + +/* Private interface */ + +int _xcb_in_init(_xcb_in *in) +{ + if(pthread_cond_init(&in->event_cond, 0)) + return 0; + in->reading = 0; + + in->queue_len = 0; + + in->request_read = 0; + in->current_reply = _xcb_queue_new(); + + in->replies = _xcb_map_new(); + in->events = _xcb_queue_new(); + in->readers = _xcb_list_new(); + if(!in->current_reply || !in->replies || !in->events || !in->readers) + return 0; + + return 1; +} + +void _xcb_in_destroy(_xcb_in *in) +{ + pthread_cond_destroy(&in->event_cond); + _xcb_queue_delete(in->current_reply, free); + _xcb_map_delete(in->replies, free); + _xcb_queue_delete(in->events, free); + _xcb_list_delete(in->readers, 0); +} + +int _xcb_in_expect_reply(XCBConnection *c, unsigned int request) +{ + /* XXX: currently a no-op */ + return 1; +} + +int _xcb_in_read_packet(XCBConnection *c) +{ + XCBGenericRep genrep; + int length = 32; + unsigned char *buf; + + /* Wait for there to be enough data for us to read a whole packet */ + if(c->in.queue_len < length) + return 0; + + /* Get the response type, length, and sequence number. */ + memcpy(&genrep, c->in.queue, sizeof(genrep)); + + /* For reply packets, check that the entire packet is available. */ + if(genrep.response_type == 1) + length += genrep.length * 4; + + buf = malloc(length); + if(!buf) + return 0; + if(_xcb_in_read_block(c, buf, length) <= 0) + { + free(buf); + return 0; + } + + /* Compute 32-bit sequence number of this packet. */ + /* XXX: do "sequence lost" check here */ + if((genrep.response_type & 0x7f) != KeymapNotify) + { + int lastread = c->in.request_read; + c->in.request_read = (lastread & 0xffff0000) | genrep.sequence; + if(c->in.request_read != lastread && !_xcb_queue_is_empty(c->in.current_reply)) + { + _xcb_map_put(c->in.replies, lastread, c->in.current_reply); + c->in.current_reply = _xcb_queue_new(); + } + if(c->in.request_read < lastread) + c->in.request_read += 0x10000; + } + + if(buf[0] == 1) /* response is a reply */ + { + XCBReplyData *reader = _xcb_list_find(c->in.readers, match_reply, &c->in.request_read); + _xcb_queue_enqueue(c->in.current_reply, buf); + if(reader) + pthread_cond_signal(reader->data); + return 1; + } + + if(buf[0] == 0) /* response is an error */ + { + XCBReplyData *reader = _xcb_list_find(c->in.readers, match_reply, &c->in.request_read); + if(reader && reader->error) + { + *reader->error = (XCBGenericError *) buf; + pthread_cond_signal(reader->data); + return 1; + } + } + + /* event, or error without a waiting reader */ + _xcb_queue_enqueue(c->in.events, buf); + pthread_cond_signal(&c->in.event_cond); + return 1; /* I have something for you... */ +} + +int _xcb_in_read(XCBConnection *c) +{ + int n = _xcb_readn(c->fd, c->in.queue, sizeof(c->in.queue), &c->in.queue_len); + if(n < 0 && errno == EAGAIN) + n = 1; + while(_xcb_in_read_packet(c) > 0) + /* empty */; + return n; +} + +int _xcb_in_read_block(XCBConnection *c, void *buf, int len) +{ + int done = c->in.queue_len; + if(len < done) + done = len; + + memcpy(buf, c->in.queue, done); + c->in.queue_len -= done; + memmove(c->in.queue, c->in.queue + done, c->in.queue_len); + + if(len > done) + { + int ret = _xcb_read_block(c->fd, (char *) buf + done, len - done); + if(ret <= 0) + return ret; + } + + return len; +} diff --git a/src/xcb_list.c b/src/xcb_list.c new file mode 100644 index 0000000..5b2edc0 --- /dev/null +++ b/src/xcb_list.c @@ -0,0 +1,215 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* A generic implementation of a list of void-pointers. */ + +#include <stdlib.h> + +#include "xcb.h" +#include "xcbint.h" + +typedef struct node { + struct node *next; + void *data; +} node; + +struct _xcb_list { + node *head; + node **tail; +}; + +/* Private interface */ + +_xcb_list *_xcb_list_new() +{ + _xcb_list *list; + list = malloc(sizeof(_xcb_list)); + if(!list) + return 0; + list->head = 0; + list->tail = &list->head; + return list; +} + +static void _xcb_list_clear(_xcb_list *list, XCBListFreeFunc do_free) +{ + void *tmp; + while((tmp = _xcb_list_remove_head(list))) + if(do_free) + do_free(tmp); +} + +void _xcb_list_delete(_xcb_list *list, XCBListFreeFunc do_free) +{ + if(!list) + return; + _xcb_list_clear(list, do_free); + free(list); +} + +int _xcb_list_insert(_xcb_list *list, void *data) +{ + node *cur; + cur = malloc(sizeof(node)); + if(!cur) + return 0; + cur->data = data; + + cur->next = list->head; + list->head = cur; + return 1; +} + +int _xcb_list_append(_xcb_list *list, void *data) +{ + node *cur; + cur = malloc(sizeof(node)); + if(!cur) + return 0; + cur->data = data; + cur->next = 0; + + *list->tail = cur; + list->tail = &cur->next; + return 1; +} + +void *_xcb_list_peek_head(_xcb_list *list) +{ + if(!list->head) + return 0; + return list->head->data; +} + +void *_xcb_list_remove_head(_xcb_list *list) +{ + void *ret; + node *tmp = list->head; + if(!tmp) + return 0; + ret = tmp->data; + list->head = tmp->next; + if(!list->head) + list->tail = &list->head; + free(tmp); + return ret; +} + +void *_xcb_list_remove(_xcb_list *list, int (*cmp)(const void *, const void *), const void *data) +{ + node **cur; + for(cur = &list->head; *cur; cur = &(*cur)->next) + if(cmp(data, (*cur)->data)) + { + node *tmp = *cur; + void *ret = (*cur)->data; + *cur = (*cur)->next; + if(!*cur) + list->tail = cur; + + free(tmp); + return ret; + } + return 0; +} + +void *_xcb_list_find(_xcb_list *list, int (*cmp)(const void *, const void *), const void *data) +{ + node *cur; + for(cur = list->head; cur; cur = cur->next) + if(cmp(data, cur->data)) + return cur->data; + return 0; +} + +_xcb_queue *_xcb_queue_new(void) __attribute__ ((alias ("_xcb_list_new"))); +void _xcb_queue_delete(_xcb_queue *q, XCBListFreeFunc do_free) __attribute__ ((alias ("_xcb_list_delete"))); +int _xcb_queue_enqueue(_xcb_queue *q, void *data) __attribute__ ((alias ("_xcb_list_append"))); +void *_xcb_queue_dequeue(_xcb_queue *q) __attribute__ ((alias ("_xcb_list_remove_head"))); + +int _xcb_queue_is_empty(_xcb_queue *q) +{ + return q->head == 0; +} + +typedef struct { + unsigned int key; + void *value; +} map_pair; + +_xcb_map *_xcb_map_new(void) __attribute__ ((alias ("_xcb_list_new"))); + +void _xcb_map_delete(_xcb_map *q, XCBListFreeFunc do_free) +{ + map_pair *tmp; + if(!q) + return; + while((tmp = _xcb_list_remove_head(q))) + { + if(do_free) + do_free(tmp->value); + free(tmp); + } + free(q); +} + +int _xcb_map_put(_xcb_map *q, unsigned int key, void *data) +{ + map_pair *cur = malloc(sizeof(map_pair)); + if(!cur) + return 0; + cur->key = key; + cur->value = data; + if(!_xcb_list_append(q, cur)) + { + free(cur); + return 0; + } + return 1; +} + +static int match_map_pair(const void *key, const void *pair) +{ + return ((map_pair *) pair)->key == *(unsigned int *) key; +} + +void *_xcb_map_get(_xcb_map *q, unsigned int key) +{ + map_pair *cur = _xcb_list_find(q, match_map_pair, &key); + if(!cur) + return 0; + return cur->value; +} + +void *_xcb_map_remove(_xcb_map *q, unsigned int key) +{ + map_pair *cur = _xcb_list_remove(q, match_map_pair, &key); + void *ret; + if(!cur) + return 0; + ret = cur->value; + free(cur); + return ret; +} diff --git a/src/xcb_out.c b/src/xcb_out.c new file mode 100644 index 0000000..b3a556a --- /dev/null +++ b/src/xcb_out.c @@ -0,0 +1,272 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Stuff that sends stuff to the server. */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "xcb.h" +#include "xcbext.h" +#include "xcbint.h" +#include "extensions/bigreq.h" + +static int force_sequence_wrap(XCBConnection *c) +{ + int ret = 1; + if((c->out.request - c->in.request_read) > 65530) + { + pthread_mutex_unlock(&c->iolock); + ret = XCBSync(c, 0); + pthread_mutex_lock(&c->iolock); + } + return ret; +} + +/* Public interface */ + +CARD32 XCBGetMaximumRequestLength(XCBConnection *c) +{ + pthread_mutex_lock(&c->out.reqlenlock); + if(!c->out.maximum_request_length) + { + const XCBQueryExtensionRep *ext; + c->out.maximum_request_length = c->setup->maximum_request_length; + ext = XCBGetExtensionData(c, &XCBBigRequestsId); + if(ext && ext->present) + { + XCBBigRequestsEnableRep *r = XCBBigRequestsEnableReply(c, XCBBigRequestsEnable(c), 0); + c->out.maximum_request_length = r->maximum_request_length; + free(r); + } + } + pthread_mutex_unlock(&c->out.reqlenlock); + return c->out.maximum_request_length; +} + +int XCBSendRequest(XCBConnection *c, unsigned int *request, struct iovec *vector, const XCBProtocolRequest *req) +{ + int ret; + int i; + struct iovec prefix[2]; + CARD16 shortlen = 0; + CARD32 longlen = 0; + + assert(c != 0); + assert(request != 0); + assert(vector != 0); + assert(req->count > 0); + + /* put together the length field, possibly using BIGREQUESTS */ + for(i = 0; i < req->count; ++i) + longlen += XCB_CEIL(vector[i].iov_len) >> 2; + + if(longlen > c->setup->maximum_request_length) + { + if(longlen > XCBGetMaximumRequestLength(c)) + return 0; /* server can't take this; maybe need BIGREQUESTS? */ + } + else + { + /* we don't need BIGREQUESTS. */ + shortlen = longlen; + longlen = 0; + } + + /* set the length field. */ + i = 0; + prefix[i].iov_base = vector[0].iov_base; + prefix[i].iov_len = sizeof(CARD32); + vector[0].iov_base = ((char *) vector[0].iov_base) + sizeof(CARD32); + vector[0].iov_len -= sizeof(CARD32); + ((CARD16 *) prefix[i].iov_base)[1] = shortlen; + ++i; + if(!shortlen) + { + ++longlen; + prefix[i].iov_base = &longlen; + prefix[i].iov_len = sizeof(CARD32); + ++i; + } + + /* set the major opcode, and the minor opcode for extensions */ + if(req->ext) + { + const XCBQueryExtensionRep *extension = XCBGetExtensionData(c, req->ext); + /* TODO: better error handling here, please! */ + assert(extension && extension->present); + ((CARD8 *) prefix[0].iov_base)[0] = extension->major_opcode; + ((CARD8 *) prefix[0].iov_base)[1] = req->opcode; + } + else + ((CARD8 *) prefix[0].iov_base)[0] = req->opcode; + + /* get a sequence number and arrange for delivery. */ + pthread_mutex_lock(&c->iolock); + if(req->isvoid && !force_sequence_wrap(c)) + { + pthread_mutex_unlock(&c->iolock); + return -1; + } + + *request = ++c->out.request; + + if(!req->isvoid) + _xcb_in_expect_reply(c, *request); + + ret = _xcb_out_write_block(c, prefix, i); + if(ret > 0) + ret = _xcb_out_write_block(c, vector, req->count); + pthread_mutex_unlock(&c->iolock); + + return ret; +} + +int XCBFlush(XCBConnection *c) +{ + int ret; + pthread_mutex_lock(&c->iolock); + ret = _xcb_out_flush(c); + pthread_mutex_unlock(&c->iolock); + return ret; +} + +/* Private interface */ + +int _xcb_out_init(_xcb_out *out) +{ + if(pthread_cond_init(&out->cond, 0)) + return 0; + out->writing = 0; + + out->queue_len = 0; + out->vec = 0; + out->vec_len = 0; + + out->last_request = 0; + out->request = 0; + out->request_written = 0; + + if(pthread_mutex_init(&out->reqlenlock, 0)) + return 0; + out->maximum_request_length = 0; + + return 1; +} + +void _xcb_out_destroy(_xcb_out *out) +{ + pthread_cond_destroy(&out->cond); + pthread_mutex_destroy(&out->reqlenlock); + free(out->vec); +} + +int _xcb_out_write(XCBConnection *c) +{ + int n; + if(c->out.vec_len) + n = _xcb_writev(c->fd, c->out.vec, c->out.vec_len); + else + n = _xcb_write(c->fd, &c->out.queue, &c->out.queue_len); + + if(n < 0 && errno == EAGAIN) + n = 1; + + if(c->out.vec_len) + { + int i; + for(i = 0; i < c->out.vec_len; ++i) + if(c->out.vec[i].iov_len) + return n; + c->out.vec_len = 0; + } + return n; +} + +int _xcb_out_write_block(XCBConnection *c, struct iovec *vector, size_t count) +{ + static const char pad[3]; + int i; + int len = 0; + + for(i = 0; i < count; ++i) + len += XCB_CEIL(vector[i].iov_len); + + /* Is the queue about to overflow? */ + if(c->out.queue_len + len < sizeof(c->out.queue)) + { + /* No, this will fit. */ + for(i = 0; i < count; ++i) + { + memcpy(c->out.queue + c->out.queue_len, vector[i].iov_base, vector[i].iov_len); + if(vector[i].iov_len & 3) + memset(c->out.queue + c->out.queue_len + vector[i].iov_len, 0, XCB_PAD(vector[i].iov_len)); + c->out.queue_len += XCB_CEIL(vector[i].iov_len); + } + return len; + } + + assert(!c->out.vec_len); + assert(!c->out.vec); + c->out.vec = malloc(sizeof(struct iovec) * (1 + count * 2)); + if(!c->out.vec) + return -1; + if(c->out.queue_len) + { + c->out.vec[c->out.vec_len].iov_base = c->out.queue; + c->out.vec[c->out.vec_len++].iov_len = c->out.queue_len; + c->out.queue_len = 0; + } + for(i = 0; i < count; ++i) + { + if(!vector[i].iov_len) + continue; + c->out.vec[c->out.vec_len].iov_base = vector[i].iov_base; + c->out.vec[c->out.vec_len++].iov_len = vector[i].iov_len; + if(!XCB_PAD(vector[i].iov_len)) + continue; + c->out.vec[c->out.vec_len].iov_base = (void *) pad; + c->out.vec[c->out.vec_len++].iov_len = XCB_PAD(vector[i].iov_len); + } + if(_xcb_out_flush(c) <= 0) + len = -1; + free(c->out.vec); + c->out.vec = 0; + + return len; +} + +int _xcb_out_flush(XCBConnection *c) +{ + int ret = 1; + while(ret > 0 && (c->out.queue_len || c->out.vec_len)) + ret = _xcb_conn_wait(c, /*should_write*/ 1, &c->out.cond); + c->out.last_request = 0; + c->out.request_written = c->out.request; + pthread_cond_broadcast(&c->out.cond); + return ret; +} diff --git a/src/xcb_util.c b/src/xcb_util.c new file mode 100644 index 0000000..b25a2d8 --- /dev/null +++ b/src/xcb_util.c @@ -0,0 +1,279 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* Utility functions implementable using only public APIs. */ + +#include <assert.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/fcntl.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "xcb.h" +#include "xcbext.h" + +int XCBPopcount(CARD32 mask) +{ + unsigned long y; + y = (mask >> 1) & 033333333333; + y = mask - y - ((y >> 1) & 033333333333); + return ((y + (y >> 3)) & 030707070707) % 077; +} + +int XCBParseDisplay(const char *name, char **host, int *displayp, int *screenp) +{ + int len, display, screen; + char *colon, *dot, *end; + if(!name || !*name) + name = getenv("DISPLAY"); + if(!name) + return 0; + colon = strrchr(name, ':'); + if(!colon) + return 0; + len = colon - name; + ++colon; + display = strtoul(colon, &dot, 10); + if(dot == colon) + return 0; + if(*dot == '\0') + screen = 0; + else + { + if(*dot != '.') + return 0; + ++dot; + screen = strtoul(dot, &end, 10); + if(end == dot || *end != '\0') + return 0; + } + /* At this point, the display string is fully parsed and valid, but + * the caller's memory is untouched. */ + + *host = malloc(len + 1); + if(!*host) + return 0; + memcpy(*host, name, len); + (*host)[len] = '\0'; + *displayp = display; + if(screenp) + *screenp = screen; + return 1; +} + +int XCBOpen(const char *host, const int display) +{ + int fd; + + if(*host) + { + /* display specifies TCP */ + unsigned short port = X_TCP_PORT + display; + fd = XCBOpenTCP(host, port); + } + else + { + /* display specifies Unix socket */ + static const char base[] = "/tmp/.X11-unix/X"; + char file[sizeof(base) + 20]; + snprintf(file, sizeof(file), "%s%d", base, display); + fd = XCBOpenUnix(file); + } + + return fd; +} + +int XCBOpenTCP(const char *host, const unsigned short port) +{ + int fd; + struct sockaddr_in addr; + struct hostent *hostaddr = gethostbyname(host); + if(!hostaddr) + return -1; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + memcpy(&addr.sin_addr, hostaddr->h_addr_list[0], sizeof(addr.sin_addr)); + + fd = socket(PF_INET, SOCK_STREAM, 0); + if(fd == -1) + return -1; + if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) + return -1; + return fd; +} + +int XCBOpenUnix(const char *file) +{ + int fd; + struct sockaddr_un addr = { AF_UNIX }; + strcpy(addr.sun_path, file); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(fd == -1) + return -1; + if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) + return -1; + return fd; +} + +XCBConnection *XCBConnect(const char *displayname, int *screenp) +{ + int fd, display = 0; + char *host; + XCBConnection *c; + XCBAuthInfo auth; + + if(!XCBParseDisplay(displayname, &host, &display, screenp)) + return 0; + fd = XCBOpen(host, display); + free(host); + if(fd == -1) + return 0; + + XCBGetAuthInfo(fd, &auth); + c = XCBConnectToFD(fd, &auth); + free(auth.name); + free(auth.data); + return c; +} + +XCBConnection *XCBConnectToDisplayWithAuthInfo(const char *displayname, XCBAuthInfo *auth, int *screenp) +{ + int fd, display = 0; + char *host; + + if(!XCBParseDisplay(displayname, &host, &display, screenp)) + return 0; + fd = XCBOpen(host, display); + free(host); + if(fd == -1) + return 0; + + return XCBConnectToFD(fd, auth); +} + +/* backwards compatible interface: remove before 1.0 release */ +XCBConnection *XCBConnectBasic() +{ + XCBConnection *c = XCBConnect(0, 0); + if(c) + return c; + perror("XCBConnect"); + abort(); +} + +int XCBSync(XCBConnection *c, XCBGenericError **e) +{ + XCBGetInputFocusRep *reply = XCBGetInputFocusReply(c, XCBGetInputFocus(c), e); + free(reply); + return reply != 0; +} + +/* The functions beyond this point still use only public interfaces, + * but are not themselves part of the public interface. So their + * prototypes are in xcbint.h. */ + +#include "xcbint.h" + +int _xcb_set_fd_flags(const int fd) +{ + long flags = fcntl(fd, F_GETFL, 0); + if(flags == -1) + return 0; + flags |= O_NONBLOCK; + if(fcntl(fd, F_SETFL, flags) == -1) + return 0; + if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + return 0; + return 1; +} + +int _xcb_readn(const int fd, void *buf, const int buflen, int *count) +{ + int n = read(fd, ((char *) buf) + *count, buflen - *count); + if(n > 0) + *count += n; + return n; +} + +int _xcb_read_block(const int fd, void *buf, const size_t len) +{ + int done = 0; + while(done < len) + { + int ret = _xcb_readn(fd, buf, len, &done); + if(ret < 0 && errno == EAGAIN) + { + fd_set fds; + FD_ZERO(&fds); + FD_SET(fd, &fds); + ret = select(fd + 1, &fds, 0, 0, 0); + } + if(ret <= 0) + return ret; + } + return len; +} + +int _xcb_write(const int fd, char (*buf)[], int *count) +{ + int n = write(fd, *buf, *count); + if(n > 0) + { + *count -= n; + if(*count) + memmove(*buf, *buf + n, *count); + } + return n; +} + +int _xcb_writev(const int fd, struct iovec *vec, int count) +{ + int n = writev(fd, vec, count); + if(n > 0) + { + int rem = n; + for(; count; --count, ++vec) + { + int cur = vec->iov_len; + if(cur > rem) + cur = rem; + vec->iov_len -= cur; + vec->iov_base = (char *) vec->iov_base + cur; + rem -= cur; + if(vec->iov_len) + break; + } + assert(rem == 0); + } + return n; +} diff --git a/src/xcb_xid.c b/src/xcb_xid.c new file mode 100644 index 0000000..7d7f784 --- /dev/null +++ b/src/xcb_xid.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +/* XID allocators. */ + +#include <stdlib.h> +#include "xcb.h" +#include "xcbext.h" +#include "xcbint.h" +#include "extensions/xc_misc.h" + +/* Public interface */ + +CARD32 XCBGenerateID(XCBConnection *c) +{ + CARD32 ret; + pthread_mutex_lock(&c->xid.lock); + if(c->xid.last == c->xid.max) + { + XCBXCMiscGetXIDRangeRep *range; + range = XCBXCMiscGetXIDRangeReply(c, XCBXCMiscGetXIDRange(c), 0); + c->xid.last = range->start_id; + c->xid.max = range->start_id + (range->count - 1) * c->xid.inc; + free(range); + } + ret = c->xid.last | c->xid.base; + c->xid.last += c->xid.inc; + pthread_mutex_unlock(&c->xid.lock); + return ret; +} + +/* Private interface */ + +int _xcb_xid_init(XCBConnection *c) +{ + if(pthread_mutex_init(&c->xid.lock, 0)) + return 0; + c->xid.last = 0; + c->xid.base = c->setup->resource_id_base; + c->xid.max = c->setup->resource_id_mask; + c->xid.inc = c->setup->resource_id_mask & -(c->setup->resource_id_mask); + return 1; +} + +void _xcb_xid_destroy(XCBConnection *c) +{ + pthread_mutex_destroy(&c->xid.lock); +} diff --git a/src/xcb_xlib.c b/src/xcb_xlib.c new file mode 100644 index 0000000..8cc6837 --- /dev/null +++ b/src/xcb_xlib.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2005 Bart Massey and Jamey Sharp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#include "xcbxlib.h" +#include "xcbint.h" + +unsigned int XCBGetRequestSent(XCBConnection *c) +{ + unsigned int ret; + pthread_mutex_lock(&c->iolock); + ret = c->out.request; + pthread_mutex_unlock(&c->iolock); + return ret; +} + +pthread_mutex_t *XCBGetIOLock(XCBConnection *c) +{ + return &c->iolock; +} diff --git a/src/xcbext.h b/src/xcbext.h new file mode 100644 index 0000000..c8f532c --- /dev/null +++ b/src/xcbext.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#ifndef __XCBEXT_H +#define __XCBEXT_H + +#include "xcb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* xcb_ext.c */ + +struct XCBExtension { + const char *name; + int global_id; +}; + + +/* xcb_out.c */ + +typedef struct { + size_t count; + XCBExtension *ext; + CARD8 opcode; + BOOL isvoid; +} XCBProtocolRequest; + +int XCBSendRequest(XCBConnection *c, unsigned int *sequence, struct iovec *vector, const XCBProtocolRequest *request); + + +/* xcb_in.c */ + +void *XCBWaitForReply(XCBConnection *c, unsigned int request, XCBGenericError **e); + + +/* xcb_xid.c */ + +CARD32 XCBGenerateID(XCBConnection *c); + + +/* xcb_util.c */ + +int XCBPopcount(CARD32 mask); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/xcbint.h b/src/xcbint.h new file mode 100644 index 0000000..057a315 --- /dev/null +++ b/src/xcbint.h @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#ifndef __XCBINT_H +#define __XCBINT_H + +/* Not simply (a <= b) because eventually the 32-bit sequence number + * will wrap, causing earlier sequence numbers to be higher than later + * ones for a brief but fatal period. (a and b must be unsigned.) */ +#define _xcb_assert_sequence_less(a,b) assert((b) - (a) < 65536) + +#define _xcb_assert_valid_sequence(c) do { \ + _xcb_assert_sequence_less((c)->in.request_read, (c)->out.request_written); \ + _xcb_assert_sequence_less((c)->out.request_written, (c)->out.request); \ +} while(0) + +/* xcb_list.c */ + +typedef struct _xcb_list _xcb_list; +typedef void (*XCBListFreeFunc)(void *); + +_xcb_list *_xcb_list_new(void); +void _xcb_list_delete(_xcb_list *list, XCBListFreeFunc do_free); +int _xcb_list_insert(_xcb_list *list, void *data); +int _xcb_list_append(_xcb_list *list, void *data); +void *_xcb_list_peek_head(_xcb_list *list); +void *_xcb_list_remove_head(_xcb_list *list); +void *_xcb_list_remove(_xcb_list *list, int (*cmp)(const void *, const void *), const void *data); +void *_xcb_list_find(_xcb_list *list, int (*cmp)(const void *, const void *), const void *data); + +typedef _xcb_list _xcb_queue; + +_xcb_queue *_xcb_queue_new(void); +void _xcb_queue_delete(_xcb_queue *q, XCBListFreeFunc do_free); +int _xcb_queue_enqueue(_xcb_queue *q, void *data); +void *_xcb_queue_dequeue(_xcb_queue *q); +int _xcb_queue_is_empty(_xcb_queue *q); + +typedef _xcb_list _xcb_map; + +_xcb_map *_xcb_map_new(void); +void _xcb_map_delete(_xcb_map *q, XCBListFreeFunc do_free); +int _xcb_map_put(_xcb_map *q, unsigned int key, void *data); +void *_xcb_map_get(_xcb_map *q, unsigned int key); +void *_xcb_map_remove(_xcb_map *q, unsigned int key); + + +/* xcb_util.c */ + +/* Index of nearest 4-byte boundary following E. */ +#define XCB_CEIL(E) (((E)+3)&~3) + +#define XCB_PAD(i) ((4 - (i & 3)) & 3) + +int _xcb_set_fd_flags(const int fd); +int _xcb_readn(const int fd, void *buf, const int buflen, int *count); +int _xcb_read_block(const int fd, void *buf, const size_t len); +int _xcb_write(const int fd, char (*buf)[], int *count); +int _xcb_writev(const int fd, struct iovec *vec, int count); + + +/* xcb_out.c */ + +typedef struct _xcb_out { + pthread_cond_t cond; + int writing; + + char queue[4096]; + int queue_len; + struct iovec *vec; + int vec_len; + + void *last_request; + unsigned int request; + unsigned int request_written; + + pthread_mutex_t reqlenlock; + CARD32 maximum_request_length; +} _xcb_out; + +int _xcb_out_init(_xcb_out *out); +void _xcb_out_destroy(_xcb_out *out); + +int _xcb_out_write(XCBConnection *c); +int _xcb_out_write_block(XCBConnection *c, struct iovec *vector, size_t count); +int _xcb_out_flush(XCBConnection *c); + + +/* xcb_in.c */ + +typedef struct _xcb_in { + pthread_cond_t event_cond; + int reading; + + char queue[4096]; + int queue_len; + + unsigned int request_read; + _xcb_queue *current_reply; + + _xcb_map *replies; + _xcb_queue *events; + _xcb_list *readers; +} _xcb_in; + +int _xcb_in_init(_xcb_in *in); +void _xcb_in_destroy(_xcb_in *in); + +int _xcb_in_expect_reply(XCBConnection *c, unsigned int request); + +int _xcb_in_read_packet(XCBConnection *c); +int _xcb_in_read(XCBConnection *c); +int _xcb_in_read_block(XCBConnection *c, void *buf, int nread); + + +/* xcb_xid.c */ + +typedef struct _xcb_xid { + pthread_mutex_t lock; + CARD32 last; + CARD32 base; + CARD32 max; + CARD32 inc; +} _xcb_xid; + +int _xcb_xid_init(XCBConnection *c); +void _xcb_xid_destroy(XCBConnection *c); + + +/* xcb_ext.c */ + +typedef struct _xcb_ext { + pthread_mutex_t lock; + _xcb_map *extensions; +} _xcb_ext; + +int _xcb_ext_init(XCBConnection *c); +void _xcb_ext_destroy(XCBConnection *c); + + +/* xcb_conn.c */ + +struct XCBConnection { + /* constant data */ + XCBConnSetupSuccessRep *setup; + int fd; + + /* I/O data */ + pthread_mutex_t iolock; + _xcb_in in; + _xcb_out out; + + /* misc data */ + _xcb_ext ext; + _xcb_xid xid; +}; + +int _xcb_conn_wait(XCBConnection *c, const int should_write, pthread_cond_t *cond); +#endif diff --git a/src/xcbxlib.h b/src/xcbxlib.h new file mode 100644 index 0000000..e9f7140 --- /dev/null +++ b/src/xcbxlib.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005 Bart Massey and Jamey Sharp. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +#ifndef __XCBXLIB_H +#define __XCBXLIB_H + +#include <pthread.h> +#include "xcb.h" + +unsigned int XCBGetRequestSent(XCBConnection *c); + +pthread_mutex_t *XCBGetIOLock(XCBConnection *c); + +#endif |