+ACLOCAL_AMFLAGS=-I m4
+
SUBDIRS=src tests doc
pkgconfigdir = $(libdir)/pkgconfig
if BUILD_DRI2
pkgconfig_DATA += xcb-dri2.pc
endif
+if BUILD_DRI3
+pkgconfig_DATA += xcb-dri3.pc
+endif
if BUILD_GLX
pkgconfig_DATA += xcb-glx.pc
endif
+if BUILD_PRESENT
+pkgconfig_DATA += xcb-present.pc
+endif
if BUILD_RANDR
pkgconfig_DATA += xcb-randr.pc
endif
if BUILD_XVMC
pkgconfig_DATA += xcb-xvmc.pc
endif
+if BUILD_HWA
+pkgconfig_DATA += xcb-hwa.pc
+endif
+if BUILD_HWC
+pkgconfig_DATA += xcb-hwc.pc
+endif
+
+
EXTRA_DIST = \
+Release 1.10 (2013-12-22)
+=========================
+* Bump libxcb-xkb SONAME due to ABI break introduced in 1.9.2
+* Enable libxcb-xkb by default
+* Bump libxcb-sync SONAME
+* c_client.py: Fix _sizeof() functions
+* c_client.py: Do not create pointers in unions
+* c_client.py: Always initialize xcb_align_to
+* Re-introduce xcb_ge_event_t (deprecated, xcb_ge_generic_event_t should be
+ used instead)
+* Fix alignment issues in FD passing code
+* Fix poll() if POLLIN == ROLLRDNORM|POLLRDBAND
+* Use /usr/spool/sockets/X11/ on HP-UX for UNIX sockets
+* Make xsltproc optional
+
+Release 1.9.3 (2013-11-07)
+==========================
+* Check if we need to define _XOPEN_SOURCE for struct msghdr.msg_control
+* Add configure option to enable or disable fd passing with sendmsg
+* Switch to using the CMSG_* macros for FD passing
+* Initialize automake earlier (bugfix for #66413)
+
+Release 1.9.2 (2013-11-07)
+==========================
+* Add Present extension
+* Add DRI3 library
+* Add event queue splitting
+* Add support for receiving fds in replies
+* Add xcb_send_fd API
+* Remove xcb_ge_event_t from xcb.h
+* c_client.py: Inject full_sequence into GE events
+* c_client.py: Handle multiple expr. in a bitcase
+
+Release 1.9.1 (2013-05-30)
+==========================
+* Fix python code to work with python-3
+* Security fix for integer overflow in read_packet() [CVE-2013-2064]
+
+Release 1.9 (2012-10-05)
+========================
+* Always include "config.h" at the start of all C source files.
+* Add AC_USE_SYSTEM_EXTENSIONS to allow use of more system functionality
+* Return connection failure if display string specifies non-existent screen
+* c_client: Fix parallel-make issue creating 'man' directory
+* xcb_connect: launchd: Don't fall back on tcp if $DISPLAY is a path to a launchd socket
+* c_client.py: generate manpages
+* Allow xcb_send_request with >MAX_IOV iovecs
+* Add a .gitignore for src/man/
+* Fix a multi-thread deadlock
+
Release 1.8.1 (2012-03-09)
==========================
- Fix a busy loop on BSD and Mac OS
autoreconf -v --install || exit 1
cd $ORIGDIR || exit $?
-$srcdir/configure --enable-maintainer-mode "$@"
+if test -z "$NOCONFIGURE"; then
+ $srcdir/configure "$@"
+fi
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
-AC_PREREQ(2.57)
+# Initialize Autoconf
+AC_PREREQ([2.60])
AC_INIT([libxcb],
- 1.8.1,
+ 1.10,
[xcb@lists.freedesktop.org])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([xcb.pc.in])
+
+# Initialize Automake
AM_INIT_AUTOMAKE([foreign dist-bzip2])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+# Set common system defines for POSIX extensions, such as _GNU_SOURCE
+# Must be called before any macros that run the compiler (like AC_PROG_LIBTOOL)
+# to avoid autoconf errors.
+AC_USE_SYSTEM_EXTENSIONS
+
AM_PATH_PYTHON([2.6])
PKG_CHECK_MODULES(CHECK, [check >= 0.9.4], [HAVE_CHECK=yes], [HAVE_CHECK=no])
AC_PROG_LIBTOOL
AC_PROG_CC
-AC_PATH_PROG(XSLTPROC, xsltproc, no)
-if test "$XSLTPROC" = "no"; then
- AC_MSG_ERROR([XCB requires xsltproc.])
-fi
-
-HTML_CHECK_RESULT=false
+XSLTPROC=no
+HTML_CHECK_RESULT=no
if test x"$HAVE_CHECK" = xyes; then
+ AC_PATH_PROG(XSLTPROC, xsltproc, no)
if test x"$XSLTPROC" != xno; then
- HTML_CHECK_RESULT=true
+ HTML_CHECK_RESULT=yes
fi
fi
AC_SUBST(HTML_CHECK_RESULT)
# Checks for pkg-config packages
-PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.7)
+PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.10)
NEEDED="pthread-stubs xau >= 0.99.2"
PKG_CHECK_MODULES(NEEDED, $NEEDED)
AC_SEARCH_LIBS(getaddrinfo, socket)
AC_SEARCH_LIBS(connect, socket)
+AC_ARG_ENABLE(sendfds, AS_HELP_STRING([--disable-sendfds], [Support FD passing (default: auto)]),
+ [sendfds=$enableval], [sendfds=auto])
+
+case x$sendfds in
+xauto)
+ AC_SEARCH_LIBS(sendmsg, socket, [sendfds="yes"], [sendfds="no"])
+ ;;
+esac
+
+# XPG4v2/UNIX95 added msg_control - check to see if we need to define
+# _XOPEN_SOURCE to get it (such as on Solaris)
+AC_CHECK_MEMBER([struct msghdr.msg_control], [], [],
+ [
+AC_INCLUDES_DEFAULT
+#include <sys/socket.h>
+ ])
+# First try for Solaris in C99 compliant mode, which requires XPG6/UNIX03
+if test "x$ac_cv_member_struct_msghdr_msg_control" = xno; then
+ unset ac_cv_member_struct_msghdr_msg_control
+ AC_MSG_NOTICE([trying again with _XOPEN_SOURCE=600])
+ AC_CHECK_MEMBER([struct msghdr.msg_control],
+ [AC_DEFINE([_XOPEN_SOURCE], [600],
+ [Defined if needed to expose struct msghdr.msg_control])
+ ], [], [
+#define _XOPEN_SOURCE 600
+AC_INCLUDES_DEFAULT
+#include <sys/socket.h>
+ ])
+fi
+# If that didn't work, fall back to XPG5/UNIX98 with C89
+if test "x$ac_cv_member_struct_msghdr_msg_control" = xno; then
+ unset ac_cv_member_struct_msghdr_msg_control
+ AC_MSG_NOTICE([trying again with _XOPEN_SOURCE=500])
+ AC_CHECK_MEMBER([struct msghdr.msg_control],
+ [AC_DEFINE([_XOPEN_SOURCE], [500],
+ [Defined if needed to expose struct msghdr.msg_control])
+ ], [sendfds="no"], [
+#define _XOPEN_SOURCE 500
+AC_INCLUDES_DEFAULT
+#include <sys/socket.h>
+ ])
+fi
+
+case x$sendfds in
+xyes)
+ AC_DEFINE([HAVE_SENDMSG],1,[Define if your platform supports sendmsg])
+ ;;
+esac
+
have_win32="no"
lt_enable_auto_import=""
case $host_os in
AC_CHECK_HEADERS([tsol/label.h])
AC_CHECK_FUNCS([is_system_labeled])
+dnl check for IOV_MAX, and fall back to UIO_MAXIOV on BSDish systems
+AC_CHECK_DECL([IOV_MAX], [],
+ [AC_CHECK_DECL([UIO_MAXIOV], [AC_DEFINE([IOV_MAX], [UIO_MAXIOV])],
+ [AC_DEFINE([IOV_MAX], [16], [Define if not provided by <limits.h>])],
+ [[#include <sys/uio.h>]])],
+ [[#include <limits.h>]])
+
xcbincludedir='${includedir}/xcb'
AC_SUBST(xcbincludedir)
if test "x$GCC" = xyes ; then
- CWARNFLAGS="-Wall -pedantic -Wpointer-arith \
+ CWARNFLAGS="-Wall -Wpointer-arith -Wold-style-definition \
-Wstrict-prototypes -Wmissing-declarations -Wnested-externs"
else
AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"])
if test "x$SUNCC" = "xyes"; then
- CWARNFLAGS="-v"
+ CWARNFLAGS="-v -fd"
fi
fi
AC_SUBST(CWARNFLAGS)
XCB_CHECK_VISIBILITY()
-# htmldir is not defined prior to autoconf 2.59c, so on earlier versions
-# set an equivalent value.
-AC_PREREQ([2.59c], [], [AC_SUBST([htmldir], [m4_ifset([AC_PACKAGE_TARNAME],
- ['${datadir}/doc/${PACKAGE_TARNAME}'],
- ['${datadir}/doc/${PACKAGE}'])
-])])
-
XCB_CHECK_DOXYGEN()
AC_CHECK_FUNC(getaddrinfo, [AC_DEFINE(HAVE_GETADDRINFO, 1, [getaddrinfo() function is available])], )
XCB_EXTENSION(Damage, "yes")
XCB_EXTENSION(DPMS, "yes")
XCB_EXTENSION(DRI2, "yes")
+XCB_EXTENSION(DRI3, "$sendfds")
XCB_EXTENSION(GLX, "yes")
+XCB_EXTENSION(Present, "yes")
XCB_EXTENSION(RandR, "yes")
XCB_EXTENSION(Record, "yes")
XCB_EXTENSION(Render, "yes")
XCB_EXTENSION(XFree86-DRI, "yes")
XCB_EXTENSION(Xinerama, "yes")
XCB_EXTENSION(XInput, "no")
-XCB_EXTENSION(XKB, "no")
+XCB_EXTENSION(XKB, "yes")
XCB_EXTENSION(Xprint, "yes")
XCB_EXTENSION(SELinux, "no")
XCB_EXTENSION(XTest, "yes")
XCB_EXTENSION(Xv, "yes")
XCB_EXTENSION(XvMC, "yes")
+XCB_EXTENSION(hwa, "yes")
+XCB_EXTENSION(hwc, "yes")
+
AC_ARG_WITH(launchd, AS_HELP_STRING([--with-launchd], [Build with support for Apple's launchd (default: auto)]), [LAUNCHD=$withval], [LAUNCHD=auto])
if test "x$LAUNCHD" = xauto; then
xcb-damage.pc
xcb-dpms.pc
xcb-dri2.pc
+xcb-dri3.pc
xcb-glx.pc
+xcb-present.pc
xcb-randr.pc
xcb-record.pc
xcb-render.pc
xcb-xtest.pc
xcb-xv.pc
xcb-xvmc.pc
+xcb-hwa.pc
+xcb-hwc.pc
])
AC_CONFIG_FILES([
echo ""
echo " Configuration"
echo " XDM support.........: ${have_xdmcp}"
+echo " sendmsg fd passing..: ${sendfds}"
echo " Build unit tests....: ${HAVE_CHECK}"
+echo " with html results.: ${HTML_CHECK_RESULT}"
echo " XCB buffer size.....: ${xcb_queue_buffer_size}"
echo ""
echo " X11 extensions"
echo " Damage..............: ${BUILD_DAMAGE}"
echo " Dpms................: ${BUILD_DPMS}"
echo " Dri2................: ${BUILD_DRI2}"
+echo " Dri3................: ${BUILD_DRI3}"
echo " Glx.................: ${BUILD_GLX}"
echo " Randr...............: ${BUILD_RANDR}"
echo " Record..............: ${BUILD_RECORD}"
echo " xtest...............: ${BUILD_XTEST}"
echo " xv..................: ${BUILD_XV}"
echo " xvmc................: ${BUILD_XVMC}"
+echo " hwa.................: ${BUILD_HWA}"
+echo " hwc.................: ${BUILD_HWC}"
echo ""
echo " Used CFLAGS:"
echo " CPPFLAGS............: ${CPPFLAGS}"
Name: libxcb
Summary: A C binding to the X11 protocol
-Version: 1.8.1
+Version: 1.10.0
Release: 1
Group: System/Libraries
License: MIT
BuildRequires: libpthread-stubs
BuildRequires: libXau-devel
BuildRequires: pkgconfig(xproto)
-BuildRequires: xcb-proto >= 1.6
+BuildRequires: xcb-proto >= 1.10
BuildRequires: libxslt
BuildRequires: python
BuildRequires: python-xml
#%files doc
#%defattr(-,root,root,-)
-#%{_datadir}/doc/%{name}
\ No newline at end of file
+#%{_datadir}/doc/%{name}
nodist_libxcb_dri2_la_SOURCES = dri2.c dri2.h
endif
+EXTSOURCES += dri3.c
+if BUILD_DRI3
+lib_LTLIBRARIES += libxcb-dri3.la
+libxcb_dri3_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@
+libxcb_dri3_la_LIBADD = $(XCB_LIBS)
+nodist_libxcb_dri3_la_SOURCES = dri3.c dri3.h
+endif
+
+EXTSOURCES += present.c
+if BUILD_PRESENT
+lib_LTLIBRARIES += libxcb-present.la
+libxcb_present_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@
+libxcb_present_la_LIBADD = $(XCB_LIBS)
+nodist_libxcb_present_la_SOURCES = present.c present.h
+endif
+
EXTSOURCES += glx.c
if BUILD_GLX
lib_LTLIBRARIES += libxcb-glx.la
EXTSOURCES += sync.c
if BUILD_SYNC
lib_LTLIBRARIES += libxcb-sync.la
-libxcb_sync_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@
+libxcb_sync_la_LDFLAGS = -version-info 1:0:0 -no-undefined @lt_enable_auto_import@
libxcb_sync_la_LIBADD = $(XCB_LIBS)
nodist_libxcb_sync_la_SOURCES = sync.c sync.h
endif
EXTSOURCES += xinput.c
if BUILD_XINPUT
lib_LTLIBRARIES += libxcb-xinput.la
-libxcb_xinput_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@
+libxcb_xinput_la_LDFLAGS = -version-info 1:0:1 -no-undefined @lt_enable_auto_import@
libxcb_xinput_la_LIBADD = $(XCB_LIBS)
nodist_libxcb_xinput_la_SOURCES = xinput.c xinput.h
endif
EXTSOURCES += xkb.c
if BUILD_XKB
lib_LTLIBRARIES += libxcb-xkb.la
-libxcb_xkb_la_LDFLAGS = -version-info 0:0:0 -no-undefined
+libxcb_xkb_la_LDFLAGS = -version-info 1:0:0 -no-undefined
libxcb_xkb_la_LIBADD = $(XCB_LIBS)
nodist_libxcb_xkb_la_SOURCES = xkb.c xkb.h
endif
nodist_libxcb_xvmc_la_SOURCES = xvmc.c xvmc.h
endif
+EXTSOURCES += hwa.c
+if BUILD_HWA
+lib_LTLIBRARIES += libxcb-hwa.la
+libxcb_hwa_la_LDFLAGS = -version-info 0:1:0 -no-undefined @lt_enable_auto_import@
+libxcb_hwa_la_LIBADD = $(XCB_LIBS)
+nodist_libxcb_hwa_la_SOURCES = hwa.c hwa.h
+endif
+
+EXTSOURCES += hwc.c
+if BUILD_HWC
+lib_LTLIBRARIES += libxcb-hwc.la
+libxcb_hwc_la_LDFLAGS = -version-info 0:1:0 -no-undefined @lt_enable_auto_import@
+libxcb_hwc_la_LIBADD = $(XCB_LIBS)
+nodist_libxcb_hwc_la_SOURCES = hwc.c hwc.h
+endif
EXTHEADERS=$(EXTSOURCES:.c=.h)
xcbinclude_HEADERS = xcb.h xcbext.h
nodist_xcbinclude_HEADERS = $(EXTHEADERS)
noinst_HEADERS = xcbint.h
-BUILT_SOURCES = $(EXTSOURCES)
-CLEANFILES = $(EXTSOURCES) $(EXTHEADERS)
+STATIC_MANS = man/xcb-examples.3 man/xcb-requests.3
+BUILT_MANS = man/xcb_*.3
+man_MANS = $(STATIC_MANS) $(BUILT_MANS)
+EXTRA_DIST = $(STATIC_MANS)
-$(EXTSOURCES): c_client.py
+BUILT_SOURCES = $(EXTSOURCES) $(BUILT_MANS)
+CLEANFILES = $(EXTSOURCES) $(EXTHEADERS) $(BUILT_MANS)
+
+$(EXTSOURCES): c_client.py $(XCBPROTO_XCBINCLUDEDIR)/$(@:.c=.xml)
$(PYTHON) $(srcdir)/c_client.py -p $(XCBPROTO_XCBPYTHONDIR) $(XCBPROTO_XCBINCLUDEDIR)/$(@:.c=.xml)
+
+$(man_MANS): $(EXTSOURCES)
from os.path import basename
from functools import reduce
import getopt
+import os
import sys
+import errno
+import time
import re
# Jump to the bottom of this file for the main routine
finished_sizeof = []
finished_switch = []
+# keeps enum objects so that we can refer to them when generating manpages.
+enums = {}
+
+manpaths = False
+
def _h(fmt, *args):
'''
Writes the given line to the header file.
_h('')
_h('#include "xcb.h"')
+ _c('#ifdef HAVE_CONFIG_H')
+ _c('#include "config.h"')
+ _c('#endif')
_c('#include <stdlib.h>')
_c('#include <string.h>')
_c('#include <assert.h>')
Exported function that handles enum declarations.
'''
+ enums[name] = self
+
tname = _t(name)
if namecount[tname] > 1:
tname = _t(name + ('enum',))
count = count - 1
equals = ' = ' if eval != '' else ''
comma = ',' if count > 0 else ''
- _h(' %s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma)
+ doc = ''
+ if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
+ doc = '\n/**< %s */\n' % self.doc.fields[enam]
+ _h(' %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
_h('} %s;', tname)
self.c_reply_name = _n(name + ('reply',))
self.c_reply_type = _t(name + ('reply',))
self.c_cookie_type = _t(name + ('cookie',))
+ self.c_reply_fds_name = _n(name + ('reply_fds',))
self.need_aux = False
self.need_serialize = False
switch_expr = _c_accessor_get_expr(self.expr, None)
for b in self.bitcases:
- bitcase_expr = _c_accessor_get_expr(b.type.expr, None)
- code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr))
-# code_lines.append(' printf("switch %s: entering bitcase section %s (mask=%%%%d)...\\n", %s);' %
-# (self.name[-1], b.type.name[-1], bitcase_expr))
+ len_expr = len(b.type.expr)
+ for n, expr in enumerate(b.type.expr):
+ bitcase_expr = _c_accessor_get_expr(expr, None)
+ # only one <enumref> in the <bitcase>
+ if len_expr == 1:
+ code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr))
+ # multiple <enumref> in the <bitcase>
+ elif n == 0: # first
+ code_lines.append(' if((%s & %s) ||' % (switch_expr, bitcase_expr))
+ elif len_expr == (n + 1): # last
+ code_lines.append(' (%s & %s)) {' % (switch_expr, bitcase_expr))
+ else: # between first and last
+ code_lines.append(' (%s & %s) ||' % (switch_expr, bitcase_expr))
+
b_prefix = prefix
if b.type.has_name:
b_prefix = prefix + [(b.c_field_name, '.', b.type)]
if context in ('unserialize', 'unpack', 'sizeof') and not self.var_followed_by_fixed_fields:
code_lines.append('%s xcb_block_len += sizeof(%s);' % (space, self.c_type))
code_lines.append('%s xcb_tmp += xcb_block_len;' % space)
- # probably not needed
- #_c_serialize_helper_insert_padding(context, code_lines, space, False)
+ code_lines.append('%s xcb_buffer_len += xcb_block_len;' % space)
+ code_lines.append('%s xcb_block_len = 0;' % space)
count += _c_serialize_helper_fields(context, self,
code_lines, temp_vars,
_c(' %s *xcb_out = *_buffer;', self.c_type)
_c(' unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
_c(' unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
- _c(' unsigned int xcb_align_to;')
+ _c(' unsigned int xcb_align_to = 0;')
else:
_c(' char *xcb_out = *_buffer;')
_c(' unsigned int xcb_buffer_len = 0;')
- _c(' unsigned int xcb_align_to;')
+ _c(' unsigned int xcb_align_to = 0;')
prefix = [('_aux', '->', self)]
aux_ptr = 'xcb_out'
_c(' unsigned int xcb_buffer_len = 0;')
_c(' unsigned int xcb_block_len = 0;')
_c(' unsigned int xcb_pad = 0;')
- _c(' unsigned int xcb_align_to;')
+ _c(' unsigned int xcb_align_to = 0;')
elif 'sizeof' == context:
param_names = [p[2] for p in params]
_c(' unsigned int xcb_buffer_len = 0;')
_c(' unsigned int xcb_block_len = 0;')
_c(' unsigned int xcb_pad = 0;')
- _c(' unsigned int xcb_align_to;')
+ _c(' unsigned int xcb_align_to = 0;')
_c('')
for t in temp_vars:
for field in struct_fields:
length = len(field.c_field_type)
# account for '*' pointer_spec
- if not field.type.fixed_size():
+ if not field.type.fixed_size() and not self.is_union:
length += 1
maxtypelen = max(maxtypelen, length)
def _c_complex_field(self, field, space=''):
- if (field.type.fixed_size() or
+ if (field.type.fixed_size() or self.is_union or
# in case of switch with switch children, don't make the field a pointer
# necessary for unserialize to work
(self.is_switch and field.type.is_switch)):
_c_complex(self)
_c_iterator(self, name)
-def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
+def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
'''
Declares a request function.
'''
# What flag is passed to xcb_request
func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
+ if reply_fds:
+ if func_flags == '0':
+ func_flags = 'XCB_REQUEST_REPLY_FDS'
+ else:
+ func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
+
# Global extension id variable or NULL for xproto
func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
_c_setlevel(1)
_h('')
_h('/**')
- _h(' * Delivers a request to the X server')
+ if hasattr(self, "doc") and self.doc:
+ if self.doc.brief:
+ _h(' * @brief ' + self.doc.brief)
+ else:
+ _h(' * No brief doc yet')
+
+ _h(' *')
_h(' * @param c The connection')
+ param_names = [f.c_field_name for f in param_fields]
+ if hasattr(self, "doc") and self.doc:
+ for field in param_fields:
+ # XXX: hard-coded until we fix xproto.xml
+ base_func_name = self.c_request_name if not aux else self.c_aux_name
+ if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
+ field.enum = 'GC'
+ elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
+ field.enum = 'CW'
+ elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
+ field.enum = 'CW'
+ if field.enum:
+ # XXX: why the 'xcb' prefix?
+ key = ('xcb', field.enum)
+
+ tname = _t(key)
+ if namecount[tname] > 1:
+ tname = _t(key + ('enum',))
+ _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
+
+ if self.doc and field.field_name in self.doc.fields:
+ desc = self.doc.fields[field.field_name]
+ for name in param_names:
+ desc = desc.replace('`%s`' % name, '\\a %s' % (name))
+ desc = desc.split("\n")
+ desc = [line if line != '' else '\\n' for line in desc]
+ _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
+ # If there is no documentation yet, we simply don't generate an
+ # @param tag. Doxygen will then warn about missing documentation.
+
_h(' * @return A cookie')
_h(' *')
- _h(' * Delivers a request to the X server.')
+
+ if hasattr(self, "doc") and self.doc:
+ if self.doc.description:
+ desc = self.doc.description
+ for name in param_names:
+ desc = desc.replace('`%s`' % name, '\\a %s' % (name))
+ desc = desc.split("\n")
+ _h(' * ' + "\n * ".join(desc))
+ else:
+ _h(' * No description yet')
+ else:
+ _h(' * Delivers a request to the X server.')
_h(' * ')
if checked:
_h(' * This form can be used only if the request will not cause')
# no padding necessary - _serialize() keeps track of padding automatically
_c(' ')
+ for field in param_fields:
+ if field.isfd:
+ _c(' xcb_send_fd(c, %s);', field.c_field_name)
+
_c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
# free dyn. all. data, if any
_c('}')
+def _c_reply_has_fds(self):
+ for field in self.fields:
+ if field.isfd:
+ return True
+ return False
+
+def _c_reply_fds(self, name):
+ '''
+ Declares the function that returns fds related to the reply.
+ '''
+ spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
+ spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
+ _h('')
+ _h('/**')
+ _h(' * Return the reply fds')
+ _h(' * @param c The connection')
+ _h(' * @param reply The reply')
+ _h(' *')
+ _h(' * Returns the array of reply fds of the request asked by')
+ _h(' * ')
+ _h(' * The returned value must be freed by the caller using free().')
+ _h(' */')
+ _c('')
+ _hc('')
+ _hc('/*****************************************************************************')
+ _hc(' **')
+ _hc(' ** int * %s', self.c_reply_fds_name)
+ _hc(' ** ')
+ _hc(' ** @param xcb_connection_t%s *c', spacing1)
+ _hc(' ** @param %s *reply', self.c_reply_type)
+ _hc(' ** @returns int *')
+ _hc(' **')
+ _hc(' *****************************************************************************/')
+ _hc(' ')
+ _hc('int *')
+ _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
+ _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
+ _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
+ _c('{')
+
+ _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
+
+ _c('}')
+
+
def _c_opcode(name, opcode):
'''
Declares the opcode define for requests, events, and errors.
_h(' unsigned int sequence; /**< */')
_h('} %s;', self.c_cookie_type)
+def _man_request(self, name, cookie_type, void, aux):
+ param_fields = [f for f in self.fields if f.visible]
+
+ func_name = self.c_request_name if not aux else self.c_aux_name
+
+ def create_link(linkname):
+ name = 'man/%s.3' % linkname
+ if manpaths:
+ sys.stdout.write(name)
+ f = open(name, 'w')
+ f.write('.so man3/%s.3' % func_name)
+ f.close()
+
+ if manpaths:
+ sys.stdout.write('man/%s.3 ' % func_name)
+ # Our CWD is src/, so this will end up in src/man/
+ f = open('man/%s.3' % func_name, 'w')
+ f.write('.TH %s 3 %s "XCB" "XCB Requests"\n' % (func_name, today))
+ # Left-adjust instead of adjusting to both sides
+ f.write('.ad l\n')
+ f.write('.SH NAME\n')
+ brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
+ f.write('%s \\- %s\n' % (func_name, brief))
+ f.write('.SH SYNOPSIS\n')
+ # Don't split words (hyphenate)
+ f.write('.hy 0\n')
+ f.write('.B #include <xcb/%s.h>\n' % _ns.header)
+
+ # function prototypes
+ prototype = ''
+ count = len(param_fields)
+ for field in param_fields:
+ count = count - 1
+ c_field_const_type = field.c_field_const_type
+ c_pointer = field.c_pointer
+ if c_pointer == ' ':
+ c_pointer = ''
+ if field.type.need_serialize and not aux:
+ c_field_const_type = "const void"
+ c_pointer = '*'
+ comma = ', ' if count else ');'
+ prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
+
+ f.write('.SS Request function\n')
+ f.write('.HP\n')
+ base_func_name = self.c_request_name if not aux else self.c_aux_name
+ f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
+ create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
+ if not void:
+ f.write('.PP\n')
+ f.write('.SS Reply datastructure\n')
+ f.write('.nf\n')
+ f.write('.sp\n')
+ f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
+ struct_fields = []
+ maxtypelen = 0
+
+ for field in self.reply.fields:
+ if not field.type.fixed_size() and not self.is_switch and not self.is_union:
+ continue
+ if field.wire:
+ struct_fields.append(field)
+
+ for field in struct_fields:
+ length = len(field.c_field_type)
+ # account for '*' pointer_spec
+ if not field.type.fixed_size():
+ length += 1
+ maxtypelen = max(maxtypelen, length)
+
+ def _c_complex_field(self, field, space=''):
+ if (field.type.fixed_size() or
+ # in case of switch with switch children, don't make the field a pointer
+ # necessary for unserialize to work
+ (self.is_switch and field.type.is_switch)):
+ spacing = ' ' * (maxtypelen - len(field.c_field_type))
+ f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
+ else:
+ spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
+ f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
+ #_h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
+
+ if not self.is_switch:
+ for field in struct_fields:
+ _c_complex_field(self, field)
+ else:
+ for b in self.bitcases:
+ space = ''
+ if b.type.has_name:
+ space = ' '
+ for field in b.type.fields:
+ _c_complex_field(self, field, space)
+ if b.type.has_name:
+ print >> sys.stderr, 'ERROR: New unhandled documentation case'
+ pass
+
+ f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
+ f.write('.fi\n')
+
+ f.write('.SS Reply function\n')
+ f.write('.HP\n')
+ f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
+ '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
+ (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
+ create_link('%s' % self.c_reply_name)
+
+ has_accessors = False
+ for field in self.reply.fields:
+ if field.type.is_list and not field.type.fixed_size():
+ has_accessors = True
+ elif field.prev_varsized_field is not None or not field.type.fixed_size():
+ has_accessors = True
+
+ if has_accessors:
+ f.write('.SS Reply accessors\n')
+
+ def _c_accessors_field(self, field):
+ '''
+ Declares the accessor functions for a non-list field that follows a variable-length field.
+ '''
+ c_type = self.c_type
+
+ # special case: switch
+ switch_obj = self if self.is_switch else None
+ if self.is_bitcase:
+ switch_obj = self.parents[-1]
+ if switch_obj is not None:
+ c_type = switch_obj.c_type
+
+ if field.type.is_simple:
+ f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
+ create_link('%s' % field.c_accessor_name)
+ else:
+ f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
+ create_link('%s' % field.c_accessor_name)
+
+ def _c_accessors_list(self, field):
+ '''
+ Declares the accessor functions for a list field.
+ Declares a direct-accessor function only if the list members are fixed size.
+ Declares length and get-iterator functions always.
+ '''
+ list = field.type
+ c_type = self.reply.c_type
+
+ # special case: switch
+ # in case of switch, 2 params have to be supplied to certain accessor functions:
+ # 1. the anchestor object (request or reply)
+ # 2. the (anchestor) switch object
+ # the reason is that switch is either a child of a request/reply or nested in another switch,
+ # so whenever we need to access a length field, we might need to refer to some anchestor type
+ switch_obj = self if self.is_switch else None
+ if self.is_bitcase:
+ switch_obj = self.parents[-1]
+ if switch_obj is not None:
+ c_type = switch_obj.c_type
+
+ params = []
+ fields = {}
+ parents = self.parents if hasattr(self, 'parents') else [self]
+ # 'R': parents[0] is always the 'toplevel' container type
+ params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
+ fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
+ # auxiliary object for 'R' parameters
+ R_obj = parents[0]
+
+ if switch_obj is not None:
+ # now look where the fields are defined that are needed to evaluate
+ # the switch expr, and store the parent objects in accessor_params and
+ # the fields in switch_fields
+
+ # 'S': name for the 'toplevel' switch
+ toplevel_switch = parents[1]
+ params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
+ fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
+
+ # initialize prefix for everything "below" S
+ prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
+ prefix = [(prefix_str, '->', toplevel_switch)]
+
+ # look for fields in the remaining containers
+ for p in parents[2:] + [self]:
+ # the separator between parent and child is always '.' here,
+ # because of nested switch statements
+ if not p.is_bitcase or (p.is_bitcase and p.has_name):
+ prefix.append((p.name[-1], '.', p))
+ fields.update(_c_helper_field_mapping(p, prefix, flat=True))
+
+ # auxiliary object for 'S' parameter
+ S_obj = parents[1]
+
+ if list.member.fixed_size():
+ idx = 1 if switch_obj is not None else 0
+ f.write('.HP\n')
+ f.write('%s *\\fB%s\\fP(%s);\n' %
+ (field.c_field_type, field.c_accessor_name, params[idx][0]))
+ create_link('%s' % field.c_accessor_name)
+
+ f.write('.HP\n')
+ f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
+ (field.c_length_name, c_type))
+ create_link('%s' % field.c_length_name)
+
+ if field.type.member.is_simple:
+ f.write('.HP\n')
+ f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
+ (field.c_end_name, c_type))
+ create_link('%s' % field.c_end_name)
+ else:
+ f.write('.HP\n')
+ f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
+ (field.c_iterator_type, field.c_iterator_name,
+ c_type))
+ create_link('%s' % field.c_iterator_name)
+
+ for field in self.reply.fields:
+ if field.type.is_list and not field.type.fixed_size():
+ _c_accessors_list(self, field)
+ elif field.prev_varsized_field is not None or not field.type.fixed_size():
+ _c_accessors_field(self, field)
+
+
+ f.write('.br\n')
+ # Re-enable hyphenation and adjusting to both sides
+ f.write('.hy 1\n')
+
+ # argument reference
+ f.write('.SH REQUEST ARGUMENTS\n')
+ f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
+ f.write('The XCB connection to X11.\n')
+ for field in param_fields:
+ f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
+ printed_enum = False
+ # XXX: hard-coded until we fix xproto.xml
+ if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
+ field.enum = 'GC'
+ elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
+ field.enum = 'CW'
+ elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
+ field.enum = 'CW'
+ if hasattr(field, "enum") and field.enum:
+ # XXX: why the 'xcb' prefix?
+ key = ('xcb', field.enum)
+ if key in enums:
+ f.write('One of the following values:\n')
+ f.write('.RS 1i\n')
+ enum = enums[key]
+ count = len(enum.values)
+ for (enam, eval) in enum.values:
+ count = count - 1
+ f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
+ if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
+ desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
+ f.write('%s\n' % desc)
+ else:
+ f.write('TODO: NOT YET DOCUMENTED.\n')
+ f.write('.RE\n')
+ f.write('.RS 1i\n')
+ printed_enum = True
+
+ if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
+ desc = self.doc.fields[field.field_name]
+ desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+ if printed_enum:
+ f.write('\n')
+ f.write('%s\n' % desc)
+ else:
+ f.write('TODO: NOT YET DOCUMENTED.\n')
+ if printed_enum:
+ f.write('.RE\n')
+
+ # Reply reference
+ if not void:
+ f.write('.SH REPLY FIELDS\n')
+ # These fields are present in every reply:
+ f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
+ f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
+ 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
+ 'be used to tell replies apart from each other.\n') %
+ _n(self.reply.name).upper())
+ f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
+ f.write('The sequence number of the last request processed by the X11 server.\n')
+ f.write('.IP \\fI%s\\fP 1i\n' % 'length')
+ f.write('The length of the reply, in words (a word is 4 bytes).\n')
+ for field in self.reply.fields:
+ if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
+ field.c_field_name.startswith('pad')):
+ continue
+
+ if field.type.is_list and not field.type.fixed_size():
+ continue
+ elif field.prev_varsized_field is not None or not field.type.fixed_size():
+ continue
+ f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
+ printed_enum = False
+ if hasattr(field, "enum") and field.enum:
+ # XXX: why the 'xcb' prefix?
+ key = ('xcb', field.enum)
+ if key in enums:
+ f.write('One of the following values:\n')
+ f.write('.RS 1i\n')
+ enum = enums[key]
+ count = len(enum.values)
+ for (enam, eval) in enum.values:
+ count = count - 1
+ f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
+ if enum.doc and enam in enum.doc.fields:
+ desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
+ f.write('%s\n' % desc)
+ else:
+ f.write('TODO: NOT YET DOCUMENTED.\n')
+ f.write('.RE\n')
+ f.write('.RS 1i\n')
+ printed_enum = True
+
+ if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
+ desc = self.reply.doc.fields[field.field_name]
+ desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+ if printed_enum:
+ f.write('\n')
+ f.write('%s\n' % desc)
+ else:
+ f.write('TODO: NOT YET DOCUMENTED.\n')
+ if printed_enum:
+ f.write('.RE\n')
+
+
+
+ # text description
+ f.write('.SH DESCRIPTION\n')
+ if hasattr(self, "doc") and self.doc and self.doc.description:
+ desc = self.doc.description
+ desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+ lines = desc.split('\n')
+ f.write('\n'.join(lines) + '\n')
+
+ f.write('.SH RETURN VALUE\n')
+ if void:
+ f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
+ 'have to be handled in the event loop.\n\nIf you want to '
+ 'handle errors directly with \\fIxcb_request_check\\fP '
+ 'instead, use \\fI%s_checked\\fP. See '
+ '\\fBxcb-requests(3)\\fP for details.\n') % (base_func_name))
+ else:
+ f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
+ 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
+ 'handle errors in the event loop instead, use '
+ '\\fI%s_unchecked\\fP. See \\fBxcb-requests(3)\\fP for '
+ 'details.\n') %
+ (cookie_type, self.c_reply_name, base_func_name))
+ f.write('.SH ERRORS\n')
+ if hasattr(self, "doc") and self.doc:
+ for errtype, errtext in self.doc.errors.items():
+ f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
+ errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
+ f.write('%s\n' % (errtext))
+ if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
+ f.write('This request does never generate any errors.\n')
+ if hasattr(self, "doc") and self.doc and self.doc.example:
+ f.write('.SH EXAMPLE\n')
+ f.write('.nf\n')
+ f.write('.sp\n')
+ lines = self.doc.example.split('\n')
+ f.write('\n'.join(lines) + '\n')
+ f.write('.fi\n')
+ f.write('.SH SEE ALSO\n')
+ if hasattr(self, "doc") and self.doc:
+ see = ['.BR %s (3)' % 'xcb-requests']
+ if self.doc.example:
+ see.append('.BR %s (3)' % 'xcb-examples')
+ for seename, seetype in self.doc.see.items():
+ if seetype == 'program':
+ see.append('.BR %s (1)' % seename)
+ elif seetype == 'event':
+ see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
+ elif seetype == 'request':
+ see.append('.BR %s (3)' % _n(('xcb', seename)))
+ elif seetype == 'function':
+ see.append('.BR %s (3)' % seename)
+ else:
+ see.append('TODO: %s (type %s)' % (seename, seetype))
+ f.write(',\n'.join(see) + '\n')
+ f.write('.SH AUTHOR\n')
+ f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
+ f.close()
+
+def _man_event(self, name):
+ if manpaths:
+ sys.stdout.write('man/%s.3 ' % self.c_type)
+ # Our CWD is src/, so this will end up in src/man/
+ f = open('man/%s.3' % self.c_type, 'w')
+ f.write('.TH %s 3 %s "XCB" "XCB Events"\n' % (self.c_type, today))
+ # Left-adjust instead of adjusting to both sides
+ f.write('.ad l\n')
+ f.write('.SH NAME\n')
+ brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
+ f.write('%s \\- %s\n' % (self.c_type, brief))
+ f.write('.SH SYNOPSIS\n')
+ # Don't split words (hyphenate)
+ f.write('.hy 0\n')
+ f.write('.B #include <xcb/%s.h>\n' % _ns.header)
+
+ f.write('.PP\n')
+ f.write('.SS Event datastructure\n')
+ f.write('.nf\n')
+ f.write('.sp\n')
+ f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
+ struct_fields = []
+ maxtypelen = 0
+
+ for field in self.fields:
+ if not field.type.fixed_size() and not self.is_switch and not self.is_union:
+ continue
+ if field.wire:
+ struct_fields.append(field)
+
+ for field in struct_fields:
+ length = len(field.c_field_type)
+ # account for '*' pointer_spec
+ if not field.type.fixed_size():
+ length += 1
+ maxtypelen = max(maxtypelen, length)
+
+ def _c_complex_field(self, field, space=''):
+ if (field.type.fixed_size() or
+ # in case of switch with switch children, don't make the field a pointer
+ # necessary for unserialize to work
+ (self.is_switch and field.type.is_switch)):
+ spacing = ' ' * (maxtypelen - len(field.c_field_type))
+ f.write('%s %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
+ else:
+ print >> sys.stderr, 'ERROR: New unhandled documentation case'
+
+ if not self.is_switch:
+ for field in struct_fields:
+ _c_complex_field(self, field)
+ else:
+ for b in self.bitcases:
+ space = ''
+ if b.type.has_name:
+ space = ' '
+ for field in b.type.fields:
+ _c_complex_field(self, field, space)
+ if b.type.has_name:
+ print >> sys.stderr, 'ERROR: New unhandled documentation case'
+ pass
+
+ f.write('} \\fB%s\\fP;\n' % self.c_type)
+ f.write('.fi\n')
+
+
+ f.write('.br\n')
+ # Re-enable hyphenation and adjusting to both sides
+ f.write('.hy 1\n')
+
+ # argument reference
+ f.write('.SH EVENT FIELDS\n')
+ f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
+ f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
+ 'also present in the \\fIxcb_generic_event_t\\fP and can be used '
+ 'to tell events apart from each other.\n') % _n(name).upper())
+ f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
+ f.write('The sequence number of the last request processed by the X11 server.\n')
+
+ if not self.is_switch:
+ for field in struct_fields:
+ # Skip the fields which every event has, we already documented
+ # them (see above).
+ if field.c_field_name in ('response_type', 'sequence'):
+ continue
+ if isinstance(field.type, PadType):
+ continue
+ f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
+ if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
+ desc = self.doc.fields[field.field_name]
+ desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+ f.write('%s\n' % desc)
+ else:
+ f.write('NOT YET DOCUMENTED.\n')
+
+ # text description
+ f.write('.SH DESCRIPTION\n')
+ if hasattr(self, "doc") and self.doc and self.doc.description:
+ desc = self.doc.description
+ desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+ lines = desc.split('\n')
+ f.write('\n'.join(lines) + '\n')
+
+ if hasattr(self, "doc") and self.doc and self.doc.example:
+ f.write('.SH EXAMPLE\n')
+ f.write('.nf\n')
+ f.write('.sp\n')
+ lines = self.doc.example.split('\n')
+ f.write('\n'.join(lines) + '\n')
+ f.write('.fi\n')
+ f.write('.SH SEE ALSO\n')
+ if hasattr(self, "doc") and self.doc:
+ see = ['.BR %s (3)' % 'xcb_generic_event_t']
+ if self.doc.example:
+ see.append('.BR %s (3)' % 'xcb-examples')
+ for seename, seetype in self.doc.see.items():
+ if seetype == 'program':
+ see.append('.BR %s (1)' % seename)
+ elif seetype == 'event':
+ see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
+ elif seetype == 'request':
+ see.append('.BR %s (3)' % _n(('xcb', seename)))
+ elif seetype == 'function':
+ see.append('.BR %s (3)' % seename)
+ else:
+ see.append('TODO: %s (type %s)' % (seename, seetype))
+ f.write(',\n'.join(see) + '\n')
+ f.write('.SH AUTHOR\n')
+ f.write('Generated from %s.xml. Contact xcb@lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
+ f.close()
+
+
def c_request(self, name):
'''
Exported function that handles request declarations.
# Reply structure definition
_c_complex(self.reply)
# Request prototypes
- _c_request_helper(self, name, self.c_cookie_type, False, True)
- _c_request_helper(self, name, self.c_cookie_type, False, False)
+ has_fds = _c_reply_has_fds(self.reply)
+ _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
+ _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
if self.need_aux:
- _c_request_helper(self, name, self.c_cookie_type, False, True, True)
- _c_request_helper(self, name, self.c_cookie_type, False, False, True)
+ _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
+ _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
# Reply accessors
_c_accessors(self.reply, name + ('reply',), name)
_c_reply(self, name)
+ if has_fds:
+ _c_reply_fds(self, name)
else:
# Request prototypes
_c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
_c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
_c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
+ # We generate the manpage afterwards because _c_type_setup has been called.
+ # TODO: what about aux helpers?
+ cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
+ _man_request(self, name, cookie_type, not self.reply, False)
def c_event(self, name):
'''
Exported function that handles event declarations.
'''
+
+ # The generic event structure xcb_ge_event_t has the full_sequence field
+ # at the 32byte boundary. That's why we've to inject this field into GE
+ # events while generating the structure for them. Otherwise we would read
+ # garbage (the internal full_sequence) when accessing normal event fields
+ # there.
+ if hasattr(self, 'is_ge_event') and self.is_ge_event and self.name == name:
+ event_size = 0
+ for field in self.fields:
+ if field.type.size != None and field.type.nmemb != None:
+ event_size += field.type.size * field.type.nmemb
+ if event_size == 32:
+ full_sequence = Field(tcard32, tcard32.name, 'full_sequence', False, True, True)
+ idx = self.fields.index(field)
+ self.fields.insert(idx + 1, full_sequence)
+ break
+
_c_type_setup(self, name, ('event',))
# Opcode define
_h('')
_h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
+ _man_event(self, name)
+
def c_error(self, name):
'''
Exported function that handles error declarations.
# Check for the argument that specifies path to the xcbgen python package.
try:
- opts, args = getopt.getopt(sys.argv[1:], 'p:')
+ opts, args = getopt.getopt(sys.argv[1:], 'p:m')
except getopt.GetoptError as err:
print(err)
print('Usage: c_client.py [-p path] file.xml')
for (opt, arg) in opts:
if opt == '-p':
sys.path.insert(1, arg)
+ elif opt == '-m':
+ manpaths = True
+ sys.stdout.write('man_MANS = ')
# Import the module class
try:
from xcbgen.state import Module
+ from xcbgen.xtypes import *
except ImportError:
print('''
Failed to load the xcbgen Python package!
''')
raise
+# Ensure the man subdirectory exists
+try:
+ os.mkdir('man')
+except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+
+today = time.strftime('%Y-%m-%d', time.gmtime(os.path.getmtime(args[0])))
+
# Parse the xml header
module = Module(args[0], output)
--- /dev/null
+.TH xcb-examples 3 2011-12-11 "XCB" "XCB examples"
+.ad l
+.SH NAME
+xcb-examples \- manpage examples
+.SH DESCRIPTION
+Many of the XCB manpages contain example code. These examples intend to explain
+how to use one particular part of XCB. They almost never represent a standalone
+(or even useful) program - X11 programs are relatively involved and
+thus beyond the scope of a manpage example.
+
+.SH ENVIRONMENT
+
+Every example assumes you have an \fIxcb_connection\fP and possibly other
+variables at hand. For illustrating how \fIxcb_get_property\fP works, you need
+the window of which you want to get the property, for example. To make it clear
+that these variables are your responsibility, these examples consist of a
+single function which takes the necessary variables as parameters.
+
+.SH FLUSHING
+
+Flushing means calling \fIxcb_flush\fP to clear the XCB-internal write buffer
+and send all pending requests to the X11 server. You don't explicitly need to
+flush before using a reply function (like \fIxcb_query_pointer_reply\fP), but
+you do need to flush before entering the event loop of your program.
+
+There are only two cases when XCB flushes by itself. The first case is when
+its write buffer becomes full, the second case is when you are asking for
+the reply of a request which wasn't flushed out yet (like
+\fIxcb_query_pointer_reply\fP). This last point also includes
+xcb_request_check(). Please note that waiting for an event does \fBNOT\fP
+flush.
+
+Examples generally include the \fIxcb_flush\fP call where appropriate (for
+example after setting a property). Therefore, including these functions and
+calling them in your application should just work. However, you might get
+better results when flushing outside of the function, depending on the
+architecture of your program.
+
+.SH COMPILATION
+
+If an example does not compile (without warnings) when using \fI-std=c99\fP,
+that is considered a documentation bug. Similarly, not handling errors or
+leaking memory is also considered a documentation bug. Please inform us about
+it on xcb@lists.freedesktop.org.
+
+.SH CODING STYLE
+
+Every example uses 4 spaces for indentation.
+
+Comments are in asterisks, like /* this */.
+
+No line is longer than 80 characters (including indentation).
+
+.SH SEE ALSO
+.BR xcb_connect (3),
+.BR xcb_get_property (3),
+.BR xcb_flush (3)
+.SH AUTHOR
+Michael Stapelberg <michael+xcb at stapelberg dot de>
--- /dev/null
+.TH xcb-requests 3 2011-12-11 "XCB" "XCB examples"
+.ad l
+.SH NAME
+xcb-requests \- about request manpages
+.SH DESCRIPTION
+Every request in X11, like \fIMapWindow\fP, corresponds to a number of
+functions and data structures in XCB. For \fIMapWindow\fP, XCB provides the
+function \fIxcb_map_window\fP, which fills the \fIxcb_map_window_request_t\fP
+data structure and writes that to the X11 connection. Since the \fIMapWindow\fP
+request does not have a reply, this is the most simple case.
+
+.SH REPLIES
+
+Many requests have replies. For each reply, XCB provides at least a
+corresponding data structure and a function to return a pointer to a filled
+data structure. Let's take the \fIInternAtom\fP request as an example: XCB
+provides the \fIxcb_intern_atom_reply_t\fP data structure and
+\fIxcb_intern_atom_reply\fP function. For replies which are more complex (for
+example lists, such as in \fIxcb_list_fonts\fP), accessor functions are
+provided.
+
+.SH COOKIES
+
+XCB returns a cookie for each request you send. This is an XCB-specific data
+structure containing the sequence number with which the request was sent to the
+X11 server. To get any reply, you have to provide that cookie (so that XCB
+knows which of the waiting replies you want). Here is an example to illustrate
+the use of cookies:
+
+.nf
+.sp
+void my_example(xcb_connection *conn) {
+ xcb_intern_atom_cookie_t cookie;
+ xcb_intern_atom_reply_t *reply;
+
+ cookie = xcb_intern_atom(conn, 0, strlen("_NET_WM_NAME"), "_NET_WM_NAME");
+ /* ... do other work here if possible ... */
+ if ((reply = xcb_intern_atom_reply(conn, cookie, NULL))) {
+ printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
+ }
+ free(reply);
+}
+.fi
+
+.SH CHECKED VS. UNCHECKED
+
+The checked and unchecked suffixes for functions determine which kind of error
+handling is used for this specific request.
+
+For requests which have no reply (for example \fIxcb_map_window\fP), errors
+will be delivered to the event loop (you will receive an X11 event of type 0
+when calling \fIxcb_poll_for_event\fP).
+If you want to explicitly check for errors in a blocking fashion, call the
+_checked version of the function (for example \fIxcb_map_window_checked\fP) and
+use \fIxcb_request_check\fP.
+
+For requests which have a reply (for example \fIxcb_intern_atom\fP), errors
+will be checked when calling the reply function. To get errors in the event
+loop instead, use the _unchecked version of the function (for example
+\fIxcb_intern_atom_unchecked\fP).
+
+Here is an example which illustrates the four different ways of handling errors:
+
+.nf
+.sp
+/*
+ * Request without a reply, handling errors in the event loop (default)
+ *
+ */
+void my_example(xcb_connection *conn, xcb_window_t window) {
+ /* This is a request without a reply. Errors will be delivered to the event
+ * loop. Getting an error to xcb_map_window most likely is a bug in our
+ * program, so we don't need to check for that in a blocking way. */
+ xcb_map_window(conn, window);
+
+ /* ... of course your event loop would not be in the same function ... */
+ while ((event = xcb_wait_for_event(conn)) != NULL) {
+ if (event->response_type == 0) {
+ fprintf("Received X11 error %d\\n", error->error_code);
+ free(event);
+ continue;
+ }
+
+ /* ... handle a normal event ... */
+ }
+}
+
+/*
+ * Request without a reply, handling errors directly
+ *
+ */
+void my_example(xcb_connection *conn, xcb_window_t deco, xcb_window_t window) {
+ /* A reparenting window manager wants to know whether a new window was
+ * successfully reparented. If not (because the window got destroyed
+ * already, for example), it does not make sense to map an empty window
+ * decoration at all, so we need to know this right now. */
+ xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, window,
+ deco, 0, 0);
+ xcb_generic_error_t *error;
+ if ((error = xcb_request_check(conn, cookie))) {
+ fprintf(stderr, "Could not reparent the window\\n");
+ free(error);
+ return;
+ }
+
+ /* ... do window manager stuff here ... */
+}
+
+/*
+ * Request with a reply, handling errors directly (default)
+ *
+ */
+void my_example(xcb_connection *conn, xcb_window_t window) {
+ xcb_intern_atom_cookie_t cookie;
+ xcb_intern_atom_reply_t *reply;
+ xcb_generic_error_t *error;
+
+ cookie = xcb_intern_atom(c, 0, strlen("_NET_WM_NAME"), "_NET_WM_NAME");
+ /* ... do other work here if possible ... */
+ if ((reply = xcb_intern_atom_reply(c, cookie, &error))) {
+ printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
+ free(reply);
+ } else {
+ fprintf(stderr, "X11 Error %d\\n", error->error_code);
+ free(error);
+ }
+}
+
+/*
+ * Request with a reply, handling errors in the event loop
+ *
+ */
+void my_example(xcb_connection *conn, xcb_window_t window) {
+ xcb_intern_atom_cookie_t cookie;
+ xcb_intern_atom_reply_t *reply;
+
+ cookie = xcb_intern_atom_unchecked(c, 0, strlen("_NET_WM_NAME"),
+ "_NET_WM_NAME");
+ /* ... do other work here if possible ... */
+ if ((reply = xcb_intern_atom_reply(c, cookie, NULL))) {
+ printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
+ free(reply);
+ }
+
+ /* ... of course your event loop would not be in the same function ... */
+ while ((event = xcb_wait_for_event(conn)) != NULL) {
+ if (event->response_type == 0) {
+ fprintf("Received X11 error %d\\n", error->error_code);
+ free(event);
+ continue;
+ }
+
+ /* ... handle a normal event ... */
+ }
+}
+.fi
+
+.SH SEE ALSO
+.BR xcb_map_window (3),
+.BR xcb_intern_atom (3),
+.BR xcb_list_fonts (3),
+.BR xcb_poll_for_event (3),
+.BR xcb_request_check (3)
+.SH AUTHOR
+Michael Stapelberg <michael+xcb at stapelberg dot de>
/** xcb connection errors because of socket, pipe and other stream errors. */
#define XCB_CONN_ERROR 1
-/** xcb connection shutdown because of extension not sppported */
+/** xcb connection shutdown because of extension not supported */
#define XCB_CONN_CLOSED_EXT_NOTSUPPORTED 2
/** malloc(), calloc() and realloc() error upon failure, for eg ENOMEM */
/** Connection closed, error during parsing display string. */
#define XCB_CONN_CLOSED_PARSE_ERR 5
+/** Connection closed because the server does not have a screen matching the display. */
+#define XCB_CONN_CLOSED_INVALID_SCREEN 6
+
+/** Connection closed because some FD passing operation failed */
+#define XCB_CONN_CLOSED_FDPASSING_FAILED 7
+
#define XCB_TYPE_PAD(T,I) (-(I) & (sizeof(T) > 4 ? 3 : sizeof(T) - 1))
/* Opaque structures */
*
* An event as sent by the XGE extension. The length field specifies the
* number of 4-byte blocks trailing the struct.
+ *
+ * @deprecated Since some fields in this struct have unfortunate names, it is
+ * recommended to use xcb_ge_generic_event_t instead.
*/
typedef struct {
uint8_t response_type; /**< Type of the response */
/**
* @brief Returns the next event or error from the server.
* @param c: The connection to the X server.
- * error status of the operation.
* @return The next event from the server.
*
* Returns the next event or error from the server, if one is
*/
xcb_generic_event_t *xcb_poll_for_queued_event(xcb_connection_t *c);
+typedef struct xcb_special_event xcb_special_event_t;
+
+/**
+ * @brief Returns the next event from a special queue
+ */
+xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se);
+
+/**
+ * @brief Returns the next event from a special queue, blocking until one arrives
+ */
+xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se);
+/**
+ * @typedef typedef struct xcb_extension_t xcb_extension_t
+ */
+typedef struct xcb_extension_t xcb_extension_t; /**< Opaque structure used as key for xcb_get_extension_data_t. */
+
+
+/**
+ * @brief Listen for a special event
+ */
+xcb_special_event_t *xcb_register_for_special_xge(xcb_connection_t *c,
+ xcb_extension_t *ext,
+ uint32_t eid,
+ uint32_t *stamp);
+
+/**
+ * @brief Stop listening for a special event
+ */
+void xcb_unregister_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se);
+
/**
* @brief Return the error for a request, or NULL if none can ever arrive.
* @param c: The connection to the X server.
/* xcb_ext.c */
/**
- * @typedef typedef struct xcb_extension_t xcb_extension_t
- */
-typedef struct xcb_extension_t xcb_extension_t; /**< Opaque structure used as key for xcb_get_extension_data_t. */
-
-/**
* @brief Caches reply information from QueryExtension requests.
* @param c: The connection.
* @param ext: The extension data.
* @return XCB_CONN_CLOSED_MEM_INSUFFICIENT, when memory not available.
* @return XCB_CONN_CLOSED_REQ_LEN_EXCEED, exceeding request length that server accepts.
* @return XCB_CONN_CLOSED_PARSE_ERR, error during parsing display string.
+ * @return XCB_CONN_CLOSED_INVALID_SCREEN, because the server does not have a screen matching the display.
*/
int xcb_connection_has_error(xcb_connection_t *c);
/* Connection management: the core of XCB. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
+#include <limits.h>
#include "xcb.h"
#include "xcbint.h"
static const int xcb_con_error = XCB_CONN_ERROR;
static const int xcb_con_closed_mem_er = XCB_CONN_CLOSED_MEM_INSUFFICIENT;
static const int xcb_con_closed_parse_er = XCB_CONN_CLOSED_PARSE_ERR;
+static const int xcb_con_closed_screen_er = XCB_CONN_CLOSED_INVALID_SCREEN;
static int set_fd_flags(const int fd)
{
i++;
}
#else
- n = writev(c->fd, *vector, *count);
- if(n < 0 && errno == EAGAIN)
- return 1;
+ n = *count;
+ if (n > IOV_MAX)
+ n = IOV_MAX;
+
+#if HAVE_SENDMSG
+ if (c->out.out_fd.nfd) {
+ union {
+ struct cmsghdr cmsghdr;
+ char buf[CMSG_SPACE(XCB_MAX_PASS_FD * sizeof(int))];
+ } cmsgbuf;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = *vector,
+ .msg_iovlen = n,
+ .msg_control = cmsgbuf.buf,
+ .msg_controllen = CMSG_LEN(c->out.out_fd.nfd * sizeof (int)),
+ };
+ int i;
+ struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
+
+ hdr->cmsg_len = msg.msg_controllen;
+ hdr->cmsg_level = SOL_SOCKET;
+ hdr->cmsg_type = SCM_RIGHTS;
+ memcpy(CMSG_DATA(hdr), c->out.out_fd.fd, c->out.out_fd.nfd * sizeof (int));
+
+ n = sendmsg(c->fd, &msg, 0);
+ if(n < 0 && errno == EAGAIN)
+ return 1;
+ for (i = 0; i < c->out.out_fd.nfd; i++)
+ close(c->out.out_fd.fd[i]);
+ c->out.out_fd.nfd = 0;
+ } else
+#endif
+ {
+ n = writev(c->fd, *vector, n);
+ if(n < 0 && errno == EAGAIN)
+ return 1;
+ }
+
#endif /* _WIN32 */
if(n <= 0)
{
return (xcb_connection_t *) &xcb_con_closed_parse_er;
}
+ case XCB_CONN_CLOSED_INVALID_SCREEN:
+ {
+ return (xcb_connection_t *) &xcb_con_closed_screen_er;
+ }
case XCB_CONN_ERROR:
default:
{
if(ret)
{
+ /* The code allows two threads to call select()/poll() at the same time.
+ * First thread just wants to read, a second thread wants to write, too.
+ * We have to make sure that we don't steal the reading thread's reply
+ * and let it get stuck in select()/poll().
+ * So a thread may read if either:
+ * - There is no other thread that wants to read (the above situation
+ * did not occur).
+ * - It is the reading thread (above situation occurred).
+ */
+ int may_read = c->in.reading == 1 || !count;
#if USE_POLL
- if((fd.revents & POLLIN) == POLLIN)
+ if(may_read && (fd.revents & POLLIN) != 0)
#else
- if(FD_ISSET(c->fd, &rfds))
+ if(may_read && FD_ISSET(c->fd, &rfds))
#endif
ret = ret && _xcb_in_read(c);
#if USE_POLL
- if((fd.revents & POLLOUT) == POLLOUT)
+ if((fd.revents & POLLOUT) != 0)
#else
if(FD_ISSET(c->fd, &wfds))
#endif
/* A cache for QueryExtension results. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <string.h>
/* Stuff that reads stuff from the server. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <assert.h>
#include <string.h>
#include <stdlib.h>
struct event_list *next;
};
+struct xcb_special_event {
+
+ struct xcb_special_event *next;
+
+ /* Match XGE events for the specific extension and event ID (the
+ * first 32 bit word after evtype)
+ */
+ uint8_t extension;
+ uint32_t eid;
+ uint32_t *stamp;
+
+ struct event_list *events;
+ struct event_list **events_tail;
+
+ pthread_cond_t special_event_cond;
+};
+
struct reply_list {
void *reply;
struct reply_list *next;
struct reader_list *next;
} reader_list;
+typedef struct special_list {
+ xcb_special_event_t *se;
+ struct special_list *next;
+} special_list;
+
static void remove_finished_readers(reader_list **prev_reader, uint64_t completed)
{
while(*prev_reader && XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, completed))
}
}
+#if HAVE_SENDMSG
+static int read_fds(xcb_connection_t *c, int *fds, int nfd)
+{
+ int *ifds = &c->in.in_fd.fd[c->in.in_fd.ifd];
+ int infd = c->in.in_fd.nfd - c->in.in_fd.ifd;
+
+ if (nfd > infd)
+ return 0;
+ memcpy(fds, ifds, nfd * sizeof (int));
+ c->in.in_fd.ifd += nfd;
+ return 1;
+}
+#endif
+
+typedef struct xcb_ge_special_event_t {
+ uint8_t response_type; /**< */
+ uint8_t extension; /**< */
+ uint16_t sequence; /**< */
+ uint32_t length; /**< */
+ uint16_t evtype; /**< */
+ uint8_t pad0[2]; /**< */
+ uint32_t eid; /**< */
+ uint8_t pad1[16]; /**< */
+} xcb_ge_special_event_t;
+
+static int event_special(xcb_connection_t *c,
+ struct event_list *event)
+{
+ struct xcb_special_event *special_event;
+ struct xcb_ge_special_event_t *ges = (void *) event->event;
+
+ /* Special events are always XGE events */
+ if ((ges->response_type & 0x7f) != XCB_XGE_EVENT)
+ return 0;
+
+ for (special_event = c->in.special_events;
+ special_event;
+ special_event = special_event->next)
+ {
+ if (ges->extension == special_event->extension &&
+ ges->eid == special_event->eid)
+ {
+ *special_event->events_tail = event;
+ special_event->events_tail = &event->next;
+ if (special_event->stamp)
+ ++(*special_event->stamp);
+ pthread_cond_signal(&special_event->special_event_cond);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static int read_packet(xcb_connection_t *c)
{
xcb_generic_reply_t genrep;
- int length = 32;
- int eventlength = 0; /* length after first 32 bytes for GenericEvents */
+ uint64_t length = 32;
+ uint64_t eventlength = 0; /* length after first 32 bytes for GenericEvents */
+ int nfd = 0; /* Number of file descriptors attached to the reply */
+ uint64_t bufsize;
void *buf;
pending_reply *pend = 0;
struct event_list *event;
genrep.length = p[2] * p[3] * 2;
}
length += genrep.length * 4;
+
+ /* XXX a bit of a hack -- we "know" that all FD replys place
+ * the number of fds in the pad0 byte */
+ if (pend && pend->flags & XCB_REQUEST_REPLY_FDS)
+ nfd = genrep.pad0;
}
/* XGE events may have sizes > 32 */
if ((genrep.response_type & 0x7f) == XCB_XGE_EVENT)
eventlength = genrep.length * 4;
- buf = malloc(length + eventlength +
- (genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t)));
+ bufsize = length + eventlength + nfd * sizeof(int) +
+ (genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t));
+ if (bufsize < INT32_MAX)
+ buf = malloc((size_t) bufsize);
+ else
+ buf = NULL;
if(!buf)
{
_xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT);
}
}
+#if HAVE_SENDMSG
+ if (nfd)
+ {
+ if (!read_fds(c, (int *) &((char *) buf)[length], nfd))
+ {
+ free(buf);
+ return 0;
+ }
+ }
+#endif
+
if(pend && (pend->flags & XCB_REQUEST_DISCARD_REPLY))
{
free(buf);
}
event->event = buf;
event->next = 0;
- *c->in.events_tail = event;
- c->in.events_tail = &event->next;
- pthread_cond_signal(&c->in.event_cond);
+
+ if (!event_special(c, event)) {
+ *c->in.events_tail = event;
+ c->in.events_tail = &event->next;
+ pthread_cond_signal(&c->in.event_cond);
+ }
return 1; /* I have something for you... */
}
}
}
+static void insert_special(special_list **prev_special, special_list *special, xcb_special_event_t *se)
+{
+ special->se = se;
+ special->next = *prev_special;
+ *prev_special = special;
+}
+
+static void remove_special(special_list **prev_special, special_list *special)
+{
+ while(*prev_special)
+ {
+ if(*prev_special == special)
+ {
+ *prev_special = (*prev_special)->next;
+ break;
+ }
+ prev_special = &(*prev_special)->next;
+ }
+}
+
static void *wait_for_reply(xcb_connection_t *c, uint64_t request, xcb_generic_error_t **e)
{
void *ret = 0;
return ret;
}
+int *xcb_get_reply_fds(xcb_connection_t *c, void *reply, size_t reply_size)
+{
+ return (int *) (&((char *) reply)[reply_size]);
+}
+
static void insert_pending_discard(xcb_connection_t *c, pending_reply **prev_next, uint64_t seq)
{
pending_reply *pend;
return ret;
}
+static xcb_generic_event_t *get_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_generic_event_t *event = NULL;
+ struct event_list *events;
+
+ if ((events = se->events) != NULL) {
+ event = events->event;
+ if (!(se->events = events->next))
+ se->events_tail = &se->events;
+ free (events);
+ }
+ return event;
+}
+
+xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_generic_event_t *event;
+
+ if(c->has_error)
+ return 0;
+ pthread_mutex_lock(&c->iolock);
+ event = get_special_event(c, se);
+ pthread_mutex_unlock(&c->iolock);
+ return event;
+}
+
+xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ special_list special;
+ xcb_generic_event_t *event;
+
+ if(c->has_error)
+ return 0;
+ pthread_mutex_lock(&c->iolock);
+
+ insert_special(&c->in.special_waiters, &special, se);
+
+ /* get_special_event returns 0 on empty list. */
+ while(!(event = get_special_event(c, se)))
+ if(!_xcb_conn_wait(c, &se->special_event_cond, 0, 0))
+ break;
+
+ remove_special(&c->in.special_waiters, &special);
+
+ _xcb_in_wake_up_next_reader(c);
+ pthread_mutex_unlock(&c->iolock);
+ return event;
+}
+
+xcb_special_event_t *
+xcb_register_for_special_xge(xcb_connection_t *c,
+ xcb_extension_t *ext,
+ uint32_t eid,
+ uint32_t *stamp)
+{
+ xcb_special_event_t *se;
+ const xcb_query_extension_reply_t *ext_reply;
+
+ if(c->has_error)
+ return NULL;
+ ext_reply = xcb_get_extension_data(c, ext);
+ if (!ext_reply)
+ return NULL;
+ pthread_mutex_lock(&c->iolock);
+ for (se = c->in.special_events; se; se = se->next) {
+ if (se->extension == ext_reply->major_opcode &&
+ se->eid == eid) {
+ pthread_mutex_unlock(&c->iolock);
+ return NULL;
+ }
+ }
+ se = calloc(1, sizeof(xcb_special_event_t));
+ if (!se) {
+ pthread_mutex_unlock(&c->iolock);
+ return NULL;
+ }
+
+ se->extension = ext_reply->major_opcode;
+ se->eid = eid;
+
+ se->events = NULL;
+ se->events_tail = &se->events;
+ se->stamp = stamp;
+
+ pthread_cond_init(&se->special_event_cond, 0);
+
+ se->next = c->in.special_events;
+ c->in.special_events = se;
+ pthread_mutex_unlock(&c->iolock);
+ return se;
+}
+
+void
+xcb_unregister_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_special_event_t *s, **prev;
+ struct event_list *events, *next;
+
+ if (!se)
+ return;
+
+ if (c->has_error)
+ return;
+
+ pthread_mutex_lock(&c->iolock);
+
+ for (prev = &c->in.special_events; (s = *prev) != NULL; prev = &(s->next)) {
+ if (s == se) {
+ *prev = se->next;
+ for (events = se->events; events; events = next) {
+ next = events->next;
+ free (events->event);
+ free (events);
+ }
+ pthread_cond_destroy(&se->special_event_cond);
+ free (se);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&c->iolock);
+}
+
/* Private interface */
int _xcb_in_init(_xcb_in *in)
int pthreadret;
if(c->in.readers)
pthreadret = pthread_cond_signal(c->in.readers->data);
+ else if(c->in.special_waiters)
+ pthreadret = pthread_cond_signal(&c->in.special_waiters->se->special_event_cond);
else
pthreadret = pthread_cond_signal(&c->in.event_cond);
assert(pthreadret == 0);
int _xcb_in_read(xcb_connection_t *c)
{
- int n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len, 0);
- if(n > 0)
+ int n;
+
+#if HAVE_SENDMSG
+ struct iovec iov = {
+ .iov_base = c->in.queue + c->in.queue_len,
+ .iov_len = sizeof(c->in.queue) - c->in.queue_len,
+ };
+ union {
+ struct cmsghdr cmsghdr;
+ char buf[CMSG_SPACE(XCB_MAX_PASS_FD * sizeof(int))];
+ } cmsgbuf;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = cmsgbuf.buf,
+ .msg_controllen = CMSG_SPACE(sizeof(int) * (XCB_MAX_PASS_FD - c->in.in_fd.nfd)),
+ };
+ n = recvmsg(c->fd, &msg, 0);
+
+ /* Check for truncation errors. Only MSG_CTRUNC is
+ * probably possible here, which would indicate that
+ * the sender tried to transmit more than XCB_MAX_PASS_FD
+ * file descriptors.
+ */
+ if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
+ _xcb_conn_shutdown(c, XCB_CONN_CLOSED_FDPASSING_FAILED);
+ return 0;
+ }
+#else
+ n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len, 0);
+#endif
+ if(n > 0) {
+#if HAVE_SENDMSG
+ struct cmsghdr *hdr;
+
+ if (msg.msg_controllen >= sizeof (struct cmsghdr)) {
+ for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
+ if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
+ int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
+ memcpy(&c->in.in_fd.fd[c->in.in_fd.nfd], CMSG_DATA(hdr), nfd * sizeof (int));
+ c->in.in_fd.nfd += nfd;
+ }
+ }
+ }
+#endif
c->in.queue_len += n;
+ }
while(read_packet(c))
/* empty */;
+#if HAVE_SENDMSG
+ if (c->in.in_fd.nfd) {
+ c->in.in_fd.nfd -= c->in.in_fd.ifd;
+ memmove(&c->in.in_fd.fd[0],
+ &c->in.in_fd.fd[c->in.in_fd.ifd],
+ c->in.in_fd.nfd * sizeof (int));
+ c->in.in_fd.ifd = 0;
+
+ /* If we have any left-over file descriptors after emptying
+ * the input buffer, then the server sent some that we weren't
+ * expecting. Close them and mark the connection as broken;
+ */
+ if (c->in.queue_len == 0 && c->in.in_fd.nfd != 0) {
+ int i;
+ for (i = 0; i < c->in.in_fd.nfd; i++)
+ close(c->in.in_fd.fd[i]);
+ _xcb_conn_shutdown(c, XCB_CONN_CLOSED_FDPASSING_FAILED);
+ return 0;
+ }
+ }
+#endif
#ifndef _WIN32
if((n > 0) || (n < 0 && errno == EAGAIN))
#else
/* A generic implementation of a list of void-pointers. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include "xcb.h"
/* Private interface */
-_xcb_map *_xcb_map_new()
+_xcb_map *_xcb_map_new(void)
{
_xcb_map *list;
list = malloc(sizeof(_xcb_map));
/* Stuff that sends stuff to the server. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
return request;
}
+void
+xcb_send_fd(xcb_connection_t *c, int fd)
+{
+#if HAVE_SENDMSG
+ if (c->has_error)
+ return;
+ pthread_mutex_lock(&c->iolock);
+ while (c->out.out_fd.nfd == XCB_MAX_PASS_FD) {
+ _xcb_out_flush_to(c, c->out.request);
+ if (c->has_error)
+ break;
+ }
+ if (!c->has_error)
+ c->out.out_fd.fd[c->out.out_fd.nfd++] = fd;
+ pthread_mutex_unlock(&c->iolock);
+#endif
+}
+
int xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), void *closure, int flags, uint64_t *sent)
{
int ret;
* write requests, so keep flushing until we're done
*/
do
- ret = _xcb_out_flush_to(c, c->out.request);
+ ret = _xcb_out_flush_to(c, c->out.request);
while (ret && c->out.request != c->out.request_written);
if(ret)
{
/* Utility functions implementable using only public APIs. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <assert.h>
#include <sys/types.h>
#include <limits.h>
#include "xcbext.h"
#include "xcbint.h"
-/* must be after "xcbint.h" to get autoconf #defines */
#if defined(HAVE_TSOL_LABEL_H) && defined(HAVE_IS_SYSTEM_LABELED)
# include <tsol/label.h>
# include <sys/stat.h>
static int _xcb_open(const char *host, char *protocol, const int display)
{
int fd;
+#ifdef __hpux
+ static const char unix_base[] = "/usr/spool/sockets/X11/";
+#else
static const char unix_base[] = "/tmp/.X11-unix/X";
+#endif
const char *base = unix_base;
size_t filelen;
char *file = NULL;
if(strncmp(host, "/tmp/launch", 11) == 0) {
base = host;
host = "";
- protocol = NULL;
+ protocol = "unix";
}
#endif
else
c = xcb_connect_to_fd(fd, 0);
+ if(c->has_error)
+ goto out;
+
+ /* Make sure requested screen number is in bounds for this server */
+ if((screenp != NULL) && (*screenp >= (int) c->setup->roots_len)) {
+ xcb_disconnect(c);
+ c = _xcb_conn_ret_error(XCB_CONN_CLOSED_INVALID_SCREEN);
+ goto out;
+ }
+
out:
free(host);
free(protocol);
/* XID allocators. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <assert.h>
#include <stdlib.h>
#include "xcb.h"
enum xcb_send_request_flags_t {
XCB_REQUEST_CHECKED = 1 << 0,
XCB_REQUEST_RAW = 1 << 1,
- XCB_REQUEST_DISCARD_REPLY = 1 << 2
+ XCB_REQUEST_DISCARD_REPLY = 1 << 2,
+ XCB_REQUEST_REPLY_FDS = 1 << 3
};
unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
+void xcb_send_fd(xcb_connection_t *c, int fd);
+
/* xcb_take_socket allows external code to ask XCB for permission to
* take over the write side of the socket and send raw data with
* xcb_writev. xcb_take_socket provides the sequence number of the last
void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e);
int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error);
+int *xcb_get_reply_fds(xcb_connection_t *c, void *reply, size_t replylen);
/* xcb_util.c */
/* xcb_out.c */
+#if HAVE_SENDMSG
+#define XCB_MAX_PASS_FD 16
+
+typedef struct _xcb_fd {
+ int fd[XCB_MAX_PASS_FD];
+ int nfd;
+ int ifd;
+} _xcb_fd;
+#endif
+
typedef struct _xcb_out {
pthread_cond_t cond;
int writing;
xcb_big_requests_enable_cookie_t cookie;
uint32_t value;
} maximum_request_length;
+#if HAVE_SENDMSG
+ _xcb_fd out_fd;
+#endif
} _xcb_out;
int _xcb_out_init(_xcb_out *out);
struct event_list *events;
struct event_list **events_tail;
struct reader_list *readers;
+ struct special_list *special_waiters;
struct pending_reply *pending_replies;
struct pending_reply **pending_replies_tail;
+#if HAVE_SENDMSG
+ _xcb_fd in_fd;
+#endif
+ struct xcb_special_event *special_events;
} _xcb_in;
int _xcb_in_init(_xcb_in *in);
check_PROGRAMS = check_all
check_all_SOURCES = check_all.c check_suites.h check_public.c
-all-local::
- $(RM) CheckLog*.xml
-
check-local: check-TESTS
$(RM) CheckLog.html
- if test x$(HTML_CHECK_RESULT) = xtrue; then \
+ if test x$(HTML_CHECK_RESULT) = xyes; then \
$(XSLTPROC) $(srcdir)/CheckLog.xsl CheckLog*.xml > CheckLog.html; \
else \
touch CheckLog.html; \
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: XCB DRI3
+Description: XCB DRI3 Extension
+Version: @PACKAGE_VERSION@
+Requires: xcb
+Libs: -L${libdir} -lxcb-dri3
+Cflags: -I${includedir}
--- /dev/null
+prefix=@prefix@
+
+exec_prefix=@exec_prefix@
+
+libdir=@libdir@
+
+includedir=@includedir@
+
+
+
+Name: XCB HWA
+
+Description: XCB HWA Extension
+
+Version: @PACKAGE_VERSION@
+
+Requires: xcb
+
+Libs: -L${libdir} -lxcb-hwa
+
+Cflags: -I${includedir}
--- /dev/null
+prefix=@prefix@
+
+exec_prefix=@exec_prefix@
+
+libdir=@libdir@
+
+includedir=@includedir@
+
+
+
+Name: XCB HWC
+
+Description: XCB HWC Extension
+
+Version: @PACKAGE_VERSION@
+
+Requires: xcb
+
+Libs: -L${libdir} -lxcb-hwc
+
+Cflags: -I${includedir}
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: XCB Present
+Description: XCB Present Extension
+Version: @PACKAGE_VERSION@
+Requires: xcb
+Libs: -L${libdir} -lxcb-present
+Cflags: -I${includedir}