generator: support listelement-ref
[free-sw/xcb/libxcb] / src / xcb_in.c
index b161e93..ad870c1 100644 (file)
@@ -36,9 +36,6 @@
 #include <stdio.h>
 #include <errno.h>
 
-#include "xcb.h"
-#include "xcbext.h"
-#include "xcbint.h"
 #if USE_POLL
 #include <poll.h>
 #endif
 #include "xcb_windefs.h"
 #endif /* _WIN32 */
 
+#include "xcb.h"
+#include "xcbext.h"
+#include "xcbint.h"
+
 #define XCB_ERROR 0
 #define XCB_REPLY 1
 #define XCB_XGE_EVENT 35
@@ -60,6 +61,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 +122,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;
@@ -143,9 +201,9 @@ static int read_packet(xcb_connection_t *c)
             c->in.request_completed = c->in.request_read - 1;
         }
 
-        while(c->in.pending_replies && 
+        while(c->in.pending_replies &&
               c->in.pending_replies->workaround != WORKAROUND_EXTERNAL_SOCKET_OWNER &&
-             XCB_SEQUENCE_COMPARE (c->in.pending_replies->last_request, <=, c->in.request_completed))
+              XCB_SEQUENCE_COMPARE (c->in.pending_replies->last_request, <=, c->in.request_completed))
         {
             pending_reply *oldpend = c->in.pending_replies;
             c->in.pending_replies = oldpend->next;
@@ -268,9 +326,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... */
 }
 
@@ -326,11 +387,11 @@ static int read_block(const int fd, void *buf, const ssize_t len)
             FD_ZERO(&fds);
             FD_SET(fd, &fds);
 
-           /* Initializing errno here makes sure that for Win32 this loop will execute only once */
-           errno = 0;  
-           do {
-               ret = select(fd + 1, &fds, 0, 0, 0);
-           } while (ret == -1 && errno == EINTR);
+            /* Initializing errno here makes sure that for Win32 this loop will execute only once */
+            errno = 0;
+            do {
+                ret = select(fd + 1, &fds, 0, 0, 0);
+            } while (ret == -1 && errno == EINTR);
 #endif /* USE_POLL */
         }
         if(ret <= 0)
@@ -661,17 +722,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;
@@ -682,8 +747,8 @@ xcb_register_for_special_xge(xcb_connection_t *c,
         pthread_mutex_unlock(&c->iolock);
         return NULL;
     }
-            
-    se->extension = extension;
+
+    se->extension = ext_reply->major_opcode;
     se->eid = eid;
 
     se->events = NULL;
@@ -694,7 +759,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 +770,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;
 
@@ -822,17 +889,17 @@ int _xcb_in_read(xcb_connection_t *c)
         .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;
+    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 = &fds,
-        .msg_controllen = sizeof (struct cmsghdr) + sizeof(int) * (XCB_MAX_PASS_FD - c->in.in_fd.nfd),
+        .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);
 
@@ -850,16 +917,15 @@ int _xcb_in_read(xcb_connection_t *c)
 #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;
+        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