Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7dae7ba3f9 | ||
|
33d2404d0b | ||
|
a2322e3cdc | ||
|
e7aa524bcb | ||
|
be65846cf1 | ||
|
d698fa3aa3 | ||
|
6d630cb9bb | ||
|
a22ffa399a | ||
|
53087b12e2 | ||
|
568cf48f00 | ||
|
bbe7f95e07 | ||
|
aa6ac19ff4 | ||
|
9aa5b192ba | ||
|
db3d97628e | ||
|
37f849dcad | ||
|
31ae0b83d5 | ||
|
d2eefb77b9 | ||
|
1ac2822135 | ||
|
75680fde0d |
|
@ -16,9 +16,15 @@ endif
|
||||||
if BUILD_DRI2
|
if BUILD_DRI2
|
||||||
pkgconfig_DATA += xcb-dri2.pc
|
pkgconfig_DATA += xcb-dri2.pc
|
||||||
endif
|
endif
|
||||||
|
if BUILD_DRI3
|
||||||
|
pkgconfig_DATA += xcb-dri3.pc
|
||||||
|
endif
|
||||||
if BUILD_GLX
|
if BUILD_GLX
|
||||||
pkgconfig_DATA += xcb-glx.pc
|
pkgconfig_DATA += xcb-glx.pc
|
||||||
endif
|
endif
|
||||||
|
if BUILD_PRESENT
|
||||||
|
pkgconfig_DATA += xcb-present.pc
|
||||||
|
endif
|
||||||
if BUILD_RANDR
|
if BUILD_RANDR
|
||||||
pkgconfig_DATA += xcb-randr.pc
|
pkgconfig_DATA += xcb-randr.pc
|
||||||
endif
|
endif
|
||||||
|
|
6
NEWS
6
NEWS
|
@ -1,3 +1,9 @@
|
||||||
|
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)
|
Release 1.9 (2012-10-05)
|
||||||
========================
|
========================
|
||||||
|
|
||||||
|
|
70
configure.ac
70
configure.ac
|
@ -4,18 +4,19 @@
|
||||||
# Initialize Autoconf
|
# Initialize Autoconf
|
||||||
AC_PREREQ(2.57)
|
AC_PREREQ(2.57)
|
||||||
AC_INIT([libxcb],
|
AC_INIT([libxcb],
|
||||||
1.9,
|
1.9.3,
|
||||||
[xcb@lists.freedesktop.org])
|
[xcb@lists.freedesktop.org])
|
||||||
AC_CONFIG_SRCDIR([xcb.pc.in])
|
AC_CONFIG_SRCDIR([xcb.pc.in])
|
||||||
# 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
|
|
||||||
|
|
||||||
# Initialize Automake
|
# Initialize Automake
|
||||||
AM_INIT_AUTOMAKE([foreign dist-bzip2])
|
AM_INIT_AUTOMAKE([foreign dist-bzip2])
|
||||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
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])
|
AM_PATH_PYTHON([2.6])
|
||||||
|
|
||||||
PKG_CHECK_MODULES(CHECK, [check >= 0.9.4], [HAVE_CHECK=yes], [HAVE_CHECK=no])
|
PKG_CHECK_MODULES(CHECK, [check >= 0.9.4], [HAVE_CHECK=yes], [HAVE_CHECK=no])
|
||||||
|
@ -41,7 +42,7 @@ fi
|
||||||
AC_SUBST(HTML_CHECK_RESULT)
|
AC_SUBST(HTML_CHECK_RESULT)
|
||||||
|
|
||||||
# Checks for pkg-config packages
|
# Checks for pkg-config packages
|
||||||
PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.7)
|
PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.9)
|
||||||
NEEDED="pthread-stubs xau >= 0.99.2"
|
NEEDED="pthread-stubs xau >= 0.99.2"
|
||||||
PKG_CHECK_MODULES(NEEDED, $NEEDED)
|
PKG_CHECK_MODULES(NEEDED, $NEEDED)
|
||||||
|
|
||||||
|
@ -81,6 +82,55 @@ AC_HEADER_STDC
|
||||||
AC_SEARCH_LIBS(getaddrinfo, socket)
|
AC_SEARCH_LIBS(getaddrinfo, socket)
|
||||||
AC_SEARCH_LIBS(connect, 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"
|
have_win32="no"
|
||||||
lt_enable_auto_import=""
|
lt_enable_auto_import=""
|
||||||
case $host_os in
|
case $host_os in
|
||||||
|
@ -128,7 +178,7 @@ xcbincludedir='${includedir}/xcb'
|
||||||
AC_SUBST(xcbincludedir)
|
AC_SUBST(xcbincludedir)
|
||||||
|
|
||||||
if test "x$GCC" = xyes ; then
|
if test "x$GCC" = xyes ; then
|
||||||
CWARNFLAGS="-Wall -pedantic -Wpointer-arith \
|
CWARNFLAGS="-Wall -Wpointer-arith \
|
||||||
-Wstrict-prototypes -Wmissing-declarations -Wnested-externs"
|
-Wstrict-prototypes -Wmissing-declarations -Wnested-externs"
|
||||||
else
|
else
|
||||||
AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"])
|
AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"])
|
||||||
|
@ -178,7 +228,9 @@ XCB_EXTENSION(Composite, "yes")
|
||||||
XCB_EXTENSION(Damage, "yes")
|
XCB_EXTENSION(Damage, "yes")
|
||||||
XCB_EXTENSION(DPMS, "yes")
|
XCB_EXTENSION(DPMS, "yes")
|
||||||
XCB_EXTENSION(DRI2, "yes")
|
XCB_EXTENSION(DRI2, "yes")
|
||||||
|
XCB_EXTENSION(DRI3, "$sendfds")
|
||||||
XCB_EXTENSION(GLX, "yes")
|
XCB_EXTENSION(GLX, "yes")
|
||||||
|
XCB_EXTENSION(Present, "yes")
|
||||||
XCB_EXTENSION(RandR, "yes")
|
XCB_EXTENSION(RandR, "yes")
|
||||||
XCB_EXTENSION(Record, "yes")
|
XCB_EXTENSION(Record, "yes")
|
||||||
XCB_EXTENSION(Render, "yes")
|
XCB_EXTENSION(Render, "yes")
|
||||||
|
@ -222,7 +274,9 @@ xcb-composite.pc
|
||||||
xcb-damage.pc
|
xcb-damage.pc
|
||||||
xcb-dpms.pc
|
xcb-dpms.pc
|
||||||
xcb-dri2.pc
|
xcb-dri2.pc
|
||||||
|
xcb-dri3.pc
|
||||||
xcb-glx.pc
|
xcb-glx.pc
|
||||||
|
xcb-present.pc
|
||||||
xcb-randr.pc
|
xcb-randr.pc
|
||||||
xcb-record.pc
|
xcb-record.pc
|
||||||
xcb-render.pc
|
xcb-render.pc
|
||||||
|
@ -257,6 +311,7 @@ echo " Package: ${PACKAGE_NAME} ${PACKAGE_VERSION}"
|
||||||
echo ""
|
echo ""
|
||||||
echo " Configuration"
|
echo " Configuration"
|
||||||
echo " XDM support.........: ${have_xdmcp}"
|
echo " XDM support.........: ${have_xdmcp}"
|
||||||
|
echo " sendmsg fd passing..: ${sendfds}"
|
||||||
echo " Build unit tests....: ${HAVE_CHECK}"
|
echo " Build unit tests....: ${HAVE_CHECK}"
|
||||||
echo " XCB buffer size.....: ${xcb_queue_buffer_size}"
|
echo " XCB buffer size.....: ${xcb_queue_buffer_size}"
|
||||||
echo ""
|
echo ""
|
||||||
|
@ -265,6 +320,7 @@ echo " Composite...........: ${BUILD_COMPOSITE}"
|
||||||
echo " Damage..............: ${BUILD_DAMAGE}"
|
echo " Damage..............: ${BUILD_DAMAGE}"
|
||||||
echo " Dpms................: ${BUILD_DPMS}"
|
echo " Dpms................: ${BUILD_DPMS}"
|
||||||
echo " Dri2................: ${BUILD_DRI2}"
|
echo " Dri2................: ${BUILD_DRI2}"
|
||||||
|
echo " Dri3................: ${BUILD_DRI3}"
|
||||||
echo " Glx.................: ${BUILD_GLX}"
|
echo " Glx.................: ${BUILD_GLX}"
|
||||||
echo " Randr...............: ${BUILD_RANDR}"
|
echo " Randr...............: ${BUILD_RANDR}"
|
||||||
echo " Record..............: ${BUILD_RECORD}"
|
echo " Record..............: ${BUILD_RECORD}"
|
||||||
|
|
|
@ -3,7 +3,9 @@ composite.*
|
||||||
damage.*
|
damage.*
|
||||||
dpms.*
|
dpms.*
|
||||||
dri2.*
|
dri2.*
|
||||||
|
dri3.*
|
||||||
glx.*
|
glx.*
|
||||||
|
present.*
|
||||||
randr.*
|
randr.*
|
||||||
record.*
|
record.*
|
||||||
render.*
|
render.*
|
||||||
|
|
|
@ -56,6 +56,22 @@ libxcb_dri2_la_LIBADD = $(XCB_LIBS)
|
||||||
nodist_libxcb_dri2_la_SOURCES = dri2.c dri2.h
|
nodist_libxcb_dri2_la_SOURCES = dri2.c dri2.h
|
||||||
endif
|
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
|
EXTSOURCES += glx.c
|
||||||
if BUILD_GLX
|
if BUILD_GLX
|
||||||
lib_LTLIBRARIES += libxcb-glx.la
|
lib_LTLIBRARIES += libxcb-glx.la
|
||||||
|
@ -233,7 +249,7 @@ EXTRA_DIST = $(STATIC_MANS)
|
||||||
BUILT_SOURCES = $(EXTSOURCES) $(BUILT_MANS)
|
BUILT_SOURCES = $(EXTSOURCES) $(BUILT_MANS)
|
||||||
CLEANFILES = $(EXTSOURCES) $(EXTHEADERS) $(BUILT_MANS)
|
CLEANFILES = $(EXTSOURCES) $(EXTHEADERS) $(BUILT_MANS)
|
||||||
|
|
||||||
$(EXTSOURCES): c_client.py
|
$(EXTSOURCES): c_client.py $(XCBPROTO_XCBINCLUDEDIR)/$(@:.c=.xml)
|
||||||
$(PYTHON) $(srcdir)/c_client.py -p $(XCBPROTO_XCBPYTHONDIR) $(XCBPROTO_XCBINCLUDEDIR)/$(@:.c=.xml)
|
$(PYTHON) $(srcdir)/c_client.py -p $(XCBPROTO_XCBPYTHONDIR) $(XCBPROTO_XCBINCLUDEDIR)/$(@:.c=.xml)
|
||||||
|
|
||||||
$(man_MANS): $(EXTSOURCES)
|
$(man_MANS): $(EXTSOURCES)
|
||||||
|
|
104
src/c_client.py
104
src/c_client.py
|
@ -303,6 +303,7 @@ def _c_type_setup(self, name, postfix):
|
||||||
self.c_reply_name = _n(name + ('reply',))
|
self.c_reply_name = _n(name + ('reply',))
|
||||||
self.c_reply_type = _t(name + ('reply',))
|
self.c_reply_type = _t(name + ('reply',))
|
||||||
self.c_cookie_type = _t(name + ('cookie',))
|
self.c_cookie_type = _t(name + ('cookie',))
|
||||||
|
self.c_reply_fds_name = _n(name + ('reply_fds',))
|
||||||
|
|
||||||
self.need_aux = False
|
self.need_aux = False
|
||||||
self.need_serialize = False
|
self.need_serialize = False
|
||||||
|
@ -687,10 +688,20 @@ def _c_serialize_helper_switch(context, self, complex_name,
|
||||||
switch_expr = _c_accessor_get_expr(self.expr, None)
|
switch_expr = _c_accessor_get_expr(self.expr, None)
|
||||||
|
|
||||||
for b in self.bitcases:
|
for b in self.bitcases:
|
||||||
bitcase_expr = _c_accessor_get_expr(b.type.expr, None)
|
len_expr = len(b.type.expr)
|
||||||
code_lines.append(' if(%s & %s) {' % (switch_expr, bitcase_expr))
|
for n, expr in enumerate(b.type.expr):
|
||||||
# code_lines.append(' printf("switch %s: entering bitcase section %s (mask=%%%%d)...\\n", %s);' %
|
bitcase_expr = _c_accessor_get_expr(expr, None)
|
||||||
# (self.name[-1], b.type.name[-1], bitcase_expr))
|
# 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
|
b_prefix = prefix
|
||||||
if b.type.has_name:
|
if b.type.has_name:
|
||||||
b_prefix = prefix + [(b.c_field_name, '.', b.type)]
|
b_prefix = prefix + [(b.c_field_name, '.', b.type)]
|
||||||
|
@ -1825,7 +1836,7 @@ def c_union(self, name):
|
||||||
_c_complex(self)
|
_c_complex(self)
|
||||||
_c_iterator(self, name)
|
_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.
|
Declares a request function.
|
||||||
'''
|
'''
|
||||||
|
@ -1854,6 +1865,12 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
|
||||||
# What flag is passed to xcb_request
|
# What flag is passed to xcb_request
|
||||||
func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
|
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
|
# Global extension id variable or NULL for xproto
|
||||||
func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
|
func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
|
||||||
|
|
||||||
|
@ -2139,6 +2156,10 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
|
||||||
# no padding necessary - _serialize() keeps track of padding automatically
|
# no padding necessary - _serialize() keeps track of padding automatically
|
||||||
|
|
||||||
_c(' ')
|
_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)
|
_c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
|
||||||
|
|
||||||
# free dyn. all. data, if any
|
# free dyn. all. data, if any
|
||||||
|
@ -2242,6 +2263,51 @@ def _c_reply(self, name):
|
||||||
|
|
||||||
_c('}')
|
_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):
|
def _c_opcode(name, opcode):
|
||||||
'''
|
'''
|
||||||
Declares the opcode define for requests, events, and errors.
|
Declares the opcode define for requests, events, and errors.
|
||||||
|
@ -2802,14 +2868,17 @@ def c_request(self, name):
|
||||||
# Reply structure definition
|
# Reply structure definition
|
||||||
_c_complex(self.reply)
|
_c_complex(self.reply)
|
||||||
# Request prototypes
|
# Request prototypes
|
||||||
_c_request_helper(self, name, self.c_cookie_type, False, True)
|
has_fds = _c_reply_has_fds(self.reply)
|
||||||
_c_request_helper(self, name, self.c_cookie_type, False, False)
|
_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:
|
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, True, True, has_fds)
|
||||||
_c_request_helper(self, name, self.c_cookie_type, False, False, True)
|
_c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
|
||||||
# Reply accessors
|
# Reply accessors
|
||||||
_c_accessors(self.reply, name + ('reply',), name)
|
_c_accessors(self.reply, name + ('reply',), name)
|
||||||
_c_reply(self, name)
|
_c_reply(self, name)
|
||||||
|
if has_fds:
|
||||||
|
_c_reply_fds(self, name)
|
||||||
else:
|
else:
|
||||||
# Request prototypes
|
# Request prototypes
|
||||||
_c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
|
_c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
|
||||||
|
@ -2827,6 +2896,23 @@ def c_event(self, name):
|
||||||
'''
|
'''
|
||||||
Exported function that handles event declarations.
|
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',))
|
_c_type_setup(self, name, ('event',))
|
||||||
|
|
||||||
# Opcode define
|
# Opcode define
|
||||||
|
|
58
src/xcb.h
58
src/xcb.h
|
@ -87,6 +87,9 @@ extern "C" {
|
||||||
/** Connection closed because the server does not have a screen matching the display. */
|
/** Connection closed because the server does not have a screen matching the display. */
|
||||||
#define XCB_CONN_CLOSED_INVALID_SCREEN 6
|
#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))
|
#define XCB_TYPE_PAD(T,I) (-(I) & (sizeof(T) > 4 ? 3 : sizeof(T) - 1))
|
||||||
|
|
||||||
/* Opaque structures */
|
/* Opaque structures */
|
||||||
|
@ -137,23 +140,6 @@ typedef struct {
|
||||||
uint32_t full_sequence; /**< full sequence */
|
uint32_t full_sequence; /**< full sequence */
|
||||||
} xcb_generic_event_t;
|
} xcb_generic_event_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief GE event
|
|
||||||
*
|
|
||||||
* An event as sent by the XGE extension. The length field specifies the
|
|
||||||
* number of 4-byte blocks trailing the struct.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
uint8_t response_type; /**< Type of the response */
|
|
||||||
uint8_t pad0; /**< Padding */
|
|
||||||
uint16_t sequence; /**< Sequence number */
|
|
||||||
uint32_t length;
|
|
||||||
uint16_t event_type;
|
|
||||||
uint16_t pad1;
|
|
||||||
uint32_t pad[5]; /**< Padding */
|
|
||||||
uint32_t full_sequence; /**< full sequence */
|
|
||||||
} xcb_ge_event_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generic error.
|
* @brief Generic error.
|
||||||
*
|
*
|
||||||
|
@ -305,6 +291,39 @@ xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c);
|
||||||
*/
|
*/
|
||||||
xcb_generic_event_t *xcb_poll_for_queued_event(xcb_connection_t *c);
|
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.
|
* @brief Return the error for a request, or NULL if none can ever arrive.
|
||||||
* @param c: The connection to the X server.
|
* @param c: The connection to the X server.
|
||||||
|
@ -342,11 +361,6 @@ void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence);
|
||||||
|
|
||||||
/* xcb_ext.c */
|
/* 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.
|
* @brief Caches reply information from QueryExtension requests.
|
||||||
* @param c: The connection.
|
* @param c: The connection.
|
||||||
|
|
|
@ -214,9 +214,39 @@ static int write_vec(xcb_connection_t *c, struct iovec **vector, int *count)
|
||||||
if (n > IOV_MAX)
|
if (n > IOV_MAX)
|
||||||
n = IOV_MAX;
|
n = IOV_MAX;
|
||||||
|
|
||||||
n = writev(c->fd, *vector, n);
|
#if HAVE_SENDMSG
|
||||||
if(n < 0 && errno == EAGAIN)
|
if (c->out.out_fd.nfd) {
|
||||||
return 1;
|
char cmsgbuf[CMSG_SPACE(sizeof(int) * XCB_MAX_PASS_FD)];
|
||||||
|
struct msghdr msg = {
|
||||||
|
.msg_name = NULL,
|
||||||
|
.msg_namelen = 0,
|
||||||
|
.msg_iov = *vector,
|
||||||
|
.msg_iovlen = n,
|
||||||
|
.msg_control = cmsgbuf,
|
||||||
|
.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 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
if(n <= 0)
|
if(n <= 0)
|
||||||
|
|
301
src/xcb_in.c
301
src/xcb_in.c
|
@ -60,6 +60,23 @@ struct event_list {
|
||||||
struct event_list *next;
|
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 {
|
struct reply_list {
|
||||||
void *reply;
|
void *reply;
|
||||||
struct reply_list *next;
|
struct reply_list *next;
|
||||||
|
@ -90,11 +107,67 @@ static void remove_finished_readers(reader_list **prev_reader, uint64_t complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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)
|
static int read_packet(xcb_connection_t *c)
|
||||||
{
|
{
|
||||||
xcb_generic_reply_t genrep;
|
xcb_generic_reply_t genrep;
|
||||||
int length = 32;
|
uint64_t length = 32;
|
||||||
int eventlength = 0; /* length after first 32 bytes for GenericEvents */
|
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;
|
void *buf;
|
||||||
pending_reply *pend = 0;
|
pending_reply *pend = 0;
|
||||||
struct event_list *event;
|
struct event_list *event;
|
||||||
|
@ -163,14 +236,23 @@ static int read_packet(xcb_connection_t *c)
|
||||||
genrep.length = p[2] * p[3] * 2;
|
genrep.length = p[2] * p[3] * 2;
|
||||||
}
|
}
|
||||||
length += genrep.length * 4;
|
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 */
|
/* XGE events may have sizes > 32 */
|
||||||
if ((genrep.response_type & 0x7f) == XCB_XGE_EVENT)
|
if ((genrep.response_type & 0x7f) == XCB_XGE_EVENT)
|
||||||
eventlength = genrep.length * 4;
|
eventlength = genrep.length * 4;
|
||||||
|
|
||||||
buf = malloc(length + eventlength +
|
bufsize = length + eventlength + nfd * sizeof(int) +
|
||||||
(genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t)));
|
(genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t));
|
||||||
|
if (bufsize < INT32_MAX)
|
||||||
|
buf = malloc((size_t) bufsize);
|
||||||
|
else
|
||||||
|
buf = NULL;
|
||||||
if(!buf)
|
if(!buf)
|
||||||
{
|
{
|
||||||
_xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT);
|
_xcb_conn_shutdown(c, XCB_CONN_CLOSED_MEM_INSUFFICIENT);
|
||||||
|
@ -193,6 +275,17 @@ static int read_packet(xcb_connection_t *c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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))
|
if(pend && (pend->flags & XCB_REQUEST_DISCARD_REPLY))
|
||||||
{
|
{
|
||||||
free(buf);
|
free(buf);
|
||||||
|
@ -232,9 +325,12 @@ static int read_packet(xcb_connection_t *c)
|
||||||
}
|
}
|
||||||
event->event = buf;
|
event->event = buf;
|
||||||
event->next = 0;
|
event->next = 0;
|
||||||
*c->in.events_tail = event;
|
|
||||||
c->in.events_tail = &event->next;
|
if (!event_special(c, event)) {
|
||||||
pthread_cond_signal(&c->in.event_cond);
|
*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... */
|
return 1; /* I have something for you... */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,6 +522,11 @@ void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_
|
||||||
return ret;
|
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)
|
static void insert_pending_discard(xcb_connection_t *c, pending_reply **prev_next, uint64_t seq)
|
||||||
{
|
{
|
||||||
pending_reply *pend;
|
pending_reply *pend;
|
||||||
|
@ -572,6 +673,126 @@ xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t co
|
||||||
return ret;
|
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)
|
||||||
|
{
|
||||||
|
xcb_generic_event_t *event;
|
||||||
|
|
||||||
|
if(c->has_error)
|
||||||
|
return 0;
|
||||||
|
pthread_mutex_lock(&c->iolock);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
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 */
|
/* Private interface */
|
||||||
|
|
||||||
int _xcb_in_init(_xcb_in *in)
|
int _xcb_in_init(_xcb_in *in)
|
||||||
|
@ -660,11 +881,73 @@ void _xcb_in_replies_done(xcb_connection_t *c)
|
||||||
|
|
||||||
int _xcb_in_read(xcb_connection_t *c)
|
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);
|
int n;
|
||||||
if(n > 0)
|
|
||||||
|
#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,
|
||||||
|
};
|
||||||
|
char cmsgbuf[CMSG_SPACE(sizeof(int) * XCB_MAX_PASS_FD)];
|
||||||
|
struct msghdr msg = {
|
||||||
|
.msg_name = NULL,
|
||||||
|
.msg_namelen = 0,
|
||||||
|
.msg_iov = &iov,
|
||||||
|
.msg_iovlen = 1,
|
||||||
|
.msg_control = cmsgbuf,
|
||||||
|
.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;
|
||||||
|
|
||||||
|
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;
|
c->in.queue_len += n;
|
||||||
|
}
|
||||||
while(read_packet(c))
|
while(read_packet(c))
|
||||||
/* empty */;
|
/* 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
|
#ifndef _WIN32
|
||||||
if((n > 0) || (n < 0 && errno == EAGAIN))
|
if((n > 0) || (n < 0 && errno == EAGAIN))
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -260,6 +260,24 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
|
||||||
return request;
|
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 xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), void *closure, int flags, uint64_t *sent)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
|
@ -54,11 +54,14 @@ typedef struct {
|
||||||
enum xcb_send_request_flags_t {
|
enum xcb_send_request_flags_t {
|
||||||
XCB_REQUEST_CHECKED = 1 << 0,
|
XCB_REQUEST_CHECKED = 1 << 0,
|
||||||
XCB_REQUEST_RAW = 1 << 1,
|
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);
|
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
|
/* 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
|
* 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
|
* xcb_writev. xcb_take_socket provides the sequence number of the last
|
||||||
|
@ -88,6 +91,7 @@ int xcb_writev(xcb_connection_t *c, struct iovec *vector, int count, uint64_t re
|
||||||
|
|
||||||
void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e);
|
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_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_util.c */
|
||||||
|
|
19
src/xcbint.h
19
src/xcbint.h
|
@ -79,6 +79,18 @@ void *_xcb_map_remove(_xcb_map *q, unsigned int key);
|
||||||
|
|
||||||
/* xcb_out.c */
|
/* xcb_out.c */
|
||||||
|
|
||||||
|
typedef void (*xcb_return_socket_func_t)(void *closure);
|
||||||
|
|
||||||
|
#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 {
|
typedef struct _xcb_out {
|
||||||
pthread_cond_t cond;
|
pthread_cond_t cond;
|
||||||
int writing;
|
int writing;
|
||||||
|
@ -100,6 +112,9 @@ typedef struct _xcb_out {
|
||||||
xcb_big_requests_enable_cookie_t cookie;
|
xcb_big_requests_enable_cookie_t cookie;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
} maximum_request_length;
|
} maximum_request_length;
|
||||||
|
#if HAVE_SENDMSG
|
||||||
|
_xcb_fd out_fd;
|
||||||
|
#endif
|
||||||
} _xcb_out;
|
} _xcb_out;
|
||||||
|
|
||||||
int _xcb_out_init(_xcb_out *out);
|
int _xcb_out_init(_xcb_out *out);
|
||||||
|
@ -132,6 +147,10 @@ typedef struct _xcb_in {
|
||||||
|
|
||||||
struct pending_reply *pending_replies;
|
struct pending_reply *pending_replies;
|
||||||
struct pending_reply **pending_replies_tail;
|
struct pending_reply **pending_replies_tail;
|
||||||
|
#if HAVE_SENDMSG
|
||||||
|
_xcb_fd in_fd;
|
||||||
|
#endif
|
||||||
|
struct xcb_special_event *special_events;
|
||||||
} _xcb_in;
|
} _xcb_in;
|
||||||
|
|
||||||
int _xcb_in_init(_xcb_in *in);
|
int _xcb_in_init(_xcb_in *in);
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
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}
|
|
@ -0,0 +1,11 @@
|
||||||
|
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}
|
Loading…
Reference in New Issue