+ 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;
+ 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;
+
+ /* Wait for there to be enough data for us to read a whole packet */
+ if(c->in.queue_len < length)
+ return 0;
+
+ /* Get the response type, length, and sequence number. */
+ memcpy(&genrep, c->in.queue, sizeof(genrep));
+
+ /* Compute 32-bit sequence number of this packet. */
+ if((genrep.response_type & 0x7f) != XCB_KEYMAP_NOTIFY)
+ {
+ uint64_t lastread = c->in.request_read;
+ c->in.request_read = (lastread & UINT64_C(0xffffffffffff0000)) | genrep.sequence;
+ if(XCB_SEQUENCE_COMPARE(c->in.request_read, <, lastread))
+ c->in.request_read += 0x10000;
+ if(XCB_SEQUENCE_COMPARE(c->in.request_read, >, c->in.request_expected))
+ c->in.request_expected = c->in.request_read;
+
+ if(c->in.request_read != lastread)
+ {
+ if(c->in.current_reply)
+ {
+ _xcb_map_put(c->in.replies, lastread, c->in.current_reply);
+ c->in.current_reply = 0;
+ c->in.current_reply_tail = &c->in.current_reply;
+ }
+ c->in.request_completed = c->in.request_read - 1;
+ }
+
+ 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))
+ {
+ pending_reply *oldpend = c->in.pending_replies;
+ c->in.pending_replies = oldpend->next;
+ if(!oldpend->next)
+ c->in.pending_replies_tail = &c->in.pending_replies;
+ free(oldpend);
+ }
+
+ if(genrep.response_type == XCB_ERROR)
+ c->in.request_completed = c->in.request_read;
+
+ remove_finished_readers(&c->in.readers, c->in.request_completed);
+ }
+
+ if(genrep.response_type == XCB_ERROR || genrep.response_type == XCB_REPLY)
+ {
+ pend = c->in.pending_replies;
+ if(pend &&
+ !(XCB_SEQUENCE_COMPARE(pend->first_request, <=, c->in.request_read) &&
+ (pend->workaround == WORKAROUND_EXTERNAL_SOCKET_OWNER ||
+ XCB_SEQUENCE_COMPARE(c->in.request_read, <=, pend->last_request))))
+ pend = 0;
+ }
+
+ /* For reply packets, check that the entire packet is available. */
+ if(genrep.response_type == XCB_REPLY)
+ {
+ if(pend && pend->workaround == WORKAROUND_GLX_GET_FB_CONFIGS_BUG)
+ {
+ uint32_t *p = (uint32_t *) c->in.queue;
+ 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 + nfd * sizeof(int) +
+ (genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t));
+ if (bufsize < INT32_MAX)
+ buf = malloc((size_t) bufsize);