Tizen 2.1 base
[framework/uifw/xorg/lib/libx11.git] / src / xcb_io.c
1 /* Copyright (C) 2003-2006 Jamey Sharp, Josh Triplett
2  * This file is licensed under the MIT license. See the file COPYING. */
3
4 #ifdef HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7
8 #include "Xlibint.h"
9 #include "locking.h"
10 #include "Xprivate.h"
11 #include "Xxcbint.h"
12 #include <xcb/xcbext.h>
13
14 #include <assert.h>
15 #ifdef HAVE_INTTYPES_H
16 #include <inttypes.h>
17 #endif
18 #include <stdio.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #ifdef HAVE_SYS_SELECT_H
23 #include <sys/select.h>
24 #endif
25
26 #define xcb_fail_assert(_message, _var) { \
27         unsigned int _var = 1; \
28         fprintf(stderr, "[xcb] Aborting, sorry about that.\n"); \
29         assert(!_var); \
30 }
31
32 #define throw_thread_fail_assert(_message, _var) { \
33         fprintf(stderr, "[xcb] " _message "\n"); \
34         fprintf(stderr, "[xcb] Most likely this is a multi-threaded client " \
35                         "and XInitThreads has not been called\n"); \
36         xcb_fail_assert(_message, _var); \
37 }
38
39 /* XXX: It would probably be most useful if we stored the last-processed
40  *      request, so we could find the offender from the message. */
41 #define throw_extlib_fail_assert(_message, _var) { \
42         fprintf(stderr, "[xcb] " _message "\n"); \
43         fprintf(stderr, "[xcb] This is most likely caused by a broken X " \
44                         "extension library\n"); \
45         xcb_fail_assert(_message, _var); \
46 }
47
48 static void return_socket(void *closure)
49 {
50         Display *dpy = closure;
51         InternalLockDisplay(dpy, /* don't skip user locks */ 0);
52         _XSend(dpy, NULL, 0);
53         dpy->bufmax = dpy->buffer;
54         UnlockDisplay(dpy);
55 }
56
57 static void require_socket(Display *dpy)
58 {
59         if(dpy->bufmax == dpy->buffer)
60         {
61                 uint64_t sent;
62                 int flags = 0;
63                 /* if we don't own the event queue, we have to ask XCB
64                  * to set our errors aside for us. */
65                 if(dpy->xcb->event_owner != XlibOwnsEventQueue)
66                         flags = XCB_REQUEST_CHECKED;
67                 if(!xcb_take_socket(dpy->xcb->connection, return_socket, dpy,
68                                     flags, &sent))
69                         _XIOError(dpy);
70                 /* Xlib uses unsigned long for sequence numbers.  XCB
71                  * uses 64-bit internally, but currently exposes an
72                  * unsigned int API.  If these differ, Xlib cannot track
73                  * the full 64-bit sequence number if 32-bit wrap
74                  * happens while Xlib does not own the socket.  A
75                  * complete fix would be to make XCB's public API use
76                  * 64-bit sequence numbers. */
77                 if (sizeof(unsigned long) > sizeof(unsigned int) &&
78                     dpy->xcb->event_owner == XlibOwnsEventQueue &&
79                     (sent - dpy->last_request_read >= (UINT64_C(1) << 32))) {
80                         throw_thread_fail_assert("Sequence number wrapped "
81                                                  "beyond 32 bits while Xlib "
82                                                  "did not own the socket",
83                                                  xcb_xlib_seq_number_wrapped);
84                 }
85                 dpy->xcb->last_flushed = dpy->request = sent;
86                 dpy->bufmax = dpy->xcb->real_bufmax;
87         }
88 }
89
90 /* Call internal connection callbacks for any fds that are currently
91  * ready to read. This function will not block unless one of the
92  * callbacks blocks.
93  *
94  * This code borrowed from _XWaitForReadable. Inverse call tree:
95  * _XRead
96  *  _XWaitForWritable
97  *   _XFlush
98  *   _XSend
99  *  _XEventsQueued
100  *  _XReadEvents
101  *  _XRead[0-9]+
102  *   _XAllocIDs
103  *  _XReply
104  *  _XEatData
105  * _XReadPad
106  */
107 static void check_internal_connections(Display *dpy)
108 {
109         struct _XConnectionInfo *ilist;
110         fd_set r_mask;
111         struct timeval tv;
112         int result;
113         int highest_fd = -1;
114
115         if(dpy->flags & XlibDisplayProcConni || !dpy->im_fd_info)
116                 return;
117
118         FD_ZERO(&r_mask);
119         for(ilist = dpy->im_fd_info; ilist; ilist = ilist->next)
120         {
121                 assert(ilist->fd >= 0);
122                 FD_SET(ilist->fd, &r_mask);
123                 if(ilist->fd > highest_fd)
124                         highest_fd = ilist->fd;
125         }
126         assert(highest_fd >= 0);
127
128         tv.tv_sec = 0;
129         tv.tv_usec = 0;
130         result = select(highest_fd + 1, &r_mask, NULL, NULL, &tv);
131
132         if(result == -1)
133         {
134                 if(errno == EINTR)
135                         return;
136                 _XIOError(dpy);
137         }
138
139         for(ilist = dpy->im_fd_info; result && ilist; ilist = ilist->next)
140                 if(FD_ISSET(ilist->fd, &r_mask))
141                 {
142                         _XProcessInternalConnection(dpy, ilist);
143                         --result;
144                 }
145 }
146
147 static PendingRequest *append_pending_request(Display *dpy, unsigned long sequence)
148 {
149         PendingRequest *node = malloc(sizeof(PendingRequest));
150         assert(node);
151         node->next = NULL;
152         node->sequence = sequence;
153         node->reply_waiter = 0;
154         if(dpy->xcb->pending_requests_tail)
155         {
156                 if (XLIB_SEQUENCE_COMPARE(dpy->xcb->pending_requests_tail->sequence,
157                                           >=, node->sequence))
158                         throw_thread_fail_assert("Unknown sequence number "
159                                                  "while appending request",
160                                                  xcb_xlib_unknown_seq_number);
161                 if (dpy->xcb->pending_requests_tail->next != NULL)
162                         throw_thread_fail_assert("Unknown request in queue "
163                                                  "while appending request",
164                                                  xcb_xlib_unknown_req_pending);
165                 dpy->xcb->pending_requests_tail->next = node;
166         }
167         else
168                 dpy->xcb->pending_requests = node;
169         dpy->xcb->pending_requests_tail = node;
170         return node;
171 }
172
173 static void dequeue_pending_request(Display *dpy, PendingRequest *req)
174 {
175         if (req != dpy->xcb->pending_requests)
176                 throw_thread_fail_assert("Unknown request in queue while "
177                                          "dequeuing",
178                                          xcb_xlib_unknown_req_in_deq);
179
180         dpy->xcb->pending_requests = req->next;
181         if(!dpy->xcb->pending_requests)
182         {
183                 if (req != dpy->xcb->pending_requests_tail)
184                         throw_thread_fail_assert("Unknown request in queue "
185                                                  "while dequeuing",
186                                                  xcb_xlib_unknown_req_in_deq);
187                 dpy->xcb->pending_requests_tail = NULL;
188         }
189         else if (XLIB_SEQUENCE_COMPARE(req->sequence, >=,
190                                        dpy->xcb->pending_requests->sequence))
191                 throw_thread_fail_assert("Unknown sequence number while "
192                                          "dequeuing request",
193                                          xcb_xlib_threads_sequence_lost);
194
195         free(req);
196 }
197
198 static int handle_error(Display *dpy, xError *err, Bool in_XReply)
199 {
200         _XExtension *ext;
201         int ret_code;
202         /* Oddly, Xlib only allows extensions to suppress errors when
203          * those errors were seen by _XReply. */
204         if(in_XReply)
205                 /*
206                  * we better see if there is an extension who may
207                  * want to suppress the error.
208                  */
209                 for(ext = dpy->ext_procs; ext; ext = ext->next)
210                         if(ext->error && (*ext->error)(dpy, err, &ext->codes, &ret_code))
211                                 return ret_code;
212         _XError(dpy, err);
213         return 0;
214 }
215
216 /* Widen a 32-bit sequence number into a native-word-size (unsigned long)
217  * sequence number.  Treating the comparison as a 1 and shifting it avoids a
218  * conditional branch, and shifting by 16 twice avoids a compiler warning when
219  * sizeof(unsigned long) == 4. */
220 static void widen(unsigned long *wide, unsigned int narrow)
221 {
222         unsigned long new = (*wide & ~0xFFFFFFFFUL) | narrow;
223         *wide = new + ((unsigned long) (new < *wide) << 16 << 16);
224 }
225
226 /* Thread-safety rules:
227  *
228  * At most one thread can be reading from XCB's event queue at a time.
229  * If you are not the current event-reading thread and you need to find
230  * out if an event is available, you must wait.
231  *
232  * The same rule applies for reading replies.
233  *
234  * A single thread cannot be both the the event-reading and the
235  * reply-reading thread at the same time.
236  *
237  * We always look at both the current event and the first pending reply
238  * to decide which to process next.
239  *
240  * We always process all responses in sequence-number order, which may
241  * mean waiting for another thread (either the event_waiter or the
242  * reply_waiter) to handle an earlier response before we can process or
243  * return a later one. If so, we wait on the corresponding condition
244  * variable for that thread to process the response and wake us up.
245  */
246
247 static xcb_generic_reply_t *poll_for_event(Display *dpy)
248 {
249         /* Make sure the Display's sequence numbers are valid */
250         require_socket(dpy);
251
252         /* Precondition: This thread can safely get events from XCB. */
253         assert(dpy->xcb->event_owner == XlibOwnsEventQueue && !dpy->xcb->event_waiter);
254
255         if(!dpy->xcb->next_event)
256                 dpy->xcb->next_event = xcb_poll_for_event(dpy->xcb->connection);
257
258         if(dpy->xcb->next_event)
259         {
260                 PendingRequest *req = dpy->xcb->pending_requests;
261                 xcb_generic_event_t *event = dpy->xcb->next_event;
262                 unsigned long event_sequence = dpy->last_request_read;
263                 widen(&event_sequence, event->full_sequence);
264                 if(!req || XLIB_SEQUENCE_COMPARE(event_sequence, <, req->sequence)
265                         || (event->response_type != X_Error && event_sequence == req->sequence))
266                 {
267                         if (XLIB_SEQUENCE_COMPARE(event_sequence, >,
268                                                   dpy->request))
269                         {
270                                 throw_thread_fail_assert("Unknown sequence "
271                                                          "number while "
272                                                          "processing queue",
273                                                 xcb_xlib_threads_sequence_lost);
274                         }
275                         dpy->last_request_read = event_sequence;
276                         dpy->xcb->next_event = NULL;
277                         return (xcb_generic_reply_t *) event;
278                 }
279         }
280         return NULL;
281 }
282
283 static xcb_generic_reply_t *poll_for_response(Display *dpy)
284 {
285         void *response;
286         xcb_generic_error_t *error;
287         PendingRequest *req;
288         while(!(response = poll_for_event(dpy)) &&
289               (req = dpy->xcb->pending_requests) &&
290               !req->reply_waiter &&
291               xcb_poll_for_reply(dpy->xcb->connection, req->sequence, &response, &error))
292         {
293                 if(XLIB_SEQUENCE_COMPARE(req->sequence, >, dpy->request))
294                 {
295                         throw_thread_fail_assert("Unknown sequence number "
296                                                  "while awaiting reply",
297                                                 xcb_xlib_threads_sequence_lost);
298                 }
299                 dpy->last_request_read = req->sequence;
300                 if(response)
301                         break;
302                 dequeue_pending_request(dpy, req);
303                 if(error)
304                         return (xcb_generic_reply_t *) error;
305         }
306         return response;
307 }
308
309 static void handle_response(Display *dpy, xcb_generic_reply_t *response, Bool in_XReply)
310 {
311         _XAsyncHandler *async, *next;
312         switch(response->response_type)
313         {
314         case X_Reply:
315                 for(async = dpy->async_handlers; async; async = next)
316                 {
317                         next = async->next;
318                         if(async->handler(dpy, (xReply *) response, (char *) response, sizeof(xReply) + (response->length << 2), async->data))
319                                 break;
320                 }
321                 break;
322
323         case X_Error:
324                 handle_error(dpy, (xError *) response, in_XReply);
325                 break;
326
327         default: /* event */
328                 /* GenericEvents may be > 32 bytes. In this case, the
329                  * event struct is trailed by the additional bytes. the
330                  * xcb_generic_event_t struct uses 4 bytes for internal
331                  * numbering, so we need to shift the trailing data to
332                  * be after the first 32 bytes. */
333                 if(response->response_type == GenericEvent && ((xcb_ge_event_t *) response)->length)
334                 {
335                         xcb_ge_event_t *event = (xcb_ge_event_t *) response;
336                         memmove(&event->full_sequence, &event[1], event->length * 4);
337                 }
338                 _XEnq(dpy, (xEvent *) response);
339                 break;
340         }
341         free(response);
342 }
343
344 int _XEventsQueued(Display *dpy, int mode)
345 {
346         xcb_generic_reply_t *response;
347         if(dpy->flags & XlibDisplayIOError)
348                 return 0;
349         if(dpy->xcb->event_owner != XlibOwnsEventQueue)
350                 return 0;
351
352         if(mode == QueuedAfterFlush)
353                 _XSend(dpy, NULL, 0);
354         else
355                 check_internal_connections(dpy);
356
357         /* If another thread is blocked waiting for events, then we must
358          * let that thread pick up the next event. Since it blocked, we
359          * can reasonably claim there are no new events right now. */
360         if(!dpy->xcb->event_waiter)
361         {
362                 while((response = poll_for_response(dpy)))
363                         handle_response(dpy, response, False);
364                 if(xcb_connection_has_error(dpy->xcb->connection))
365                         _XIOError(dpy);
366         }
367         return dpy->qlen;
368 }
369
370 /* _XReadEvents - Flush the output queue,
371  * then read as many events as possible (but at least 1) and enqueue them
372  */
373 void _XReadEvents(Display *dpy)
374 {
375         xcb_generic_reply_t *response;
376         unsigned long serial;
377
378         if(dpy->flags & XlibDisplayIOError)
379                 return;
380         _XSend(dpy, NULL, 0);
381         if(dpy->xcb->event_owner != XlibOwnsEventQueue)
382                 return;
383         check_internal_connections(dpy);
384
385         serial = dpy->next_event_serial_num;
386         while(serial == dpy->next_event_serial_num || dpy->qlen == 0)
387         {
388                 if(dpy->xcb->event_waiter)
389                 {
390                         ConditionWait(dpy, dpy->xcb->event_notify);
391                         /* Maybe the other thread got us an event. */
392                         continue;
393                 }
394
395                 if(!dpy->xcb->next_event)
396                 {
397                         xcb_generic_event_t *event;
398                         dpy->xcb->event_waiter = 1;
399                         UnlockDisplay(dpy);
400                         event = xcb_wait_for_event(dpy->xcb->connection);
401                         /* It appears that classic Xlib respected user
402                          * locks when waking up after waiting for
403                          * events. However, if this thread did not have
404                          * any user locks, and another thread takes a
405                          * user lock and tries to read events, then we'd
406                          * deadlock. So we'll choose to let the thread
407                          * that got in first consume events, despite the
408                          * later thread's user locks. */
409                         InternalLockDisplay(dpy, /* ignore user locks */ 1);
410                         dpy->xcb->event_waiter = 0;
411                         ConditionBroadcast(dpy, dpy->xcb->event_notify);
412                         if(!event)
413                                 _XIOError(dpy);
414                         dpy->xcb->next_event = event;
415                 }
416
417                 /* We've established most of the conditions for
418                  * poll_for_response to return non-NULL. The exceptions
419                  * are connection shutdown, and finding that another
420                  * thread is waiting for the next reply we'd like to
421                  * process. */
422
423                 response = poll_for_response(dpy);
424                 if(response)
425                         handle_response(dpy, response, False);
426                 else if(dpy->xcb->pending_requests->reply_waiter)
427                 { /* need braces around ConditionWait */
428                         ConditionWait(dpy, dpy->xcb->reply_notify);
429                 }
430                 else
431                         _XIOError(dpy);
432         }
433
434         /* The preceding loop established that there is no
435          * event_waiter--unless we just called ConditionWait because of
436          * a reply_waiter, in which case another thread may have become
437          * the event_waiter while we slept unlocked. */
438         if(!dpy->xcb->event_waiter)
439                 while((response = poll_for_response(dpy)))
440                         handle_response(dpy, response, False);
441         if(xcb_connection_has_error(dpy->xcb->connection))
442                 _XIOError(dpy);
443 }
444
445 /*
446  * _XSend - Flush the buffer and send the client data. 32 bit word aligned
447  * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
448  *
449  * Note that the connection must not be read from once the data currently
450  * in the buffer has been written.
451  */
452 void _XSend(Display *dpy, const char *data, long size)
453 {
454         static const xReq dummy_request;
455         static char const pad[3];
456         struct iovec vec[3];
457         uint64_t requests;
458         _XExtension *ext;
459         xcb_connection_t *c = dpy->xcb->connection;
460         if(dpy->flags & XlibDisplayIOError)
461                 return;
462
463         if(dpy->bufptr == dpy->buffer && !size)
464                 return;
465
466         /* iff we asked XCB to set aside errors, we must pick those up
467          * eventually. iff there are async handlers, we may have just
468          * issued requests that will generate replies. in either case,
469          * we need to remember to check later. */
470         if(dpy->xcb->event_owner != XlibOwnsEventQueue || dpy->async_handlers)
471         {
472                 uint64_t sequence;
473                 for(sequence = dpy->xcb->last_flushed + 1; sequence <= dpy->request; ++sequence)
474                         append_pending_request(dpy, sequence);
475         }
476         requests = dpy->request - dpy->xcb->last_flushed;
477         dpy->xcb->last_flushed = dpy->request;
478
479         vec[0].iov_base = dpy->buffer;
480         vec[0].iov_len = dpy->bufptr - dpy->buffer;
481         vec[1].iov_base = (char *)data;
482         vec[1].iov_len = size;
483         vec[2].iov_base = (char *)pad;
484         vec[2].iov_len = -size & 3;
485
486         for(ext = dpy->flushes; ext; ext = ext->next_flush)
487         {
488                 int i;
489                 for(i = 0; i < 3; ++i)
490                         if(vec[i].iov_len)
491                                 ext->before_flush(dpy, &ext->codes, vec[i].iov_base, vec[i].iov_len);
492         }
493
494         if(xcb_writev(c, vec, 3, requests) < 0)
495                 _XIOError(dpy);
496         dpy->bufptr = dpy->buffer;
497         dpy->last_req = (char *) &dummy_request;
498
499         check_internal_connections(dpy);
500
501         _XSetSeqSyncFunction(dpy);
502 }
503
504 /*
505  * _XFlush - Flush the X request buffer.  If the buffer is empty, no
506  * action is taken.
507  */
508 void _XFlush(Display *dpy)
509 {
510         require_socket(dpy);
511         _XSend(dpy, NULL, 0);
512
513         _XEventsQueued(dpy, QueuedAfterReading);
514 }
515
516 static const XID inval_id = ~0UL;
517
518 void _XIDHandler(Display *dpy)
519 {
520         if (dpy->xcb->next_xid == inval_id)
521                 _XAllocIDs(dpy, &dpy->xcb->next_xid, 1);
522 }
523
524 /* _XAllocID - resource ID allocation routine. */
525 XID _XAllocID(Display *dpy)
526 {
527         XID ret = dpy->xcb->next_xid;
528         assert (ret != inval_id);
529         dpy->xcb->next_xid = inval_id;
530         _XSetPrivSyncFunction(dpy);
531         return ret;
532 }
533
534 /* _XAllocIDs - multiple resource ID allocation routine. */
535 void _XAllocIDs(Display *dpy, XID *ids, int count)
536 {
537         int i;
538 #ifdef XTHREADS
539         if (dpy->lock)
540                 (*dpy->lock->user_lock_display)(dpy);
541         UnlockDisplay(dpy);
542 #endif
543         for (i = 0; i < count; i++)
544                 ids[i] = xcb_generate_id(dpy->xcb->connection);
545 #ifdef XTHREADS
546         InternalLockDisplay(dpy, /* don't skip user locks */ 0);
547         if (dpy->lock)
548                 (*dpy->lock->user_unlock_display)(dpy);
549 #endif
550 }
551
552 static void _XFreeReplyData(Display *dpy, Bool force)
553 {
554         if(!force && dpy->xcb->reply_consumed < dpy->xcb->reply_length)
555                 return;
556         free(dpy->xcb->reply_data);
557         dpy->xcb->reply_data = NULL;
558 }
559
560 /*
561  * _XReply - Wait for a reply packet and copy its contents into the
562  * specified rep.
563  * extra: number of 32-bit words expected after the reply
564  * discard: should I discard data following "extra" words?
565  */
566 Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
567 {
568         xcb_generic_error_t *error;
569         xcb_connection_t *c = dpy->xcb->connection;
570         char *reply;
571         PendingRequest *current;
572
573         if (dpy->xcb->reply_data)
574                 throw_extlib_fail_assert("Extra reply data still left in queue",
575                                          xcb_xlib_extra_reply_data_left);
576
577         if(dpy->flags & XlibDisplayIOError)
578                 return 0;
579
580         _XSend(dpy, NULL, 0);
581         if(dpy->xcb->pending_requests_tail && dpy->xcb->pending_requests_tail->sequence == dpy->request)
582                 current = dpy->xcb->pending_requests_tail;
583         else
584                 current = append_pending_request(dpy, dpy->request);
585         /* Don't let any other thread get this reply. */
586         current->reply_waiter = 1;
587
588         while(1)
589         {
590                 PendingRequest *req = dpy->xcb->pending_requests;
591                 xcb_generic_reply_t *response;
592
593                 if(req != current && req->reply_waiter)
594                 {
595                         ConditionWait(dpy, dpy->xcb->reply_notify);
596                         /* Another thread got this reply. */
597                         continue;
598                 }
599                 req->reply_waiter = 1;
600                 UnlockDisplay(dpy);
601                 response = xcb_wait_for_reply(c, req->sequence, &error);
602                 /* Any user locks on another thread must have been taken
603                  * while we slept in xcb_wait_for_reply. Classic Xlib
604                  * ignored those user locks in this case, so we do too. */
605                 InternalLockDisplay(dpy, /* ignore user locks */ 1);
606
607                 /* We have the response we're looking for. Now, before
608                  * letting anyone else process this sequence number, we
609                  * need to process any events that should have come
610                  * earlier. */
611
612                 if(dpy->xcb->event_owner == XlibOwnsEventQueue)
613                 {
614                         xcb_generic_reply_t *event;
615                         /* If some thread is already waiting for events,
616                          * it will get the first one. That thread must
617                          * process that event before we can continue. */
618                         /* FIXME: That event might be after this reply,
619                          * and might never even come--or there might be
620                          * multiple threads trying to get events. */
621                         while(dpy->xcb->event_waiter)
622                         { /* need braces around ConditionWait */
623                                 ConditionWait(dpy, dpy->xcb->event_notify);
624                         }
625                         while((event = poll_for_event(dpy)))
626                                 handle_response(dpy, event, True);
627                 }
628
629                 req->reply_waiter = 0;
630                 ConditionBroadcast(dpy, dpy->xcb->reply_notify);
631                 if(XLIB_SEQUENCE_COMPARE(req->sequence, >, dpy->request)) {
632                         throw_thread_fail_assert("Unknown sequence number "
633                                                  "while processing reply",
634                                                 xcb_xlib_threads_sequence_lost);
635                 }
636                 dpy->last_request_read = req->sequence;
637                 if(!response)
638                         dequeue_pending_request(dpy, req);
639
640                 if(req == current)
641                 {
642                         reply = (char *) response;
643                         break;
644                 }
645
646                 if(error)
647                         handle_response(dpy, (xcb_generic_reply_t *) error, True);
648                 else if(response)
649                         handle_response(dpy, response, True);
650         }
651         check_internal_connections(dpy);
652
653         if(dpy->xcb->next_event && dpy->xcb->next_event->response_type == X_Error)
654         {
655                 xcb_generic_event_t *event = dpy->xcb->next_event;
656                 unsigned long event_sequence = dpy->last_request_read;
657                 widen(&event_sequence, event->full_sequence);
658                 if(event_sequence == dpy->last_request_read)
659                 {
660                         error = (xcb_generic_error_t *) event;
661                         dpy->xcb->next_event = NULL;
662                 }
663         }
664
665         if(error)
666         {
667                 int ret_code;
668
669                 /* Xlib is evil and assumes that even errors will be
670                  * copied into rep. */
671                 memcpy(rep, error, 32);
672
673                 /* do not die on "no such font", "can't allocate",
674                    "can't grab" failures */
675                 switch(error->error_code)
676                 {
677                         case BadName:
678                                 switch(error->major_code)
679                                 {
680                                         case X_LookupColor:
681                                         case X_AllocNamedColor:
682                                                 free(error);
683                                                 return 0;
684                                 }
685                                 break;
686                         case BadFont:
687                                 if(error->major_code == X_QueryFont) {
688                                         free(error);
689                                         return 0;
690                                 }
691                                 break;
692                         case BadAlloc:
693                         case BadAccess:
694                                 free(error);
695                                 return 0;
696                 }
697
698                 ret_code = handle_error(dpy, (xError *) error, True);
699                 free(error);
700                 return ret_code;
701         }
702
703         /* it's not an error, but we don't have a reply, so it's an I/O
704          * error. */
705         if(!reply)
706         {
707                 _XIOError(dpy);
708                 return 0;
709         }
710
711         /* there's no error and we have a reply. */
712         dpy->xcb->reply_data = reply;
713         dpy->xcb->reply_consumed = sizeof(xReply) + (extra * 4);
714         dpy->xcb->reply_length = sizeof(xReply);
715         if(dpy->xcb->reply_data[0] == 1)
716                 dpy->xcb->reply_length += (((xcb_generic_reply_t *) dpy->xcb->reply_data)->length * 4);
717
718         /* error: Xlib asks too much. give them what we can anyway. */
719         if(dpy->xcb->reply_length < dpy->xcb->reply_consumed)
720                 dpy->xcb->reply_consumed = dpy->xcb->reply_length;
721
722         memcpy(rep, dpy->xcb->reply_data, dpy->xcb->reply_consumed);
723         _XFreeReplyData(dpy, discard);
724         return 1;
725 }
726
727 int _XRead(Display *dpy, char *data, long size)
728 {
729         assert(size >= 0);
730         if(size == 0)
731                 return 0;
732         if(dpy->xcb->reply_data == NULL ||
733            dpy->xcb->reply_consumed + size > dpy->xcb->reply_length)
734                 throw_extlib_fail_assert("Too much data requested from _XRead",
735                                          xcb_xlib_too_much_data_requested);
736         memcpy(data, dpy->xcb->reply_data + dpy->xcb->reply_consumed, size);
737         dpy->xcb->reply_consumed += size;
738         _XFreeReplyData(dpy, False);
739         return 0;
740 }
741
742 /*
743  * _XReadPad - Read bytes from the socket taking into account incomplete
744  * reads.  If the number of bytes is not 0 mod 4, read additional pad
745  * bytes.
746  */
747 void _XReadPad(Display *dpy, char *data, long size)
748 {
749         _XRead(dpy, data, size);
750         dpy->xcb->reply_consumed += -size & 3;
751         _XFreeReplyData(dpy, False);
752 }
753
754 /* Read and discard "n" 8-bit bytes of data */
755 void _XEatData(Display *dpy, unsigned long n)
756 {
757         dpy->xcb->reply_consumed += n;
758         _XFreeReplyData(dpy, False);
759 }