[Xcb-commit] libxcb: Branch 'xcb-1.9' - 12 commits - configure.ac Makefile.am src xcb-dri3.pc.in xcb-present.pc.in

Keith Packard keithp at kemper.freedesktop.org
Thu Nov 7 23:03:27 CET 2013


 Makefile.am       |    6 +
 configure.ac      |   25 ++++
 src/.gitignore    |    2 
 src/Makefile.am   |   18 +++
 src/c_client.py   |  104 +++++++++++++++++-
 src/xcb.h         |   58 ++++++----
 src/xcb_conn.c    |   31 +++++
 src/xcb_in.c      |  296 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/xcb_out.c     |   18 +++
 src/xcbext.h      |    6 -
 src/xcbint.h      |   24 ++++
 xcb-dri3.pc.in    |   11 ++
 xcb-present.pc.in |   11 ++
 13 files changed, 565 insertions(+), 45 deletions(-)

New commits:
commit d698fa3aa3ce61ccde5f15fe635f67808b32030b
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Nov 7 13:50:33 2013 -0800

    Update to version 1.9.2
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/configure.ac b/configure.ac
index aca5b1b..dcc1875 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
 # Initialize Autoconf
 AC_PREREQ(2.57)
 AC_INIT([libxcb],
-        1.9.1,
+        1.9.2,
         [xcb at lists.freedesktop.org])
 AC_CONFIG_SRCDIR([xcb.pc.in])
 # Set common system defines for POSIX extensions, such as _GNU_SOURCE
commit 6d630cb9bbd72d274a564acd4862dbaae4782f6f
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Jul 11 16:01:02 2013 -0700

    Add Present extension
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-By: Uli Schlachter <psychon at znc.in>

diff --git a/Makefile.am b/Makefile.am
index b70f3de..b54d399 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,6 +22,9 @@ 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
diff --git a/configure.ac b/configure.ac
index 7cc4bbb..aca5b1b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -193,6 +193,7 @@ XCB_EXTENSION(DPMS, "yes")
 XCB_EXTENSION(DRI2, "yes")
 XCB_EXTENSION(DRI3, "$have_sendmsg")
 XCB_EXTENSION(GLX, "yes")
+XCB_EXTENSION(Present, "yes")
 XCB_EXTENSION(RandR, "yes")
 XCB_EXTENSION(Record, "yes")
 XCB_EXTENSION(Render, "yes")
@@ -238,6 +239,7 @@ xcb-dpms.pc
 xcb-dri2.pc
 xcb-dri3.pc
 xcb-glx.pc
+xcb-present.pc
 xcb-randr.pc
 xcb-record.pc
 xcb-render.pc
diff --git a/src/.gitignore b/src/.gitignore
index 71a7341..a2a9010 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -5,6 +5,7 @@ dpms.*
 dri2.*
 dri3.*
 glx.*
+present.*
 randr.*
 record.*
 render.*
diff --git a/src/Makefile.am b/src/Makefile.am
index 9d6d246..346ee03 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -64,6 +64,14 @@ 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
diff --git a/xcb-present.pc.in b/xcb-present.pc.in
new file mode 100644
index 0000000..848ac02
--- /dev/null
+++ b/xcb-present.pc.in
@@ -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}
commit a22ffa399a63a2c53aabe66efe9df01196fed74e
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Apr 9 21:35:52 2013 -0700

    Add DRI3 library
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-By: Uli Schlachter <psychon at znc.in>

diff --git a/Makefile.am b/Makefile.am
index 1f88b72..b70f3de 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,6 +16,9 @@ endif
 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
diff --git a/configure.ac b/configure.ac
index 330cdf4..7cc4bbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -191,6 +191,7 @@ XCB_EXTENSION(Composite, "yes")
 XCB_EXTENSION(Damage, "yes")
 XCB_EXTENSION(DPMS, "yes")
 XCB_EXTENSION(DRI2, "yes")
