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