+static xcb_generic_event_t *get_event(xcb_connection_t *c)
+{
+ struct event_list *cur = c->in.events;
+ xcb_generic_event_t *ret;
+ if(!c->in.events)
+ return 0;
+ ret = cur->event;
+ c->in.events = cur->next;
+ if(!cur->next)
+ c->in.events_tail = &c->in.events;
+ free(cur);
+ return ret;
+}
+
+static void free_reply_list(struct reply_list *head)
+{
+ while(head)
+ {
+ struct reply_list *cur = head;
+ head = cur->next;
+ free(cur->reply);
+ free(cur);
+ }
+}
+
+static int read_block(const int fd, void *buf, const ssize_t len)
+{
+ int done = 0;
+ while(done < len)
+ {
+ int ret = recv(fd, ((char *) buf) + done, len - done, 0);
+ if(ret > 0)
+ done += ret;
+#ifndef _WIN32
+ if(ret < 0 && errno == EAGAIN)
+#else
+ if(ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
+#endif /* !_Win32 */
+ {
+#if USE_POLL
+ struct pollfd pfd;
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ do {
+ ret = poll(&pfd, 1, -1);
+ } while (ret == -1 && errno == EINTR);
+#else
+ fd_set fds;
+ 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);
+#endif /* USE_POLL */
+ }
+ if(ret <= 0)
+ return ret;
+ }
+ return len;
+}
+
+static int poll_for_reply(xcb_connection_t *c, uint64_t request, void **reply, xcb_generic_error_t **error)
+{
+ struct reply_list *head;
+
+ /* If an error occurred when issuing the request, fail immediately. */
+ if(!request)
+ head = 0;
+ /* We've read requests past the one we want, so if it has replies we have
+ * them all and they're in the replies map. */
+ else if(XCB_SEQUENCE_COMPARE(request, <, c->in.request_read))
+ {
+ head = _xcb_map_remove(c->in.replies, request);
+ if(head && head->next)
+ _xcb_map_put(c->in.replies, request, head->next);
+ }
+ /* We're currently processing the responses to the request we want, and we
+ * have a reply ready to return. So just return it without blocking. */
+ else if(request == c->in.request_read && c->in.current_reply)
+ {
+ head = c->in.current_reply;
+ c->in.current_reply = head->next;
+ if(!head->next)
+ c->in.current_reply_tail = &c->in.current_reply;
+ }
+ /* We know this request can't have any more replies, and we've already
+ * established it doesn't have a reply now. Don't bother blocking. */
+ else if(request == c->in.request_completed)
+ head = 0;
+ /* We may have more replies on the way for this request: block until we're
+ * sure. */
+ else
+ return 0;
+
+ if(error)
+ *error = 0;
+ *reply = 0;
+
+ if(head)
+ {
+ if(((xcb_generic_reply_t *) head->reply)->response_type == XCB_ERROR)
+ {
+ if(error)
+ *error = head->reply;
+ else
+ free(head->reply);
+ }
+ else
+ *reply = head->reply;
+
+ free(head);
+ }