+XCB_EXTENSION(DRI3, "$have_sendmsg")
 XCB_EXTENSION(GLX, "yes")
 XCB_EXTENSION(RandR, "yes")
 XCB_EXTENSION(Record, "yes")
@@ -235,6 +236,7 @@ xcb-composite.pc
 xcb-damage.pc
 xcb-dpms.pc
 xcb-dri2.pc
+xcb-dri3.pc
 xcb-glx.pc
 xcb-randr.pc
 xcb-record.pc
@@ -279,6 +281,7 @@ echo "    Composite...........: ${BUILD_COMPOSITE}"
 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}"
diff --git a/src/.gitignore b/src/.gitignore
index a402afe..71a7341 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -3,6 +3,7 @@ composite.*
 damage.*
 dpms.*
 dri2.*
+dri3.*
 glx.*
 randr.*
 record.*
diff --git a/src/Makefile.am b/src/Makefile.am
index f48e14e..9d6d246 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -56,6 +56,14 @@ libxcb_dri2_la_LIBADD = $(XCB_LIBS)
 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 += glx.c
 if BUILD_GLX
 lib_LTLIBRARIES += libxcb-glx.la
diff --git a/xcb-dri3.pc.in b/xcb-dri3.pc.in
new file mode 100644
index 0000000..0eb7390
--- /dev/null
+++ b/xcb-dri3.pc.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}
commit 53087b12e2e0e523470bc126c14068525cd3e2cf
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Nov 7 05:20:06 2013 -0800

    Require xcb proto version 1.9
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/configure.ac b/configure.ac
index 1906174..330cdf4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,7 +41,7 @@ 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.9)
 NEEDED="pthread-stubs xau >= 0.99.2"
 PKG_CHECK_MODULES(NEEDED, $NEEDED)
 
commit 568cf48f00441c834ed78375f13e7846c57312e9
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Apr 12 20:15:41 2013 -0700

    Add event queue splitting
    
    This allows apps to peel off certain XGE events into separate queues
    for custom handling. Designed to support the Present extension
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-By: Uli Schlachter <psychon at znc.in>

diff --git a/src/xcb.h b/src/xcb.h
index fe64851..3f2663a 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -291,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);
 
+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.
@@ -329,11 +362,6 @@ void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence);
 /* 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.
diff --git a/src/xcb_in.c b/src/xcb_in.c
index b161e93..839f615 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -60,6 +60,23 @@ struct event_list {
     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;
@@ -104,6 +121,46 @@ static int read_fds(xcb_connection_t *c, int *fds, int nfd)
 }
 #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;
@@ -268,9 +325,12 @@ static int read_packet(xcb_connection_t *c)
     }
     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... */
 }
 
@@ -661,17 +721,21 @@ xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
 
 xcb_special_event_t *
 xcb_register_for_special_xge(xcb_connection_t *c,
-                             uint8_t extension,
+                             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 == extension &&
+        if (se->extension == ext_reply->major_opcode &&
             se->eid == eid) {
             pthread_mutex_unlock(&c->iolock);
             return NULL;
@@ -683,7 +747,7 @@ xcb_register_for_special_xge(xcb_connection_t *c,
         return NULL;
     }
             
-    se->extension = extension;
+    se->extension = ext_reply->major_opcode;
     se->eid = eid;
 
     se->events = NULL;
@@ -694,7 +758,6 @@ xcb_register_for_special_xge(xcb_connection_t *c,
 
     se->next = c->in.special_events;
     c->in.special_events = se;
-
     pthread_mutex_unlock(&c->iolock);
     return se;
 }
@@ -706,6 +769,9 @@ xcb_unregister_for_special_event(xcb_connection_t *c,
     xcb_special_event_t *s, **prev;
     struct event_list   *events, *next;
 
+    if (!se)
+        return;
+
     if (c->has_error)
         return;
 
diff --git a/src/xcbint.h b/src/xcbint.h
index fcf62b8..45dc044 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -155,6 +155,7 @@ typedef struct _xcb_in {
 #if HAVE_SENDMSG
     _xcb_fd in_fd;
 #endif
+    struct xcb_special_event *special_events;
 } _xcb_in;
 
 int _xcb_in_init(_xcb_in *in);
commit bbe7f95e070642c87679cdf4e218fd8fa7528cf3
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Jan 18 01:29:40 2013 -0800

    Add support for receiving fds in replies
    
    Requests signal which replies will have fds, and the replies report
    how many fds they expect in byte 1.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-By: Uli Schlachter <psychon at znc.in>

diff --git a/src/c_client.py b/src/c_client.py
index e5626f3..ce8019c 100644
--- a/src/c_client.py
+++ b/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_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
@@ -1835,7 +1836,7 @@ def c_union(self, name):
     _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.
     '''
@@ -1864,6 +1865,12 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
     # 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'
 
@@ -2256,6 +2263,51 @@ def _c_reply(self, name):
 
     _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.
@@ -2816,14 +2868,17 @@ def c_request(self, name):
         # 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)
diff --git a/src/xcb_in.c b/src/xcb_in.c
index 8a7af92..b161e93 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -90,11 +90,26 @@ 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
+
 static int read_packet(xcb_connection_t *c)
 {
     xcb_generic_reply_t genrep;
     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;
@@ -164,13 +179,18 @@ static int read_packet(xcb_connection_t *c)
             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;
 
-    bufsize = length + eventlength +
+    bufsize = length + eventlength + nfd * sizeof(int)  +
         (genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t));
     if (bufsize < INT32_MAX)
         buf = malloc((size_t) bufsize);
@@ -198,6 +218,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))
     {
         free(buf);
@@ -431,6 +462,11 @@ void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_
     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;
@@ -577,6 +613,120 @@ xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t co
     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,
+                             uint8_t extension,
+                             uint32_t eid,
+                             uint32_t *stamp)
+{
+    xcb_special_event_t *se;
+
+    if(c->has_error)
+        return NULL;
+    pthread_mutex_lock(&c->iolock);
+    for (se = c->in.special_events; se; se = se->next) {
+        if (se->extension == extension &&
+            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 = extension;
+    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 (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)
@@ -665,11 +815,79 @@ void _xcb_in_replies_done(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);
-    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,
+    };
+    struct {
+        struct cmsghdr  cmsghdr;
+        int fd[XCB_MAX_PASS_FD];
+    } fds;
+    struct msghdr msg = {
+        .msg_name = NULL,
+        .msg_namelen = 0,
+        .msg_iov = &iov,
+        .msg_iovlen = 1,
+        .msg_control = &fds,
+        .msg_controllen = sizeof (struct cmsghdr) + 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
+        if (msg.msg_controllen > sizeof (struct cmsghdr))
+        {
+            if (fds.cmsghdr.cmsg_level == SOL_SOCKET &&
+                fds.cmsghdr.cmsg_type == SCM_RIGHTS)
+            {
+                int nfd = (msg.msg_controllen - sizeof (struct cmsghdr)) / sizeof (int);
+                memmove(&c->in.in_fd.fd[c->in.in_fd.nfd],
+                        fds.fd,
+                        nfd);
+                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
diff --git a/src/xcbext.h b/src/xcbext.h
index 4c09d99..20ec1c3 100644
--- a/src/xcbext.h
+++ b/src/xcbext.h
@@ -54,7 +54,8 @@ typedef struct {
 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);
@@ -90,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);
 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 */
diff --git a/src/xcbint.h b/src/xcbint.h
index aaf6685..fcf62b8 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -92,6 +92,7 @@ typedef struct _xcb_fd {
     struct cmsghdr cmsghdr;
     int fd[XCB_MAX_PASS_FD];
     int nfd;
+    int ifd;
 } _xcb_fd;
 #endif
 
@@ -151,6 +152,9 @@ typedef struct _xcb_in {
 
     struct pending_reply *pending_replies;
     struct pending_reply **pending_replies_tail;
+#if HAVE_SENDMSG
+    _xcb_fd in_fd;
+#endif
 } _xcb_in;
 
 int _xcb_in_init(_xcb_in *in);
commit aa6ac19ff407834f0a57fca501602273ced2f714
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Jan 14 11:23:00 2013 -0800

    Add xcb_send_fd API
    
    This uses sendmsg to transmit file descriptors from the application to
    the X server
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-By: Uli Schlachter <psychon at znc.in>

diff --git a/configure.ac b/configure.ac
index 3abe833..1906174 100644
--- a/configure.ac
+++ b/configure.ac
@@ -81,6 +81,19 @@ AC_HEADER_STDC
 AC_SEARCH_LIBS(getaddrinfo, socket)
 AC_SEARCH_LIBS(connect, socket)
 
+have_sendmsg="no"
+case $host_os in
+linux*)
+        AC_SEARCH_LIBS(sendmsg, socket, [have_sendmsg="yes"], [have_sendmsg="no"])
+        ;;
+esac
+
+case x$have_sendmsg 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
@@ -257,6 +270,7 @@ echo "  Package: ${PACKAGE_NAME} ${PACKAGE_VERSION}"
 echo ""
 echo "  Configuration"
 echo "    XDM support.........: ${have_xdmcp}"
+echo "    sendmsg fd passing..: ${have_sendmsg}"
 echo "    Build unit tests....: ${HAVE_CHECK}"
 echo "    XCB buffer size.....: ${xcb_queue_buffer_size}"
 echo ""
diff --git a/src/c_client.py b/src/c_client.py
index c477bab..e5626f3 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -2149,6 +2149,10 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
         # 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
diff --git a/src/xcb.h b/src/xcb.h
index e782d44..fe64851 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -87,6 +87,9 @@ extern "C" {
 /** 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 */
diff --git a/src/xcb_conn.c b/src/xcb_conn.c
index 6a7a806..d5d3c46 100644
--- a/src/xcb_conn.c
+++ b/src/xcb_conn.c
@@ -214,9 +214,34 @@ static int write_vec(xcb_connection_t *c, struct iovec **vector, int *count)
     if (n > IOV_MAX)
 	n = IOV_MAX;
 
-    n = writev(c->fd, *vector, n);
-    if(n < 0 && errno == EAGAIN)
-        return 1;
+#if HAVE_SENDMSG
+    if (c->out.out_fd.nfd) {
+        struct msghdr msg = {
+            .msg_name = NULL,
+            .msg_namelen = 0,
+            .msg_iov = *vector,
+            .msg_iovlen = n,
+            .msg_control = &c->out.out_fd,
+            .msg_controllen = sizeof (struct cmsghdr) + c->out.out_fd.nfd * sizeof (int),
+        };
+        int i;
+        c->out.out_fd.cmsghdr.cmsg_len = msg.msg_controllen;
+        c->out.out_fd.cmsghdr.cmsg_level = SOL_SOCKET;
+        c->out.out_fd.cmsghdr.cmsg_type = SCM_RIGHTS;
+        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)
diff --git a/src/xcb_out.c b/src/xcb_out.c
index a4f52fb..18bb5f9 100644
--- a/src/xcb_out.c
+++ b/src/xcb_out.c
@@ -260,6 +260,24 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
     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;
diff --git a/src/xcbext.h b/src/xcbext.h
index 98b3c93..4c09d99 100644
--- a/src/xcbext.h
+++ b/src/xcbext.h
@@ -59,6 +59,8 @@ enum xcb_send_request_flags_t {
 
 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
diff --git a/src/xcbint.h b/src/xcbint.h
index f9e5a52..aaf6685 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -34,6 +34,10 @@
 #include "config.h"
 #endif
 
+#if HAVE_SENDMSG
+#include <sys/socket.h>
+#endif
+
 #ifdef GCC_HAS_VISIBILITY
 #pragma GCC visibility push(hidden)
 #endif
@@ -79,6 +83,18 @@ void *_xcb_map_remove(_xcb_map *q, unsigned int key);
 
 /* 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 {
+    struct cmsghdr cmsghdr;
+    int fd[XCB_MAX_PASS_FD];
+    int nfd;
+} _xcb_fd;
+#endif
+
 typedef struct _xcb_out {
     pthread_cond_t cond;
     int writing;
@@ -100,6 +116,9 @@ typedef struct _xcb_out {
         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);
commit 9aa5b192ba7d4544c9dcf6d7687aa4730b7b9c2e
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Jan 18 01:28:56 2013 -0800

    -pendantic is too pendantic
    
    Many system headers have warnings when compiled with this flag.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-By: Uli Schlachter <psychon at znc.in>

diff --git a/configure.ac b/configure.ac
index 9796f90..3abe833 100644
--- a/configure.ac
+++ b/configure.ac
@@ -128,7 +128,7 @@ xcbincludedir='${includedir}/xcb'
 AC_SUBST(xcbincludedir)
 
 if  test "x$GCC" = xyes ; then
-    CWARNFLAGS="-Wall -pedantic -Wpointer-arith \
+    CWARNFLAGS="-Wall -Wpointer-arith \
 		-Wstrict-prototypes -Wmissing-declarations -Wnested-externs"
 else
     AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"])
commit db3d97628ed0dcee17645f5c9018104a6d04e27d
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Jul 12 10:32:03 2013 -0700

    Make protocol C files depend on protocol XML files
    
    When new XML files get installed, make sure the C files are regenerated
    
    Signed-off-by: Keith Packard <keithp at keithp.com>
    Reviewed-By: Uli Schlachter <psychon at znc.in>

diff --git a/src/Makefile.am b/src/Makefile.am
index 6b5a2c3..f48e14e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -233,7 +233,7 @@ EXTRA_DIST = $(STATIC_MANS)
 BUILT_SOURCES = $(EXTSOURCES) $(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)
 
 $(man_MANS): $(EXTSOURCES)
commit 37f849dcadc8218ec23cec8fa300a4ff246081b6
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Nov 6 19:33:53 2013 -0800

    Remove xcb_ge_event_t from xcb.h
    
    xcb proto now publishes this structure from an XML description
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/src/xcb.h b/src/xcb.h
index f7dc6af..e782d44 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -138,23 +138,6 @@ typedef struct {
 } 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.
  *
  * A generic error structure.
commit 31ae0b83d5b9600221d9ee57b915df4e91e32e9a
Author: Daniel Martin <consume.noise at gmail.com>
Date:   Sat Jun 8 11:20:39 2013 +0200

    c_client.py: Inject full_sequence into GE events
    
    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.
    
    Signed-off-by: Daniel Martin <consume.noise at gmail.com>
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Peter Harris <pharris at opentext.com>

diff --git a/src/c_client.py b/src/c_client.py
index 942e78a..c477bab 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -2837,6 +2837,23 @@ 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
commit d2eefb77b961fa957e0497e755e448c4fd5df8c3
Author: Daniel Martin <consume.noise at gmail.com>
Date:   Mon May 13 23:33:04 2013 +0200

    c_client.py: Handle multiple expr. in a bitcase
    
    Adopt a change from xcbgen. With that modification the expression in a
    bitcase became a list of expressions to support multiple <enumref> in a
    <bitcase>.
    
    Signed-off-by: Daniel Martin <consume.noise at gmail.com>
    Signed-off-by: Peter Harris <pharris at opentext.com>

diff --git a/src/c_client.py b/src/c_client.py
index ec66223..942e78a 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -687,10 +687,20 @@ def _c_serialize_helper_switch(context, self, complex_name,
     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)]


More information about the xcb-commit mailing list