XlibInt.c revision 1ab64890
1/* $Xorg: XlibInt.c,v 1.8 2001/02/09 02:03:38 xorgcvs Exp $ */ 2/* 3 4Copyright 1985, 1986, 1987, 1998 The Open Group 5 6Permission to use, copy, modify, distribute, and sell this software and its 7documentation for any purpose is hereby granted without fee, provided that 8the above copyright notice appear in all copies and that both that 9copyright notice and this permission notice appear in supporting 10documentation. 11 12The above copyright notice and this permission notice shall be included 13in all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 19OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21OTHER DEALINGS IN THE SOFTWARE. 22 23Except as contained in this notice, the name of The Open Group shall 24not be used in advertising or otherwise to promote the sale, use or 25other dealings in this Software without prior written authorization 26from The Open Group. 27 28*/ 29/* $XFree86: xc/lib/X11/XlibInt.c,v 3.38 2003/10/30 21:55:05 alanh Exp $ */ 30 31/* 32 * XlibInt.c - Internal support routines for the C subroutine 33 * interface library (Xlib) to the X Window System Protocol V11.0. 34 */ 35#define NEED_EVENTS 36#define NEED_REPLIES 37 38#ifdef WIN32 39#define _XLIBINT_ 40#endif 41#ifdef HAVE_CONFIG_H 42#include <config.h> 43#endif 44#include "Xlibint.h" 45#include <X11/Xpoll.h> 46#if !USE_XCB 47#include <X11/Xtrans/Xtrans.h> 48#include <X11/extensions/xcmiscstr.h> 49#endif /* !USE_XCB */ 50#include <stdio.h> 51#ifdef WIN32 52#include <direct.h> 53#endif 54 55#ifdef XTHREADS 56#include "locking.h" 57 58/* these pointers get initialized by XInitThreads */ 59LockInfoPtr _Xglobal_lock = NULL; 60void (*_XCreateMutex_fn)(LockInfoPtr) = NULL; 61/* struct _XCVList *(*_XCreateCVL_fn)() = NULL; */ 62void (*_XFreeMutex_fn)(LockInfoPtr) = NULL; 63void (*_XLockMutex_fn)( 64 LockInfoPtr /* lock */ 65#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE) 66 , char * /* file */ 67 , int /* line */ 68#endif 69 ) = NULL; 70void (*_XUnlockMutex_fn)( 71 LockInfoPtr /* lock */ 72#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE) 73 , char * /* file */ 74 , int /* line */ 75#endif 76 ) = NULL; 77xthread_t (*_Xthread_self_fn)(void) = NULL; 78 79#define XThread_Self() ((*_Xthread_self_fn)()) 80 81#if !USE_XCB 82#define UnlockNextReplyReader(d) if ((d)->lock) \ 83 (*(d)->lock->pop_reader)((d),&(d)->lock->reply_awaiters,&(d)->lock->reply_awaiters_tail) 84 85#define QueueReplyReaderLock(d) ((d)->lock ? \ 86 (*(d)->lock->push_reader)(d,&(d)->lock->reply_awaiters_tail) : NULL) 87#define QueueEventReaderLock(d) ((d)->lock ? \ 88 (*(d)->lock->push_reader)(d,&(d)->lock->event_awaiters_tail) : NULL) 89 90#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE) 91#define InternalLockDisplay(d,wskip) if ((d)->lock) \ 92 (*(d)->lock->internal_lock_display)(d,wskip,__FILE__,__LINE__) 93#else 94#define InternalLockDisplay(d,wskip) if ((d)->lock) \ 95 (*(d)->lock->internal_lock_display)(d,wskip) 96#endif 97#endif /* !USE_XCB */ 98 99#else /* XTHREADS else */ 100 101#if !USE_XCB 102#define UnlockNextReplyReader(d) 103#define UnlockNextEventReader(d) 104#define InternalLockDisplay(d,wskip) 105#endif /* !USE_XCB */ 106 107#endif /* XTHREADS else */ 108 109/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX 110 * systems are broken and return EWOULDBLOCK when they should return EAGAIN 111 */ 112#ifdef WIN32 113#define ETEST() (WSAGetLastError() == WSAEWOULDBLOCK) 114#else 115#ifdef __CYGWIN__ /* Cygwin uses ENOBUFS to signal socket is full */ 116#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) 117#else 118#if defined(EAGAIN) && defined(EWOULDBLOCK) 119#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK) 120#else 121#ifdef EAGAIN 122#define ETEST() (errno == EAGAIN) 123#else 124#define ETEST() (errno == EWOULDBLOCK) 125#endif /* EAGAIN */ 126#endif /* EAGAIN && EWOULDBLOCK */ 127#endif /* __CYGWIN__ */ 128#endif /* WIN32 */ 129 130#ifdef WIN32 131#define ECHECK(err) (WSAGetLastError() == err) 132#define ESET(val) WSASetLastError(val) 133#else 134#ifdef __UNIXOS2__ 135#define ECHECK(err) (errno == err) 136#define ESET(val) 137#else 138#ifdef ISC 139#define ECHECK(err) ((errno == err) || ETEST()) 140#else 141#define ECHECK(err) (errno == err) 142#endif 143#define ESET(val) errno = val 144#endif 145#endif 146 147#if defined(LOCALCONN) || defined(LACHMAN) 148#ifdef EMSGSIZE 149#define ESZTEST() (ECHECK(EMSGSIZE) || ECHECK(ERANGE)) 150#else 151#define ESZTEST() ECHECK(ERANGE) 152#endif 153#else 154#ifdef EMSGSIZE 155#define ESZTEST() ECHECK(EMSGSIZE) 156#endif 157#endif 158 159#ifdef __UNIXOS2__ 160#if !USE_XCB 161#define select(n,r,w,x,t) os2ClientSelect(n,r,w,x,t) 162#endif /* !USE_XCB */ 163#include <limits.h> 164#define MAX_PATH _POSIX_PATH_MAX 165#endif 166 167#if !USE_XCB 168#ifdef MUSTCOPY 169 170#define STARTITERATE(tpvar,type,start,endcond) \ 171 { register char *cpvar; \ 172 for (cpvar = (char *) (start); endcond; ) { \ 173 type dummy; memcpy ((char *) &dummy, cpvar, SIZEOF(type)); \ 174 tpvar = &dummy; 175#define ITERPTR(tpvar) cpvar 176#define RESETITERPTR(tpvar,type,start) cpvar = start 177#define INCITERPTR(tpvar,type) cpvar += SIZEOF(type) 178#define ENDITERATE }} 179 180#else 181 182#define STARTITERATE(tpvar,type,start,endcond) \ 183 for (tpvar = (type *) (start); endcond; ) 184#define ITERPTR(tpvar) (char *)tpvar 185#define RESETITERPTR(tpvar,type,start) tpvar = (type *) (start) 186#define INCITERPTR(tpvar,type) tpvar++ 187#define ENDITERATE 188 189#endif /* MUSTCOPY */ 190 191typedef union { 192 xReply rep; 193 char buf[BUFSIZE]; 194} _XAlignedBuffer; 195 196static char *_XAsyncReply( 197 Display *dpy, 198 register xReply *rep, 199 char *buf, 200 register int *lenp, 201 Bool discard); 202#endif /* !USE_XCB */ 203 204#define SEQLIMIT (65535 - (BUFSIZE / SIZEOF(xReq)) - 10) 205 206/* 207 * The following routines are internal routines used by Xlib for protocol 208 * packet transmission and reception. 209 * 210 * _XIOError(Display *) will be called if any sort of system call error occurs. 211 * This is assumed to be a fatal condition, i.e., XIOError should not return. 212 * 213 * _XError(Display *, xError *) will be called whenever an X_Error event is 214 * received. This is not assumed to be a fatal condition, i.e., it is 215 * acceptable for this procedure to return. However, XError should NOT 216 * perform any operations (directly or indirectly) on the DISPLAY. 217 * 218 * Routines declared with a return type of 'Status' return 0 on failure, 219 * and non 0 on success. Routines with no declared return type don't 220 * return anything. Whenever possible routines that create objects return 221 * the object they have created. 222 */ 223 224#if !USE_XCB 225static xReq _dummy_request = { 226 0, 0, 0 227}; 228 229/* 230 * This is an OS dependent routine which: 231 * 1) returns as soon as the connection can be written on.... 232 * 2) if the connection can be read, must enqueue events and handle errors, 233 * until the connection is writable. 234 */ 235static void 236_XWaitForWritable( 237 Display *dpy 238#ifdef XTHREADS 239 , 240 xcondition_t cv /* our reading condition variable */ 241#endif 242 ) 243{ 244#ifdef USE_POLL 245 struct pollfd filedes; 246#else 247 fd_set r_mask; 248 fd_set w_mask; 249#endif 250 int nfound; 251 252#ifdef USE_POLL 253 filedes.fd = dpy->fd; 254 filedes.events = 0; 255#else 256 FD_ZERO(&r_mask); 257 FD_ZERO(&w_mask); 258#endif 259 260 for (;;) { 261#ifdef XTHREADS 262 /* We allow only one thread at a time to read, to minimize 263 passing of read data between threads. 264 Now, who is it? If there is a non-NULL reply_awaiters and 265 we (i.e., our cv) are not at the head of it, then whoever 266 is at the head is the reader, and we don't read. 267 Otherwise there is no reply_awaiters or we are at the 268 head, having just appended ourselves. 269 In this case, if there is a event_awaiters, then whoever 270 is at the head of it got there before we did, and they are the 271 reader. 272 273 Last cases: no event_awaiters and we are at the head of 274 reply_awaiters or reply_awaiters is NULL: we are the reader, 275 since there is obviously no one else involved. 276 277 XXX - what if cv is NULL and someone else comes along after 278 us while we are waiting? 279 */ 280 281 if (!dpy->lock || 282 (!dpy->lock->event_awaiters && 283 (!dpy->lock->reply_awaiters || 284 dpy->lock->reply_awaiters->cv == cv))) 285#endif 286#ifdef USE_POLL 287 filedes.events = POLLIN; 288 filedes.events |= POLLOUT; 289#else 290 FD_SET(dpy->fd, &r_mask); 291 FD_SET(dpy->fd, &w_mask); 292#endif 293 294 do { 295 UnlockDisplay(dpy); 296#ifdef USE_POLL 297 nfound = poll (&filedes, 1, -1); 298#else 299 nfound = Select (dpy->fd + 1, &r_mask, &w_mask, NULL, NULL); 300#endif 301 InternalLockDisplay(dpy, cv != NULL); 302 if (nfound < 0 && !ECHECK(EINTR)) 303 _XIOError(dpy); 304 } while (nfound <= 0); 305 306 if ( 307#ifdef USE_POLL 308 filedes.revents & POLLIN 309#else 310 FD_ISSET(dpy->fd, &r_mask) 311#endif 312 ) 313 { 314 _XAlignedBuffer buf; 315 BytesReadable_t pend; 316 register int len; 317 register xReply *rep; 318 319 /* find out how much data can be read */ 320 if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0) 321 _XIOError(dpy); 322 len = pend; 323 324 /* must read at least one xEvent; if none is pending, then 325 we'll just block waiting for it */ 326 if (len < SIZEOF(xReply) 327#ifdef XTHREADS 328 || dpy->async_handlers 329#endif 330 ) 331 len = SIZEOF(xReply); 332 333 /* but we won't read more than the max buffer size */ 334 if (len > BUFSIZE) len = BUFSIZE; 335 336 /* round down to an integral number of XReps */ 337 len = (len / SIZEOF(xReply)) * SIZEOF(xReply); 338 339 (void) _XRead (dpy, buf.buf, (long) len); 340 341 STARTITERATE(rep,xReply,buf.buf,len > 0) { 342 if (rep->generic.type == X_Reply) { 343 int tmp = len; 344 RESETITERPTR(rep,xReply, 345 _XAsyncReply (dpy, rep, 346 ITERPTR(rep), &tmp, True)); 347 len = tmp; 348 pend = len; 349 } else { 350 if (rep->generic.type == X_Error) 351 _XError (dpy, (xError *)rep); 352 else /* must be an event packet */ 353 _XEnq (dpy, (xEvent *)rep); 354 INCITERPTR(rep,xReply); 355 len -= SIZEOF(xReply); 356 } 357 } ENDITERATE 358#ifdef XTHREADS 359 if (dpy->lock && dpy->lock->event_awaiters) 360 ConditionSignal(dpy, dpy->lock->event_awaiters->cv); 361#endif 362 } 363#ifdef USE_POLL 364 if (filedes.revents & (POLLOUT|POLLHUP|POLLERR)) 365#else 366 if (FD_ISSET(dpy->fd, &w_mask)) 367#endif 368 { 369#ifdef XTHREADS 370 if (dpy->lock) { 371 ConditionBroadcast(dpy, dpy->lock->writers); 372 } 373#endif 374 return; 375 } 376 } 377} 378#endif /* !USE_XCB */ 379 380 381#define POLLFD_CACHE_SIZE 5 382 383/* initialize the struct array passed to poll() below */ 384Bool _XPollfdCacheInit( 385 Display *dpy) 386{ 387#ifdef USE_POLL 388 struct pollfd *pfp; 389 390 pfp = (struct pollfd *)Xmalloc(POLLFD_CACHE_SIZE * sizeof(struct pollfd)); 391 if (!pfp) 392 return False; 393 pfp[0].fd = dpy->fd; 394 pfp[0].events = POLLIN; 395 396 dpy->filedes = (XPointer)pfp; 397#endif 398 return True; 399} 400 401void _XPollfdCacheAdd( 402 Display *dpy, 403 int fd) 404{ 405#ifdef USE_POLL 406 struct pollfd *pfp = (struct pollfd *)dpy->filedes; 407 408 if (dpy->im_fd_length <= POLLFD_CACHE_SIZE) { 409 pfp[dpy->im_fd_length].fd = fd; 410 pfp[dpy->im_fd_length].events = POLLIN; 411 } 412#endif 413} 414 415/* ARGSUSED */ 416void _XPollfdCacheDel( 417 Display *dpy, 418 int fd) /* not used */ 419{ 420#ifdef USE_POLL 421 struct pollfd *pfp = (struct pollfd *)dpy->filedes; 422 struct _XConnectionInfo *conni; 423 424 /* just recalculate whole list */ 425 if (dpy->im_fd_length <= POLLFD_CACHE_SIZE) { 426 int loc = 1; 427 for (conni = dpy->im_fd_info; conni; conni=conni->next) { 428 pfp[loc].fd = conni->fd; 429 pfp[loc].events = POLLIN; 430 loc++; 431 } 432 } 433#endif 434} 435 436#if !USE_XCB 437/* returns True iff there is an event in the queue newer than serial_num */ 438 439static Bool 440_XNewerQueuedEvent( 441 Display *dpy, 442 int serial_num) 443{ 444 _XQEvent *qev; 445 446 if (dpy->next_event_serial_num == serial_num) 447 return False; 448 449 qev = dpy->head; 450 while (qev) { 451 if (qev->qserial_num >= serial_num) { 452 return True; 453 } 454 qev = qev->next; 455 } 456 return False; 457} 458 459static int 460_XWaitForReadable( 461 Display *dpy) 462{ 463 int result; 464 int fd = dpy->fd; 465 struct _XConnectionInfo *ilist; 466 register int saved_event_serial = 0; 467 int in_read_events = 0; 468 register Bool did_proc_conni = False; 469#ifdef USE_POLL 470 struct pollfd *filedes; 471#else 472 fd_set r_mask; 473 int highest_fd = fd; 474#endif 475 476#ifdef USE_POLL 477 if (dpy->im_fd_length + 1 > POLLFD_CACHE_SIZE 478 && !(dpy->flags & XlibDisplayProcConni)) { 479 /* XXX - this fallback is gross */ 480 int i; 481 482 filedes = (struct pollfd *)Xmalloc(dpy->im_fd_length * sizeof(struct pollfd)); 483 filedes[0].fd = fd; 484 filedes[0].events = POLLIN; 485 for (ilist=dpy->im_fd_info, i=1; ilist; ilist=ilist->next, i++) { 486 filedes[i].fd = ilist->fd; 487 filedes[i].events = POLLIN; 488 } 489 } else { 490 filedes = (struct pollfd *)dpy->filedes; 491 } 492#else 493 FD_ZERO(&r_mask); 494#endif 495 for (;;) { 496#ifndef USE_POLL 497 FD_SET(fd, &r_mask); 498 if (!(dpy->flags & XlibDisplayProcConni)) 499 for (ilist=dpy->im_fd_info; ilist; ilist=ilist->next) { 500 FD_SET(ilist->fd, &r_mask); 501 if (ilist->fd > highest_fd) 502 highest_fd = ilist->fd; 503 } 504#endif 505 UnlockDisplay(dpy); 506#ifdef USE_POLL 507 result = poll(filedes, 508 (dpy->flags & XlibDisplayProcConni) ? 1 : 1+dpy->im_fd_length, 509 -1); 510#else 511 result = Select(highest_fd + 1, &r_mask, NULL, NULL, NULL); 512#endif 513 InternalLockDisplay(dpy, dpy->flags & XlibDisplayReply); 514 if (result == -1 && !ECHECK(EINTR)) _XIOError(dpy); 515 if (result <= 0) 516 continue; 517#ifdef USE_POLL 518 if (filedes[0].revents & (POLLIN|POLLHUP|POLLERR)) 519#else 520 if (FD_ISSET(fd, &r_mask)) 521#endif 522 break; 523 if (!(dpy->flags & XlibDisplayProcConni)) { 524 int i; 525 526 saved_event_serial = dpy->next_event_serial_num; 527 /* dpy flags can be clobbered by internal connection callback */ 528 in_read_events = dpy->flags & XlibDisplayReadEvents; 529 for (ilist=dpy->im_fd_info, i=1; ilist; ilist=ilist->next, i++) { 530#ifdef USE_POLL 531 if (filedes[i].revents & POLLIN) 532#else 533 if (FD_ISSET(ilist->fd, &r_mask)) 534#endif 535 { 536 _XProcessInternalConnection(dpy, ilist); 537 did_proc_conni = True; 538 } 539 } 540#ifdef USE_POLL 541 if (dpy->im_fd_length + 1 > POLLFD_CACHE_SIZE) 542 Xfree(filedes); 543#endif 544 } 545 if (did_proc_conni) { 546 /* some internal connection callback might have done an 547 XPutBackEvent. We notice it here and if we needed an event, 548 we can return all the way. */ 549 if (_XNewerQueuedEvent(dpy, saved_event_serial) 550 && (in_read_events 551#ifdef XTHREADS 552 || (dpy->lock && dpy->lock->event_awaiters) 553#endif 554 )) 555 return -2; 556 did_proc_conni = False; 557 } 558 } 559#ifdef XTHREADS 560#ifdef XTHREADS_DEBUG 561 printf("thread %x _XWaitForReadable returning\n", XThread_Self()); 562#endif 563#endif 564 return 0; 565} 566#endif /* !USE_XCB */ 567 568static 569int _XSeqSyncFunction( 570 register Display *dpy) 571{ 572 xGetInputFocusReply rep; 573 register xReq *req; 574 575 LockDisplay(dpy); 576 if ((dpy->request - dpy->last_request_read) >= (BUFSIZE / SIZEOF(xReq))) { 577 GetEmptyReq(GetInputFocus, req); 578 (void) _XReply (dpy, (xReply *)&rep, 0, xTrue); 579 } 580 /* could get XID handler while waiting for reply in MT env */ 581 if (dpy->synchandler == _XSeqSyncFunction) { 582 dpy->synchandler = dpy->savedsynchandler; 583 dpy->flags &= ~XlibDisplayPrivSync; 584 } 585 UnlockDisplay(dpy); 586 SyncHandle(); 587 return 0; 588} 589 590void _XSetSeqSyncFunction( 591 register Display *dpy) 592{ 593 if ((dpy->request - dpy->last_request_read) >= SEQLIMIT && 594 !(dpy->flags & XlibDisplayPrivSync)) { 595 dpy->savedsynchandler = dpy->synchandler; 596 dpy->synchandler = _XSeqSyncFunction; 597 dpy->flags |= XlibDisplayPrivSync; 598 } 599} 600 601#if !USE_XCB 602#ifdef XTHREADS 603static void _XFlushInt( 604 register Display *dpy, 605 register xcondition_t cv); 606#endif 607 608/* 609 * _XFlush - Flush the X request buffer. If the buffer is empty, no 610 * action is taken. This routine correctly handles incremental writes. 611 * This routine may have to be reworked if int < long. 612 */ 613void _XFlush( 614 register Display *dpy) 615{ 616#ifdef XTHREADS 617 /* With multi-threading we introduce an internal routine to which 618 we can pass a condition variable to do locking correctly. */ 619 620 _XFlushInt(dpy, NULL); 621} 622 623/* _XFlushInt - Internal version of _XFlush used to do multi-threaded 624 * locking correctly. 625 */ 626 627static void _XFlushInt( 628 register Display *dpy, 629 register xcondition_t cv) 630{ 631#endif /* XTHREADS*/ 632 register long size, todo; 633 register int write_stat; 634 register char *bufindex; 635 _XExtension *ext; 636 637 /* This fix resets the bufptr to the front of the buffer so 638 * additional appends to the bufptr will not corrupt memory. Since 639 * the server is down, these appends are no-op's anyway but 640 * callers of _XFlush() are not verifying this before they call it. 641 */ 642 if (dpy->flags & XlibDisplayIOError) 643 { 644 dpy->bufptr = dpy->buffer; 645 dpy->last_req = (char *)&_dummy_request; 646 return; 647 } 648 649#ifdef XTHREADS 650 while (dpy->flags & XlibDisplayWriting) { 651 if (dpy->lock) { 652 ConditionWait(dpy, dpy->lock->writers); 653 } else { 654 _XWaitForWritable (dpy, cv); 655 } 656 } 657#endif 658 size = todo = dpy->bufptr - dpy->buffer; 659 if (!size) return; 660#ifdef XTHREADS 661 dpy->flags |= XlibDisplayWriting; 662 /* make sure no one else can put in data */ 663 dpy->bufptr = dpy->bufmax; 664#endif 665 for (ext = dpy->flushes; ext; ext = ext->next_flush) 666 (*ext->before_flush)(dpy, &ext->codes, dpy->buffer, size); 667 bufindex = dpy->buffer; 668 /* 669 * While write has not written the entire buffer, keep looping 670 * until the entire buffer is written. bufindex will be 671 * incremented and size decremented as buffer is written out. 672 */ 673 while (size) { 674 ESET(0); 675 write_stat = _X11TransWrite(dpy->trans_conn, 676 bufindex, (int) todo); 677 if (write_stat >= 0) { 678 size -= write_stat; 679 todo = size; 680 bufindex += write_stat; 681 } else if (ETEST()) { 682 _XWaitForWritable(dpy 683#ifdef XTHREADS 684 , cv 685#endif 686 ); 687#ifdef SUNSYSV 688 } else if (ECHECK(0)) { 689 _XWaitForWritable(dpy 690#ifdef XTHREADS 691 , cv 692#endif 693 ); 694#endif 695#ifdef ESZTEST 696 } else if (ESZTEST()) { 697 if (todo > 1) 698 todo >>= 1; 699 else { 700 _XWaitForWritable(dpy 701#ifdef XTHREADS 702 , cv 703#endif 704 ); 705 } 706#endif 707 } else if (!ECHECK(EINTR)) { 708 /* Write failed! */ 709 /* errno set by write system call. */ 710 _XIOError(dpy); 711 } 712 } 713 dpy->last_req = (char *)&_dummy_request; 714 _XSetSeqSyncFunction(dpy); 715 dpy->bufptr = dpy->buffer; 716#ifdef XTHREADS 717 dpy->flags &= ~XlibDisplayWriting; 718#endif 719} 720 721int 722_XEventsQueued( 723 register Display *dpy, 724 int mode) 725{ 726 register int len; 727 BytesReadable_t pend; 728 _XAlignedBuffer buf; 729 register xReply *rep; 730 char *read_buf; 731#ifdef XTHREADS 732 int entry_event_serial_num; 733 struct _XCVList *cvl = NULL; 734 xthread_t self; 735 736#ifdef XTHREADS_DEBUG 737 printf("_XEventsQueued called in thread %x\n", XThread_Self()); 738#endif 739#endif /* XTHREADS*/ 740 741 if (mode == QueuedAfterFlush) 742 { 743 _XFlush(dpy); 744 if (dpy->qlen) 745 return(dpy->qlen); 746 } 747 if (dpy->flags & XlibDisplayIOError) return(dpy->qlen); 748 749#ifdef XTHREADS 750 /* create our condition variable and append to list, 751 * unless we were called from within XProcessInternalConnection 752 * or XLockDisplay 753 */ 754 xthread_clear_id(self); 755 if (dpy->lock && (xthread_have_id (dpy->lock->conni_thread) 756 || xthread_have_id (dpy->lock->locking_thread))) 757 /* some thread is in XProcessInternalConnection or XLockDisplay 758 so we have to see if we are it */ 759 self = XThread_Self(); 760 if (!xthread_have_id(self) 761 || (!xthread_equal(self, dpy->lock->conni_thread) 762 && !xthread_equal(self, dpy->lock->locking_thread))) { 763 /* In the multi-threaded case, if there is someone else 764 reading events, then there aren't any available, so 765 we just return. If we waited we would block. 766 */ 767 if (dpy->lock && dpy->lock->event_awaiters) 768 return dpy->qlen; 769 /* nobody here but us, so lock out any newcomers */ 770 cvl = QueueEventReaderLock(dpy); 771 } 772 773 while (dpy->lock && cvl && dpy->lock->reply_first) { 774 /* note which events we have already seen so we'll know 775 if _XReply (in another thread) reads one */ 776 entry_event_serial_num = dpy->next_event_serial_num; 777 ConditionWait(dpy, cvl->cv); 778 /* did _XReply read an event we can return? */ 779 if (_XNewerQueuedEvent(dpy, entry_event_serial_num)) 780 { 781 UnlockNextEventReader(dpy); 782 return 0; 783 } 784 } 785#endif /* XTHREADS*/ 786 787 if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0) 788 _XIOError(dpy); 789#ifdef XCONN_CHECK_FREQ 790 /* This is a crock, required because FIONREAD or equivalent is 791 * not guaranteed to detect a broken connection. 792 */ 793 if (!pend && !dpy->qlen && ++dpy->conn_checker >= XCONN_CHECK_FREQ) 794 { 795 int result; 796#ifdef USE_POLL 797 struct pollfd filedes; 798#else 799 fd_set r_mask; 800 static struct timeval zero_time; 801#endif 802 803 dpy->conn_checker = 0; 804#ifdef USE_POLL 805 filedes.fd = dpy->fd; 806 filedes.events = POLLIN; 807 if ((result = poll(&filedes, 1, 0))) 808#else 809 FD_ZERO(&r_mask); 810 FD_SET(dpy->fd, &r_mask); 811 if ((result = Select(dpy->fd + 1, &r_mask, NULL, NULL, &zero_time))) 812#endif 813 { 814 if (result > 0) 815 { 816 if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0) 817 _XIOError(dpy); 818 /* we should not get zero, if we do, force a read */ 819 if (!pend) 820 pend = SIZEOF(xReply); 821 } 822 else if (result < 0 && !ECHECK(EINTR)) 823 _XIOError(dpy); 824 } 825 } 826#endif /* XCONN_CHECK_FREQ */ 827 if (!(len = pend)) { 828 /* _XFlush can enqueue events */ 829#ifdef XTHREADS 830 if (cvl) 831#endif 832 { 833 UnlockNextEventReader(dpy); 834 } 835 return(dpy->qlen); 836 } 837 /* Force a read if there is not enough data. Otherwise, 838 * a select() loop at a higher-level will spin undesirably, 839 * and we've seen at least one OS that appears to not update 840 * the result from FIONREAD once it has returned nonzero. 841 */ 842#ifdef XTHREADS 843 if (dpy->lock && dpy->lock->reply_awaiters) { 844 read_buf = (char *)dpy->lock->reply_awaiters->buf; 845 len = SIZEOF(xReply); 846 } else 847#endif /* XTHREADS*/ 848 { 849 read_buf = buf.buf; 850 851 if (len < SIZEOF(xReply) 852#ifdef XTHREADS 853 || dpy->async_handlers 854#endif 855 ) 856 len = SIZEOF(xReply); 857 else if (len > BUFSIZE) 858 len = BUFSIZE; 859 len = (len / SIZEOF(xReply)) * SIZEOF(xReply); 860 } 861#ifdef XCONN_CHECK_FREQ 862 dpy->conn_checker = 0; 863#endif 864 865 (void) _XRead (dpy, read_buf, (long) len); 866 867#ifdef XTHREADS 868 /* what did we actually read: reply or event? */ 869 if (dpy->lock && dpy->lock->reply_awaiters) { 870 if (((xReply *)read_buf)->generic.type == X_Reply || 871 ((xReply *)read_buf)->generic.type == X_Error) 872 { 873 dpy->lock->reply_was_read = True; 874 dpy->lock->reply_first = True; 875 if (read_buf != (char *)dpy->lock->reply_awaiters->buf) 876 memcpy(dpy->lock->reply_awaiters->buf, read_buf, 877 len); 878 if (cvl) { 879 UnlockNextEventReader(dpy); 880 } 881 return(dpy->qlen); /* we read, so we can return */ 882 } else if (read_buf != buf.buf) 883 memcpy(buf.buf, read_buf, len); 884 } 885#endif /* XTHREADS*/ 886 887 STARTITERATE(rep,xReply,buf.buf,len > 0) { 888 if (rep->generic.type == X_Reply) { 889 int tmp = len; 890 RESETITERPTR(rep,xReply, 891 _XAsyncReply (dpy, rep, 892 ITERPTR(rep), &tmp, True)); 893 len = tmp; 894 pend = len; 895 } else { 896 if (rep->generic.type == X_Error) 897 _XError (dpy, (xError *)rep); 898 else /* must be an event packet */ 899 _XEnq (dpy, (xEvent *)rep); 900 INCITERPTR(rep,xReply); 901 len -= SIZEOF(xReply); 902 } 903 } ENDITERATE 904 905#ifdef XTHREADS 906 if (cvl) 907#endif 908 { 909 UnlockNextEventReader(dpy); 910 } 911 return(dpy->qlen); 912} 913 914/* _XReadEvents - Flush the output queue, 915 * then read as many events as possible (but at least 1) and enqueue them 916 */ 917void _XReadEvents( 918 register Display *dpy) 919{ 920 _XAlignedBuffer buf; 921 BytesReadable_t pend; 922 int len; 923 register xReply *rep; 924 Bool not_yet_flushed = True; 925 char *read_buf; 926 int i; 927 int entry_event_serial_num = dpy->next_event_serial_num; 928#ifdef XTHREADS 929 struct _XCVList *cvl = NULL; 930 xthread_t self; 931 932#ifdef XTHREADS_DEBUG 933 printf("_XReadEvents called in thread %x\n", 934 XThread_Self()); 935#endif 936 /* create our condition variable and append to list, 937 * unless we were called from within XProcessInternalConnection 938 * or XLockDisplay 939 */ 940 xthread_clear_id(self); 941 if (dpy->lock && (xthread_have_id (dpy->lock->conni_thread) 942 || xthread_have_id (dpy->lock->locking_thread))) 943 /* some thread is in XProcessInternalConnection or XLockDisplay 944 so we have to see if we are it */ 945 self = XThread_Self(); 946 if (!xthread_have_id(self) 947 || (!xthread_equal(self, dpy->lock->conni_thread) 948 && !xthread_equal(self, dpy->lock->locking_thread))) 949 cvl = QueueEventReaderLock(dpy); 950#endif /* XTHREADS */ 951 952 do { 953#ifdef XTHREADS 954 /* if it is not our turn to read an event off the wire, 955 wait til we're at head of list */ 956 if (dpy->lock && cvl && 957 (dpy->lock->event_awaiters != cvl || 958 dpy->lock->reply_first)) { 959 ConditionWait(dpy, cvl->cv); 960 continue; 961 } 962#endif /* XTHREADS */ 963 /* find out how much data can be read */ 964 if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0) 965 _XIOError(dpy); 966 len = pend; 967 968 /* must read at least one xEvent; if none is pending, then 969 we'll just flush and block waiting for it */ 970 if (len < SIZEOF(xEvent) 971#ifdef XTHREADS 972 || dpy->async_handlers 973#endif 974 ) { 975 len = SIZEOF(xEvent); 976 /* don't flush until the first time we would block */ 977 if (not_yet_flushed) { 978 _XFlush (dpy); 979 if (_XNewerQueuedEvent(dpy, entry_event_serial_num)) { 980 /* _XReply has read an event for us */ 981 goto got_event; 982 } 983 not_yet_flushed = False; 984 } 985 } 986 987#ifdef XTHREADS 988 /* If someone is waiting for a reply, gamble that 989 the reply will be the next thing on the wire 990 and read it into their buffer. */ 991 if (dpy->lock && dpy->lock->reply_awaiters) { 992 read_buf = (char *)dpy->lock->reply_awaiters->buf; 993 len = SIZEOF(xReply); 994 } else 995#endif /* XTHREADS*/ 996 { 997 read_buf = buf.buf; 998 999 /* but we won't read more than the max buffer size */ 1000 if (len > BUFSIZE) 1001 len = BUFSIZE; 1002 1003 /* round down to an integral number of XReps */ 1004 len = (len / SIZEOF(xEvent)) * SIZEOF(xEvent); 1005 } 1006 1007#ifdef XTHREADS 1008 if (xthread_have_id(self)) 1009 /* save value we may have to stick in conni_thread */ 1010 dpy->lock->reading_thread = self; 1011#endif /* XTHREADS */ 1012 dpy->flags |= XlibDisplayReadEvents; 1013 i = _XRead (dpy, read_buf, (long) len); 1014 dpy->flags &= ~XlibDisplayReadEvents; 1015 if (i == -2) { 1016 /* special flag from _XRead to say that internal connection has 1017 done XPutBackEvent. Which we can use so we're done. */ 1018 got_event: 1019#ifdef XTHREADS 1020 if (dpy->lock && dpy->lock->lock_wait) { 1021 if (dpy->lock->event_awaiters != cvl) 1022 /* since it is not us, must be user lock thread */ 1023 ConditionSignal(dpy, 1024 dpy->lock->event_awaiters->cv); 1025 (*dpy->lock->lock_wait)(dpy); 1026 continue; 1027 } 1028#endif 1029 break; 1030 } 1031#ifdef XTHREADS 1032 if (xthread_have_id(self)) 1033 xthread_clear_id(dpy->lock->reading_thread); 1034 1035 /* what did we actually read: reply or event? */ 1036 if (dpy->lock && dpy->lock->reply_awaiters) { 1037 if (((xReply *)read_buf)->generic.type == X_Reply || 1038 ((xReply *)read_buf)->generic.type == X_Error) 1039 { 1040 dpy->lock->reply_was_read = True; 1041 dpy->lock->reply_first = True; 1042 if (read_buf != (char *)dpy->lock->reply_awaiters->buf) 1043 memcpy(dpy->lock->reply_awaiters->buf, 1044 read_buf, len); 1045 ConditionSignal(dpy, dpy->lock->reply_awaiters->cv); 1046 continue; 1047 } else if (read_buf != buf.buf) 1048 memcpy(buf.buf, read_buf, len); 1049 } 1050#endif /* XTHREADS */ 1051 1052 STARTITERATE(rep,xReply,buf.buf,len > 0) { 1053 if (rep->generic.type == X_Reply) { 1054 RESETITERPTR(rep,xReply, 1055 _XAsyncReply (dpy, rep, 1056 ITERPTR(rep), &len, True)); 1057 pend = len; 1058 } else { 1059 if (rep->generic.type == X_Error) 1060 _XError (dpy, (xError *) rep); 1061 else /* must be an event packet */ 1062 _XEnq (dpy, (xEvent *)rep); 1063 INCITERPTR(rep,xReply); 1064 len -= SIZEOF(xReply); 1065 } 1066 } ENDITERATE; 1067 } while (!_XNewerQueuedEvent(dpy, entry_event_serial_num)); 1068 1069 UnlockNextEventReader(dpy); 1070} 1071 1072/* 1073 * _XRead - Read bytes from the socket taking into account incomplete 1074 * reads. This routine may have to be reworked if int < long. 1075 */ 1076int _XRead( 1077 register Display *dpy, 1078 register char *data, 1079 register long size) 1080{ 1081 register long bytes_read; 1082#ifdef XTHREADS 1083 int original_size = size; 1084#endif 1085 1086 if ((dpy->flags & XlibDisplayIOError) || size == 0) 1087 return 0; 1088 ESET(0); 1089 while ((bytes_read = _X11TransRead(dpy->trans_conn, data, (int)size)) 1090 != size) { 1091 1092 if (bytes_read > 0) { 1093 size -= bytes_read; 1094 data += bytes_read; 1095 } 1096 else if (ETEST()) { 1097 if (_XWaitForReadable(dpy) == -2) 1098 return -2; /* internal connection did XPutBackEvent */ 1099 ESET(0); 1100 } 1101#ifdef SUNSYSV 1102 else if (ECHECK(0)) { 1103 if (_XWaitForReadable(dpy) == -2) 1104 return -2; /* internal connection did XPutBackEvent */ 1105 } 1106#endif 1107 else if (bytes_read == 0) { 1108 /* Read failed because of end of file! */ 1109 ESET(EPIPE); 1110 _XIOError(dpy); 1111 } 1112 1113 else /* bytes_read is less than 0; presumably -1 */ { 1114 /* If it's a system call interrupt, it's not an error. */ 1115 if (!ECHECK(EINTR)) 1116 _XIOError(dpy); 1117 } 1118 } 1119#ifdef XTHREADS 1120 if (dpy->lock && dpy->lock->reply_bytes_left > 0) 1121 { 1122 dpy->lock->reply_bytes_left -= original_size; 1123 if (dpy->lock->reply_bytes_left == 0) { 1124 dpy->flags &= ~XlibDisplayReply; 1125 UnlockNextReplyReader(dpy); 1126 } 1127 } 1128#endif /* XTHREADS*/ 1129 return 0; 1130} 1131#endif /* !USE_XCB */ 1132 1133#ifdef LONG64 1134void _XRead32( 1135 Display *dpy, 1136 register long *data, 1137 long len) 1138{ 1139 register int *buf; 1140 register long i; 1141 1142 if (len) { 1143 (void) _XRead(dpy, (char *)data, len); 1144 i = len >> 2; 1145 buf = (int *)data + i; 1146 data += i; 1147 while (--i >= 0) 1148 *--data = *--buf; 1149 } 1150} 1151#endif /* LONG64 */ 1152 1153#ifdef WORD64 1154 1155/* 1156 * XXX This is a *really* stupid way of doing this.... 1157 * PACKBUFFERSIZE must be a multiple of 4. 1158 */ 1159 1160#define PACKBUFFERSIZE 4096 1161 1162 1163/* 1164 * _XRead32 - Read bytes from the socket unpacking each 32 bits 1165 * into a long (64 bits on a CRAY computer). 1166 * 1167 */ 1168static void _doXRead32( 1169 register Display *dpy, 1170 register long *data 1171 register long size, 1172 register char *packbuffer) 1173{ 1174 long *lpack,*lp; 1175 long mask32 = 0x00000000ffffffff; 1176 long maskw, nwords, i, bits; 1177 1178 _XReadPad (dpy, packbuffer, size); 1179 1180 lp = data; 1181 lpack = (long *) packbuffer; 1182 nwords = size >> 2; 1183 bits = 32; 1184 1185 for(i=0;i<nwords;i++){ 1186 maskw = mask32 << bits; 1187 *lp++ = ( *lpack & maskw ) >> bits; 1188 bits = bits ^32; 1189 if(bits){ 1190 lpack++; 1191 } 1192 } 1193} 1194 1195void _XRead32( 1196 Display *dpy, 1197 long *data, 1198 long len) 1199{ 1200 char packbuffer[PACKBUFFERSIZE]; 1201 unsigned nunits = PACKBUFFERSIZE >> 2; 1202 1203 for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) { 1204 _doXRead32 (dpy, data, PACKBUFFERSIZE, packbuffer); 1205 } 1206 if (len) _doXRead32 (dpy, data, len, packbuffer); 1207} 1208 1209 1210 1211/* 1212 * _XRead16 - Read bytes from the socket unpacking each 16 bits 1213 * into a long (64 bits on a CRAY computer). 1214 * 1215 */ 1216static _doXRead16( 1217 register Display *dpy, 1218 register short *data, 1219 register long size, 1220 char *packbuffer) 1221{ 1222 long *lpack,*lp; 1223 long mask16 = 0x000000000000ffff; 1224 long maskw, nwords, i, bits; 1225 1226 (void) _XRead(dpy,packbuffer,size); /* don't do a padded read... */ 1227 1228 lp = (long *) data; 1229 lpack = (long *) packbuffer; 1230 nwords = size >> 1; /* number of 16 bit words to be unpacked */ 1231 bits = 48; 1232 for(i=0;i<nwords;i++){ 1233 maskw = mask16 << bits; 1234 *lp++ = ( *lpack & maskw ) >> bits; 1235 bits -= 16; 1236 if(bits < 0){ 1237 lpack++; 1238 bits = 48; 1239 } 1240 } 1241} 1242 1243void _XRead16( 1244 Display *dpy, 1245 short *data, 1246 long len) 1247{ 1248 char packbuffer[PACKBUFFERSIZE]; 1249 unsigned nunits = PACKBUFFERSIZE >> 1; 1250 1251 for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) { 1252 _doXRead16 (dpy, data, PACKBUFFERSIZE, packbuffer); 1253 } 1254 if (len) _doXRead16 (dpy, data, len, packbuffer); 1255} 1256 1257void _XRead16Pad( 1258 Display *dpy, 1259 short *data, 1260 long size) 1261{ 1262 int slop = (size & 3); 1263 short slopbuf[3]; 1264 1265 _XRead16 (dpy, data, size); 1266 if (slop > 0) { 1267 _XRead16 (dpy, slopbuf, 4 - slop); 1268 } 1269} 1270#endif /* WORD64 */ 1271 1272 1273#if !USE_XCB 1274/* 1275 * _XReadPad - Read bytes from the socket taking into account incomplete 1276 * reads. If the number of bytes is not 0 mod 4, read additional pad 1277 * bytes. This routine may have to be reworked if int < long. 1278 */ 1279void _XReadPad( 1280 register Display *dpy, 1281 register char *data, 1282 register long size) 1283{ 1284 register long bytes_read; 1285 struct iovec iov[2]; 1286 char pad[3]; 1287#ifdef XTHREADS 1288 int original_size; 1289#endif 1290 1291 if ((dpy->flags & XlibDisplayIOError) || size == 0) return; 1292 iov[0].iov_len = (int)size; 1293 iov[0].iov_base = data; 1294 /* 1295 * The following hack is used to provide 32 bit long-word 1296 * aligned padding. The [1] vector is of length 0, 1, 2, or 3, 1297 * whatever is needed. 1298 */ 1299 1300 iov[1].iov_len = -size & 3; 1301 iov[1].iov_base = pad; 1302 size += iov[1].iov_len; 1303#ifdef XTHREADS 1304 original_size = size; 1305#endif 1306 ESET(0); 1307 while ((bytes_read = _X11TransReadv (dpy->trans_conn, iov, 2)) != size) { 1308 1309 if (bytes_read > 0) { 1310 size -= bytes_read; 1311 if (iov[0].iov_len < bytes_read) { 1312 int pad_bytes_read = bytes_read - iov[0].iov_len; 1313 iov[1].iov_len -= pad_bytes_read; 1314 iov[1].iov_base = 1315 (char *)iov[1].iov_base + pad_bytes_read; 1316 iov[0].iov_len = 0; 1317 } 1318 else { 1319 iov[0].iov_len -= bytes_read; 1320 iov[0].iov_base = (char *)iov[0].iov_base + bytes_read; 1321 } 1322 } 1323 else if (ETEST()) { 1324 _XWaitForReadable(dpy); 1325 ESET(0); 1326 } 1327#ifdef SUNSYSV 1328 else if (ECHECK(0)) { 1329 _XWaitForReadable(dpy); 1330 } 1331#endif 1332 else if (bytes_read == 0) { 1333 /* Read failed because of end of file! */ 1334 ESET(EPIPE); 1335 _XIOError(dpy); 1336 } 1337 1338 else /* bytes_read is less than 0; presumably -1 */ { 1339 /* If it's a system call interrupt, it's not an error. */ 1340 if (!ECHECK(EINTR)) 1341 _XIOError(dpy); 1342 } 1343 } 1344#ifdef XTHREADS 1345 if (dpy->lock && dpy->lock->reply_bytes_left > 0) 1346 { 1347 dpy->lock->reply_bytes_left -= original_size; 1348 if (dpy->lock->reply_bytes_left == 0) { 1349 dpy->flags &= ~XlibDisplayReply; 1350 UnlockNextReplyReader(dpy); 1351 } 1352 } 1353#endif /* XTHREADS*/ 1354} 1355 1356/* 1357 * _XSend - Flush the buffer and send the client data. 32 bit word aligned 1358 * transmission is used, if size is not 0 mod 4, extra bytes are transmitted. 1359 * This routine may have to be reworked if int < long; 1360 */ 1361void 1362_XSend ( 1363 register Display *dpy, 1364 _Xconst char *data, 1365 register long size) 1366{ 1367 struct iovec iov[3]; 1368 static char const pad[3] = {0, 0, 0}; 1369 /* XText8 and XText16 require that the padding bytes be zero! */ 1370 1371 long skip, dbufsize, padsize, total, todo; 1372 _XExtension *ext; 1373 1374 if (!size || (dpy->flags & XlibDisplayIOError)) return; 1375 dbufsize = dpy->bufptr - dpy->buffer; 1376#ifdef XTHREADS 1377 dpy->flags |= XlibDisplayWriting; 1378 /* make sure no one else can put in data */ 1379 dpy->bufptr = dpy->bufmax; 1380#endif 1381 padsize = -size & 3; 1382 for (ext = dpy->flushes; ext; ext = ext->next_flush) { 1383 (*ext->before_flush)(dpy, &ext->codes, dpy->buffer, dbufsize); 1384 (*ext->before_flush)(dpy, &ext->codes, (char *)data, size); 1385 if (padsize) 1386 (*ext->before_flush)(dpy, &ext->codes, pad, padsize); 1387 } 1388 skip = 0; 1389 todo = total = dbufsize + size + padsize; 1390 1391 /* 1392 * There are 3 pieces that may need to be written out: 1393 * 1394 * o whatever is in the display buffer 1395 * o the data passed in by the user 1396 * o any padding needed to 32bit align the whole mess 1397 * 1398 * This loop looks at all 3 pieces each time through. It uses skip 1399 * to figure out whether or not a given piece is needed. 1400 */ 1401 while (total) { 1402 long before = skip; /* amount of whole thing written */ 1403 long remain = todo; /* amount to try this time, <= total */ 1404 int i = 0; 1405 long len; 1406 1407 /* You could be very general here and have "in" and "out" iovecs 1408 * and write a loop without using a macro, but what the heck. This 1409 * translates to: 1410 * 1411 * how much of this piece is new? 1412 * if more new then we are trying this time, clamp 1413 * if nothing new 1414 * then bump down amount already written, for next piece 1415 * else put new stuff in iovec, will need all of next piece 1416 * 1417 * Note that todo had better be at least 1 or else we'll end up 1418 * writing 0 iovecs. 1419 */ 1420#define InsertIOV(pointer, length) \ 1421 len = (length) - before; \ 1422 if (len > remain) \ 1423 len = remain; \ 1424 if (len <= 0) { \ 1425 before = (-len); \ 1426 } else { \ 1427 iov[i].iov_len = len; \ 1428 iov[i].iov_base = (pointer) + before; \ 1429 i++; \ 1430 remain -= len; \ 1431 before = 0; \ 1432 } 1433 1434 InsertIOV (dpy->buffer, dbufsize) 1435 InsertIOV ((char *)data, size) 1436 InsertIOV ((char *)pad, padsize) 1437 1438 ESET(0); 1439 if ((len = _X11TransWritev(dpy->trans_conn, iov, i)) >= 0) { 1440 skip += len; 1441 total -= len; 1442 todo = total; 1443 } else if (ETEST()) { 1444 _XWaitForWritable(dpy 1445#ifdef XTHREADS 1446 , NULL 1447#endif 1448 ); 1449#ifdef SUNSYSV 1450 } else if (ECHECK(0)) { 1451 _XWaitForWritable(dpy 1452#ifdef XTHREADS 1453 , NULL 1454#endif 1455 ); 1456#endif 1457#ifdef ESZTEST 1458 } else if (ESZTEST()) { 1459 if (todo > 1) 1460 todo >>= 1; 1461 else { 1462 _XWaitForWritable(dpy 1463#ifdef XTHREADS 1464 , NULL 1465#endif 1466 ); 1467 } 1468#endif 1469 } else if (!ECHECK(EINTR)) { 1470 _XIOError(dpy); 1471 } 1472 } 1473 dpy->last_req = (char *) & _dummy_request; 1474 _XSetSeqSyncFunction(dpy); 1475 dpy->bufptr = dpy->buffer; 1476#ifdef XTHREADS 1477 dpy->flags &= ~XlibDisplayWriting; 1478#endif 1479 return; 1480} 1481 1482static void 1483_XGetMiscCode( 1484 register Display *dpy) 1485{ 1486 xQueryExtensionReply qrep; 1487 register xQueryExtensionReq *qreq; 1488 xXCMiscGetVersionReply vrep; 1489 register xXCMiscGetVersionReq *vreq; 1490 1491 if (dpy->xcmisc_opcode) 1492 return; 1493 GetReq(QueryExtension, qreq); 1494 qreq->nbytes = sizeof(XCMiscExtensionName) - 1; 1495 qreq->length += (qreq->nbytes+(unsigned)3)>>2; 1496 _XSend(dpy, XCMiscExtensionName, (long)qreq->nbytes); 1497 if (!_XReply (dpy, (xReply *)&qrep, 0, xTrue)) 1498 dpy->xcmisc_opcode = -1; 1499 else { 1500 GetReq(XCMiscGetVersion, vreq); 1501 vreq->reqType = qrep.major_opcode; 1502 vreq->miscReqType = X_XCMiscGetVersion; 1503 vreq->majorVersion = XCMiscMajorVersion; 1504 vreq->minorVersion = XCMiscMinorVersion; 1505 if (!_XReply (dpy, (xReply *)&vrep, 0, xTrue)) 1506 dpy->xcmisc_opcode = -1; 1507 else 1508 dpy->xcmisc_opcode = qrep.major_opcode; 1509 } 1510} 1511 1512static int 1513_XIDHandler( 1514 register Display *dpy) 1515{ 1516 xXCMiscGetXIDRangeReply grep; 1517 register xXCMiscGetXIDRangeReq *greq; 1518 1519 LockDisplay(dpy); 1520 _XGetMiscCode(dpy); 1521 if (dpy->xcmisc_opcode > 0) { 1522 GetReq(XCMiscGetXIDRange, greq); 1523 greq->reqType = dpy->xcmisc_opcode; 1524 greq->miscReqType = X_XCMiscGetXIDRange; 1525 if (_XReply (dpy, (xReply *)&grep, 0, xTrue) && grep.count) { 1526 dpy->resource_id = ((grep.start_id - dpy->resource_base) >> 1527 dpy->resource_shift); 1528 dpy->resource_max = dpy->resource_id; 1529 if (grep.count > 5) 1530 dpy->resource_max += grep.count - 6; 1531 dpy->resource_max <<= dpy->resource_shift; 1532 } 1533 } 1534 if (dpy->flags & XlibDisplayPrivSync) { 1535 dpy->synchandler = dpy->savedsynchandler; 1536 dpy->flags &= ~XlibDisplayPrivSync; 1537 } 1538 UnlockDisplay(dpy); 1539 SyncHandle(); 1540 return 0; 1541} 1542 1543/* 1544 * _XAllocID - resource ID allocation routine. 1545 */ 1546XID _XAllocID( 1547 register Display *dpy) 1548{ 1549 XID id; 1550 1551 id = dpy->resource_id << dpy->resource_shift; 1552 if (id >= dpy->resource_max) { 1553 if (!(dpy->flags & XlibDisplayPrivSync)) { 1554 dpy->savedsynchandler = dpy->synchandler; 1555 dpy->flags |= XlibDisplayPrivSync; 1556 } 1557 dpy->synchandler = _XIDHandler; 1558 dpy->resource_max = dpy->resource_mask + 1; 1559 } 1560 if (id <= dpy->resource_mask) { 1561 dpy->resource_id++; 1562 return (dpy->resource_base + id); 1563 } 1564 if (id != 0x10000000) { 1565 (void) fprintf(stderr, 1566 "Xlib: resource ID allocation space exhausted!\n"); 1567 id = 0x10000000; 1568 dpy->resource_id = id >> dpy->resource_shift; 1569 } 1570 return id; 1571} 1572 1573/* 1574 * _XAllocIDs - multiple resource ID allocation routine. 1575 */ 1576void _XAllocIDs( 1577 register Display *dpy, 1578 XID *ids, 1579 int count) 1580{ 1581 XID id; 1582 int i; 1583 xXCMiscGetXIDListReply grep; 1584 register xXCMiscGetXIDListReq *greq; 1585 1586 id = dpy->resource_id << dpy->resource_shift; 1587 if (dpy->resource_max <= dpy->resource_mask && 1588 id <= dpy->resource_mask && 1589 (dpy->resource_max - id) > ((count - 1) << dpy->resource_shift)) { 1590 id += dpy->resource_base; 1591 for (i = 0; i < count; i++) { 1592 ids[i] = id; 1593 id += (1 << dpy->resource_shift); 1594 dpy->resource_id++; 1595 } 1596 return; 1597 } 1598 grep.count = 0; 1599 _XGetMiscCode(dpy); 1600 if (dpy->xcmisc_opcode > 0) { 1601 GetReq(XCMiscGetXIDList, greq); 1602 greq->reqType = dpy->xcmisc_opcode; 1603 greq->miscReqType = X_XCMiscGetXIDList; 1604 greq->count = count; 1605 if (_XReply(dpy, (xReply *)&grep, 0, xFalse) && grep.count) { 1606 _XRead32(dpy, (long *) ids, 4L * (long) (grep.count)); 1607 for (i = 0; i < grep.count; i++) { 1608 id = (ids[i] - dpy->resource_base) >> dpy->resource_shift; 1609 if (id >= dpy->resource_id) 1610 dpy->resource_id = id; 1611 } 1612 if (id >= dpy->resource_max) { 1613 if (!(dpy->flags & XlibDisplayPrivSync)) { 1614 dpy->savedsynchandler = dpy->synchandler; 1615 dpy->flags |= XlibDisplayPrivSync; 1616 } 1617 dpy->synchandler = _XIDHandler; 1618 dpy->resource_max = dpy->resource_mask + 1; 1619 } 1620 } 1621 } 1622 for (i = grep.count; i < count; i++) 1623 ids[i] = XAllocID(dpy); 1624} 1625#endif /* !USE_XCB */ 1626 1627/* 1628 * The hard part about this is that we only get 16 bits from a reply. 1629 * We have three values that will march along, with the following invariant: 1630 * dpy->last_request_read <= rep->sequenceNumber <= dpy->request 1631 * We have to keep 1632 * dpy->request - dpy->last_request_read < 2^16 1633 * or else we won't know for sure what value to use in events. We do this 1634 * by forcing syncs when we get close. 1635 */ 1636 1637unsigned long 1638_XSetLastRequestRead( 1639 register Display *dpy, 1640 register xGenericReply *rep) 1641{ 1642 register unsigned long newseq, lastseq; 1643 1644 lastseq = dpy->last_request_read; 1645 /* 1646 * KeymapNotify has no sequence number, but is always guaranteed 1647 * to immediately follow another event, except when generated via 1648 * SendEvent (hmmm). 1649 */ 1650 if ((rep->type & 0x7f) == KeymapNotify) 1651 return(lastseq); 1652 1653 newseq = (lastseq & ~((unsigned long)0xffff)) | rep->sequenceNumber; 1654 1655 if (newseq < lastseq) { 1656 newseq += 0x10000; 1657 if (newseq > dpy->request) { 1658 (void) fprintf (stderr, 1659 "Xlib: sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n", 1660 newseq, dpy->request, 1661 (unsigned int) rep->type); 1662 newseq -= 0x10000; 1663 } 1664 } 1665 1666 dpy->last_request_read = newseq; 1667 return(newseq); 1668} 1669 1670#if !USE_XCB 1671/* 1672 * _XReply - Wait for a reply packet and copy its contents into the 1673 * specified rep. Meanwhile we must handle error and event packets that 1674 * we may encounter. 1675 */ 1676Status 1677_XReply ( 1678 register Display *dpy, 1679 register xReply *rep, 1680 int extra, /* number of 32-bit words expected after the reply */ 1681 Bool discard) /* should I discard data following "extra" words? */ 1682{ 1683 /* Pull out the serial number now, so that (currently illegal) requests 1684 * generated by an error handler don't confuse us. 1685 */ 1686 unsigned long cur_request = dpy->request; 1687#ifdef XTHREADS 1688 struct _XCVList *cvl; 1689#endif 1690 1691 if (dpy->flags & XlibDisplayIOError) 1692 return 0; 1693 1694#ifdef XTHREADS 1695 /* create our condition variable and append to list */ 1696 cvl = QueueReplyReaderLock(dpy); 1697 if (cvl) { 1698 cvl->buf = rep; 1699 if (dpy->lock->reply_awaiters == cvl && !dpy->lock->event_awaiters) 1700 dpy->lock->reply_first = True; 1701 } 1702 1703#ifdef XTHREADS_DEBUG 1704 printf("_XReply called in thread %x, adding %x to cvl\n", 1705 XThread_Self(), cvl); 1706#endif 1707 1708 _XFlushInt(dpy, cvl ? cvl->cv : NULL); 1709 /* if it is not our turn to read a reply off the wire, 1710 * wait til we're at head of list. if there is an event waiter, 1711 * and our reply hasn't been read, they'll be in select and will 1712 * hand control back to us next. 1713 */ 1714 if(dpy->lock && 1715 (dpy->lock->reply_awaiters != cvl || !dpy->lock->reply_first)) { 1716 ConditionWait(dpy, cvl->cv); 1717 } 1718 dpy->flags |= XlibDisplayReply; 1719#else /* XTHREADS else */ 1720 _XFlush(dpy); 1721#endif 1722 1723 for (;;) { 1724#ifdef XTHREADS 1725 /* Did another thread's _XReadEvents get our reply by accident? */ 1726 if (!dpy->lock || !dpy->lock->reply_was_read) 1727#endif 1728 (void) _XRead(dpy, (char *)rep, (long)SIZEOF(xReply)); 1729#ifdef XTHREADS 1730 if (dpy->lock) 1731 dpy->lock->reply_was_read = False; 1732#endif 1733 1734 switch ((int)rep->generic.type) { 1735 1736 case X_Reply: 1737 /* Reply received. Fast update for synchronous replies, 1738 * but deal with multiple outstanding replies. 1739 */ 1740 if (rep->generic.sequenceNumber == (cur_request & 0xffff)) 1741 dpy->last_request_read = cur_request; 1742 else { 1743 int pend = SIZEOF(xReply); 1744 if (_XAsyncReply(dpy, rep, (char *)rep, &pend, False) 1745 != (char *)rep) 1746 continue; 1747 } 1748 if (extra <= rep->generic.length) { 1749 if (extra > 0) 1750 /* 1751 * Read the extra data into storage immediately 1752 * following the GenericReply structure. 1753 */ 1754 (void) _XRead (dpy, (char *) (NEXTPTR(rep,xReply)), 1755 ((long)extra) << 2); 1756 if (discard) { 1757 if (extra < rep->generic.length) 1758 _XEatData(dpy, (rep->generic.length - extra) << 2); 1759 } 1760#ifdef XTHREADS 1761 if (dpy->lock) { 1762 if (discard) { 1763 dpy->lock->reply_bytes_left = 0; 1764 } else { 1765 dpy->lock->reply_bytes_left = 1766 (rep->generic.length - extra) << 2; 1767 } 1768 if (dpy->lock->reply_bytes_left == 0) { 1769 dpy->flags &= ~XlibDisplayReply; 1770 UnlockNextReplyReader(dpy); 1771 } 1772 } else 1773 dpy->flags &= ~XlibDisplayReply; 1774#endif 1775 return 1; 1776 } 1777 /* 1778 *if we get here, then extra > rep->generic.length--meaning we 1779 * read a reply that's shorter than we expected. This is an 1780 * error, but we still need to figure out how to handle it... 1781 */ 1782 (void) _XRead (dpy, (char *) (NEXTPTR(rep,xReply)), 1783 ((long) rep->generic.length) << 2); 1784 dpy->flags &= ~XlibDisplayReply; 1785 UnlockNextReplyReader(dpy); 1786 _XIOError (dpy); 1787 return (0); 1788 1789 case X_Error: 1790 { 1791 register _XExtension *ext; 1792 register Bool ret = False; 1793 int ret_code; 1794 xError *err = (xError *) rep; 1795 unsigned long serial; 1796 1797 dpy->flags &= ~XlibDisplayReply; 1798 serial = _XSetLastRequestRead(dpy, (xGenericReply *)rep); 1799 if (serial == cur_request) 1800 /* do not die on "no such font", "can't allocate", 1801 "can't grab" failures */ 1802 switch ((int)err->errorCode) { 1803 case BadName: 1804 switch (err->majorCode) { 1805 case X_LookupColor: 1806 case X_AllocNamedColor: 1807 UnlockNextReplyReader(dpy); 1808 return(0); 1809 } 1810 break; 1811 case BadFont: 1812 if (err->majorCode == X_QueryFont) { 1813 UnlockNextReplyReader(dpy); 1814 return (0); 1815 } 1816 break; 1817 case BadAlloc: 1818 case BadAccess: 1819 UnlockNextReplyReader(dpy); 1820 return (0); 1821 } 1822 /* 1823 * we better see if there is an extension who may 1824 * want to suppress the error. 1825 */ 1826 for (ext = dpy->ext_procs; !ret && ext; ext = ext->next) { 1827 if (ext->error) 1828 ret = (*ext->error)(dpy, err, &ext->codes, &ret_code); 1829 } 1830 if (!ret) { 1831 _XError(dpy, err); 1832 ret_code = 0; 1833 } 1834 if (serial == cur_request) { 1835 UnlockNextReplyReader(dpy); 1836 return(ret_code); 1837 } 1838 1839 } /* case X_Error */ 1840 break; 1841 default: 1842 _XEnq(dpy, (xEvent *) rep); 1843#ifdef XTHREADS 1844 if (dpy->lock && dpy->lock->event_awaiters) 1845 ConditionSignal(dpy, dpy->lock->event_awaiters->cv); 1846#endif 1847 break; 1848 } 1849 } 1850} 1851 1852static char * 1853_XAsyncReply( 1854 Display *dpy, 1855 register xReply *rep, 1856 char *buf, 1857 register int *lenp, 1858 Bool discard) 1859{ 1860 register _XAsyncHandler *async, *next; 1861 register int len; 1862 register Bool consumed = False; 1863 char *nbuf; 1864 1865 (void) _XSetLastRequestRead(dpy, &rep->generic); 1866 len = SIZEOF(xReply) + (rep->generic.length << 2); 1867 if (len < SIZEOF(xReply)) { 1868 _XIOError (dpy); 1869 buf += *lenp; 1870 *lenp = 0; 1871 return buf; 1872 } 1873 1874 for (async = dpy->async_handlers; async; async = next) { 1875 next = async->next; 1876 if ((consumed = (*async->handler)(dpy, rep, buf, *lenp, async->data))) 1877 break; 1878 } 1879 if (!consumed) { 1880 if (!discard) 1881 return buf; 1882 (void) fprintf(stderr, 1883 "Xlib: unexpected async reply (sequence 0x%lx)!\n", 1884 dpy->last_request_read); 1885#ifdef XTHREADS 1886#ifdef XTHREADS_DEBUG 1887 printf("thread %x, unexpected async reply\n", XThread_Self()); 1888#endif 1889#endif 1890 if (len > *lenp) 1891 _XEatData(dpy, len - *lenp); 1892 } 1893 if (len < SIZEOF(xReply)) 1894 { 1895 _XIOError (dpy); 1896 buf += *lenp; 1897 *lenp = 0; 1898 return buf; 1899 } 1900 if (len >= *lenp) { 1901 buf += *lenp; 1902 *lenp = 0; 1903 return buf; 1904 } 1905 *lenp -= len; 1906 buf += len; 1907 len = *lenp; 1908 nbuf = buf; 1909 while (len > SIZEOF(xReply)) { 1910 if (*buf == X_Reply) 1911 return nbuf; 1912 buf += SIZEOF(xReply); 1913 len -= SIZEOF(xReply); 1914 } 1915 if (len > 0 && len < SIZEOF(xReply)) { 1916 buf = nbuf; 1917 len = SIZEOF(xReply) - len; 1918 nbuf -= len; 1919 memmove(nbuf, buf, *lenp); 1920 (void) _XRead(dpy, nbuf + *lenp, (long)len); 1921 *lenp += len; 1922 } 1923 return nbuf; 1924} 1925#endif /* !USE_XCB */ 1926 1927/* 1928 * Support for internal connections, such as an IM might use. 1929 * By Stephen Gildea, X Consortium, September 1993 1930 */ 1931 1932/* _XRegisterInternalConnection 1933 * Each IM (or Xlib extension) that opens a file descriptor that Xlib should 1934 * include in its select/poll mask must call this function to register the 1935 * fd with Xlib. Any XConnectionWatchProc registered by XAddConnectionWatch 1936 * will also be called. 1937 * 1938 * Whenever Xlib detects input available on fd, it will call callback 1939 * with call_data to process it. If non-Xlib code calls select/poll 1940 * and detects input available, it must call XProcessInternalConnection, 1941 * which will call the associated callback. 1942 * 1943 * Non-Xlib code can learn about these additional fds by calling 1944 * XInternalConnectionNumbers or, more typically, by registering 1945 * a XConnectionWatchProc with XAddConnectionWatch 1946 * to be called when fds are registered or unregistered. 1947 * 1948 * Returns True if registration succeeded, False if not, typically 1949 * because could not allocate memory. 1950 * Assumes Display locked when called. 1951 */ 1952Status 1953_XRegisterInternalConnection( 1954 Display* dpy, 1955 int fd, 1956 _XInternalConnectionProc callback, 1957 XPointer call_data 1958) 1959{ 1960 struct _XConnectionInfo *new_conni, **iptr; 1961 struct _XConnWatchInfo *watchers; 1962 XPointer *wd; 1963 1964 new_conni = (struct _XConnectionInfo*)Xmalloc(sizeof(struct _XConnectionInfo)); 1965 if (!new_conni) 1966 return 0; 1967 new_conni->watch_data = (XPointer *)Xmalloc(dpy->watcher_count * sizeof(XPointer)); 1968 if (!new_conni->watch_data) { 1969 Xfree(new_conni); 1970 return 0; 1971 } 1972 new_conni->fd = fd; 1973 new_conni->read_callback = callback; 1974 new_conni->call_data = call_data; 1975 new_conni->next = NULL; 1976 /* link new structure onto end of list */ 1977 for (iptr = &dpy->im_fd_info; *iptr; iptr = &(*iptr)->next) 1978 ; 1979 *iptr = new_conni; 1980 dpy->im_fd_length++; 1981 _XPollfdCacheAdd(dpy, fd); 1982 1983 for (watchers=dpy->conn_watchers, wd=new_conni->watch_data; 1984 watchers; 1985 watchers=watchers->next, wd++) { 1986 *wd = NULL; /* for cleanliness */ 1987 (*watchers->fn) (dpy, watchers->client_data, fd, True, wd); 1988 } 1989 1990 return 1; 1991} 1992 1993/* _XUnregisterInternalConnection 1994 * Each IM (or Xlib extension) that closes a file descriptor previously 1995 * registered with _XRegisterInternalConnection must call this function. 1996 * Any XConnectionWatchProc registered by XAddConnectionWatch 1997 * will also be called. 1998 * 1999 * Assumes Display locked when called. 2000 */ 2001void 2002_XUnregisterInternalConnection( 2003 Display* dpy, 2004 int fd 2005) 2006{ 2007 struct _XConnectionInfo *info_list, **prev; 2008 struct _XConnWatchInfo *watch; 2009 XPointer *wd; 2010 2011 for (prev = &dpy->im_fd_info; (info_list = *prev); 2012 prev = &info_list->next) { 2013 if (info_list->fd == fd) { 2014 *prev = info_list->next; 2015 dpy->im_fd_length--; 2016 for (watch=dpy->conn_watchers, wd=info_list->watch_data; 2017 watch; 2018 watch=watch->next, wd++) { 2019 (*watch->fn) (dpy, watch->client_data, fd, False, wd); 2020 } 2021 if (info_list->watch_data) 2022 Xfree (info_list->watch_data); 2023 Xfree (info_list); 2024 break; 2025 } 2026 } 2027 _XPollfdCacheDel(dpy, fd); 2028} 2029 2030/* XInternalConnectionNumbers 2031 * Returns an array of fds and an array of corresponding call data. 2032 * Typically a XConnectionWatchProc registered with XAddConnectionWatch 2033 * will be used instead of this function to discover 2034 * additional fds to include in the select/poll mask. 2035 * 2036 * The list is allocated with Xmalloc and should be freed by the caller 2037 * with Xfree; 2038 */ 2039Status 2040XInternalConnectionNumbers( 2041 Display *dpy, 2042 int **fd_return, 2043 int *count_return 2044) 2045{ 2046 int count; 2047 struct _XConnectionInfo *info_list; 2048 int *fd_list; 2049 2050 LockDisplay(dpy); 2051 count = 0; 2052 for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) 2053 count++; 2054 fd_list = (int*) Xmalloc (count * sizeof(int)); 2055 if (!fd_list) { 2056 UnlockDisplay(dpy); 2057 return 0; 2058 } 2059 count = 0; 2060 for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) { 2061 fd_list[count] = info_list->fd; 2062 count++; 2063 } 2064 UnlockDisplay(dpy); 2065 2066 *fd_return = fd_list; 2067 *count_return = count; 2068 return 1; 2069} 2070 2071void _XProcessInternalConnection( 2072 Display *dpy, 2073 struct _XConnectionInfo *conn_info) 2074{ 2075 dpy->flags |= XlibDisplayProcConni; 2076#if defined(XTHREADS) && !USE_XCB 2077 if (dpy->lock) { 2078 /* check cache to avoid call to thread_self */ 2079 if (xthread_have_id(dpy->lock->reading_thread)) 2080 dpy->lock->conni_thread = dpy->lock->reading_thread; 2081 else 2082 dpy->lock->conni_thread = XThread_Self(); 2083 } 2084#endif /* XTHREADS && !USE_XCB */ 2085 UnlockDisplay(dpy); 2086 (*conn_info->read_callback) (dpy, conn_info->fd, conn_info->call_data); 2087 LockDisplay(dpy); 2088#if defined(XTHREADS) && !USE_XCB 2089 if (dpy->lock) 2090 xthread_clear_id(dpy->lock->conni_thread); 2091#endif /* XTHREADS && !USE_XCB */ 2092 dpy->flags &= ~XlibDisplayProcConni; 2093} 2094 2095/* XProcessInternalConnection 2096 * Call the _XInternalConnectionProc registered by _XRegisterInternalConnection 2097 * for this fd. 2098 * The Display is NOT locked during the call. 2099 */ 2100void 2101XProcessInternalConnection( 2102 Display* dpy, 2103 int fd 2104) 2105{ 2106 struct _XConnectionInfo *info_list; 2107 2108 LockDisplay(dpy); 2109 for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) { 2110 if (info_list->fd == fd) { 2111 _XProcessInternalConnection(dpy, info_list); 2112 break; 2113 } 2114 } 2115 UnlockDisplay(dpy); 2116} 2117 2118/* XAddConnectionWatch 2119 * Register a callback to be called whenever _XRegisterInternalConnection 2120 * or _XUnregisterInternalConnection is called. 2121 * Callbacks are called with the Display locked. 2122 * If any connections are already registered, the callback is immediately 2123 * called for each of them. 2124 */ 2125Status 2126XAddConnectionWatch( 2127 Display* dpy, 2128 XConnectionWatchProc callback, 2129 XPointer client_data 2130) 2131{ 2132 struct _XConnWatchInfo *new_watcher, **wptr; 2133 struct _XConnectionInfo *info_list; 2134 XPointer *wd_array; 2135 2136 LockDisplay(dpy); 2137 2138 /* allocate new watch data */ 2139 for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) { 2140 wd_array = (XPointer *)Xrealloc((char *)info_list->watch_data, 2141 (dpy->watcher_count + 1) * 2142 sizeof(XPointer)); 2143 if (!wd_array) { 2144 UnlockDisplay(dpy); 2145 return 0; 2146 } 2147 wd_array[dpy->watcher_count] = NULL; /* for cleanliness */ 2148 } 2149 2150 new_watcher = (struct _XConnWatchInfo*)Xmalloc(sizeof(struct _XConnWatchInfo)); 2151 if (!new_watcher) { 2152 UnlockDisplay(dpy); 2153 return 0; 2154 } 2155 new_watcher->fn = callback; 2156 new_watcher->client_data = client_data; 2157 new_watcher->next = NULL; 2158 2159 /* link new structure onto end of list */ 2160 for (wptr = &dpy->conn_watchers; *wptr; wptr = &(*wptr)->next) 2161 ; 2162 *wptr = new_watcher; 2163 dpy->watcher_count++; 2164 2165 /* call new watcher on all currently registered fds */ 2166 for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) { 2167 (*callback) (dpy, client_data, info_list->fd, True, 2168 info_list->watch_data + dpy->watcher_count - 1); 2169 } 2170 2171 UnlockDisplay(dpy); 2172 return 1; 2173} 2174 2175/* XRemoveConnectionWatch 2176 * Unregister a callback registered by XAddConnectionWatch. 2177 * Both callback and client_data must match what was passed to 2178 * XAddConnectionWatch. 2179 */ 2180void 2181XRemoveConnectionWatch( 2182 Display* dpy, 2183 XConnectionWatchProc callback, 2184 XPointer client_data 2185) 2186{ 2187 struct _XConnWatchInfo *watch; 2188 struct _XConnWatchInfo *previous = NULL; 2189 struct _XConnectionInfo *conni; 2190 int counter = 0; 2191 2192 LockDisplay(dpy); 2193 for (watch=dpy->conn_watchers; watch; watch=watch->next) { 2194 if (watch->fn == callback && watch->client_data == client_data) { 2195 if (previous) 2196 previous->next = watch->next; 2197 else 2198 dpy->conn_watchers = watch->next; 2199 Xfree (watch); 2200 dpy->watcher_count--; 2201 /* remove our watch_data for each connection */ 2202 for (conni=dpy->im_fd_info; conni; conni=conni->next) { 2203 /* don't bother realloc'ing; these arrays are small anyway */ 2204 /* overlapping */ 2205 memmove(conni->watch_data+counter, 2206 conni->watch_data+counter+1, 2207 dpy->watcher_count - counter); 2208 } 2209 break; 2210 } 2211 previous = watch; 2212 counter++; 2213 } 2214 UnlockDisplay(dpy); 2215} 2216 2217/* end of internal connections support */ 2218 2219 2220#if !USE_XCB 2221/* Read and discard "n" 8-bit bytes of data */ 2222 2223void _XEatData( 2224 Display *dpy, 2225 register unsigned long n) 2226{ 2227#define SCRATCHSIZE 2048 2228 char buf[SCRATCHSIZE]; 2229 2230 while (n > 0) { 2231 register long bytes_read = (n > SCRATCHSIZE) ? SCRATCHSIZE : n; 2232 (void) _XRead (dpy, buf, bytes_read); 2233 n -= bytes_read; 2234 } 2235#undef SCRATCHSIZE 2236} 2237#endif /* !USE_XCB */ 2238 2239 2240/* 2241 * _XEnq - Place event packets on the display's queue. 2242 * note that no squishing of move events in V11, since there 2243 * is pointer motion hints.... 2244 */ 2245void _XEnq( 2246 register Display *dpy, 2247 register xEvent *event) 2248{ 2249 register _XQEvent *qelt; 2250 2251 if ((qelt = dpy->qfree)) { 2252 /* If dpy->qfree is non-NULL do this, else malloc a new one. */ 2253 dpy->qfree = qelt->next; 2254 } 2255 else if ((qelt = 2256 (_XQEvent *) Xmalloc((unsigned)sizeof(_XQEvent))) == NULL) { 2257 /* Malloc call failed! */ 2258 ESET(ENOMEM); 2259 _XIOError(dpy); 2260 } 2261 qelt->next = NULL; 2262 /* go call through display to find proper event reformatter */ 2263 if ((*dpy->event_vec[event->u.u.type & 0177])(dpy, &qelt->event, event)) { 2264 qelt->qserial_num = dpy->next_event_serial_num++; 2265 if (dpy->tail) dpy->tail->next = qelt; 2266 else dpy->head = qelt; 2267 2268 dpy->tail = qelt; 2269 dpy->qlen++; 2270 } else { 2271 /* ignored, or stashed away for many-to-one compression */ 2272 qelt->next = dpy->qfree; 2273 dpy->qfree = qelt; 2274 } 2275} 2276 2277/* 2278 * _XDeq - Remove event packet from the display's queue. 2279 */ 2280void _XDeq( 2281 register Display *dpy, 2282 register _XQEvent *prev, /* element before qelt */ 2283 register _XQEvent *qelt) /* element to be unlinked */ 2284{ 2285 if (prev) { 2286 if ((prev->next = qelt->next) == NULL) 2287 dpy->tail = prev; 2288 } else { 2289 /* no prev, so removing first elt */ 2290 if ((dpy->head = qelt->next) == NULL) 2291 dpy->tail = NULL; 2292 } 2293 qelt->qserial_num = 0; 2294 qelt->next = dpy->qfree; 2295 dpy->qfree = qelt; 2296 dpy->qlen--; 2297} 2298 2299/* 2300 * EventToWire in separate file in that often not needed. 2301 */ 2302 2303/*ARGSUSED*/ 2304Bool 2305_XUnknownWireEvent( 2306 register Display *dpy, /* pointer to display structure */ 2307 register XEvent *re, /* pointer to where event should be reformatted */ 2308 register xEvent *event) /* wire protocol event */ 2309{ 2310#ifdef notdef 2311 (void) fprintf(stderr, 2312 "Xlib: unhandled wire event! event number = %d, display = %x\n.", 2313 event->u.u.type, dpy); 2314#endif 2315 return(False); 2316} 2317 2318/*ARGSUSED*/ 2319Status 2320_XUnknownNativeEvent( 2321 register Display *dpy, /* pointer to display structure */ 2322 register XEvent *re, /* pointer to where event should be reformatted */ 2323 register xEvent *event) /* wire protocol event */ 2324{ 2325#ifdef notdef 2326 (void) fprintf(stderr, 2327 "Xlib: unhandled native event! event number = %d, display = %x\n.", 2328 re->type, dpy); 2329#endif 2330 return(0); 2331} 2332/* 2333 * reformat a wire event into an XEvent structure of the right type. 2334 */ 2335Bool 2336_XWireToEvent( 2337 register Display *dpy, /* pointer to display structure */ 2338 register XEvent *re, /* pointer to where event should be reformatted */ 2339 register xEvent *event) /* wire protocol event */ 2340{ 2341 2342 re->type = event->u.u.type & 0x7f; 2343 ((XAnyEvent *)re)->serial = _XSetLastRequestRead(dpy, 2344 (xGenericReply *)event); 2345 ((XAnyEvent *)re)->send_event = ((event->u.u.type & 0x80) != 0); 2346 ((XAnyEvent *)re)->display = dpy; 2347 2348 /* Ignore the leading bit of the event type since it is set when a 2349 client sends an event rather than the server. */ 2350 2351 switch (event-> u.u.type & 0177) { 2352 case KeyPress: 2353 case KeyRelease: 2354 { 2355 register XKeyEvent *ev = (XKeyEvent*) re; 2356 ev->root = event->u.keyButtonPointer.root; 2357 ev->window = event->u.keyButtonPointer.event; 2358 ev->subwindow = event->u.keyButtonPointer.child; 2359 ev->time = event->u.keyButtonPointer.time; 2360 ev->x = cvtINT16toInt(event->u.keyButtonPointer.eventX); 2361 ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY); 2362 ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX); 2363 ev->y_root = cvtINT16toInt(event->u.keyButtonPointer.rootY); 2364 ev->state = event->u.keyButtonPointer.state; 2365 ev->same_screen = event->u.keyButtonPointer.sameScreen; 2366 ev->keycode = event->u.u.detail; 2367 } 2368 break; 2369 case ButtonPress: 2370 case ButtonRelease: 2371 { 2372 register XButtonEvent *ev = (XButtonEvent *) re; 2373 ev->root = event->u.keyButtonPointer.root; 2374 ev->window = event->u.keyButtonPointer.event; 2375 ev->subwindow = event->u.keyButtonPointer.child; 2376 ev->time = event->u.keyButtonPointer.time; 2377 ev->x = cvtINT16toInt(event->u.keyButtonPointer.eventX); 2378 ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY); 2379 ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX); 2380 ev->y_root = cvtINT16toInt(event->u.keyButtonPointer.rootY); 2381 ev->state = event->u.keyButtonPointer.state; 2382 ev->same_screen = event->u.keyButtonPointer.sameScreen; 2383 ev->button = event->u.u.detail; 2384 } 2385 break; 2386 case MotionNotify: 2387 { 2388 register XMotionEvent *ev = (XMotionEvent *)re; 2389 ev->root = event->u.keyButtonPointer.root; 2390 ev->window = event->u.keyButtonPointer.event; 2391 ev->subwindow = event->u.keyButtonPointer.child; 2392 ev->time = event->u.keyButtonPointer.time; 2393 ev->x = cvtINT16toInt(event->u.keyButtonPointer.eventX); 2394 ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY); 2395 ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX); 2396 ev->y_root = cvtINT16toInt(event->u.keyButtonPointer.rootY); 2397 ev->state = event->u.keyButtonPointer.state; 2398 ev->same_screen = event->u.keyButtonPointer.sameScreen; 2399 ev->is_hint = event->u.u.detail; 2400 } 2401 break; 2402 case EnterNotify: 2403 case LeaveNotify: 2404 { 2405 register XCrossingEvent *ev = (XCrossingEvent *) re; 2406 ev->root = event->u.enterLeave.root; 2407 ev->window = event->u.enterLeave.event; 2408 ev->subwindow = event->u.enterLeave.child; 2409 ev->time = event->u.enterLeave.time; 2410 ev->x = cvtINT16toInt(event->u.enterLeave.eventX); 2411 ev->y = cvtINT16toInt(event->u.enterLeave.eventY); 2412 ev->x_root = cvtINT16toInt(event->u.enterLeave.rootX); 2413 ev->y_root = cvtINT16toInt(event->u.enterLeave.rootY); 2414 ev->state = event->u.enterLeave.state; 2415 ev->mode = event->u.enterLeave.mode; 2416 ev->same_screen = (event->u.enterLeave.flags & 2417 ELFlagSameScreen) && True; 2418 ev->focus = (event->u.enterLeave.flags & 2419 ELFlagFocus) && True; 2420 ev->detail = event->u.u.detail; 2421 } 2422 break; 2423 case FocusIn: 2424 case FocusOut: 2425 { 2426 register XFocusChangeEvent *ev = (XFocusChangeEvent *) re; 2427 ev->window = event->u.focus.window; 2428 ev->mode = event->u.focus.mode; 2429 ev->detail = event->u.u.detail; 2430 } 2431 break; 2432 case KeymapNotify: 2433 { 2434 register XKeymapEvent *ev = (XKeymapEvent *) re; 2435 ev->window = None; 2436 memcpy(&ev->key_vector[1], 2437 (char *)((xKeymapEvent *) event)->map, 2438 sizeof (((xKeymapEvent *) event)->map)); 2439 } 2440 break; 2441 case Expose: 2442 { 2443 register XExposeEvent *ev = (XExposeEvent *) re; 2444 ev->window = event->u.expose.window; 2445 ev->x = event->u.expose.x; 2446 ev->y = event->u.expose.y; 2447 ev->width = event->u.expose.width; 2448 ev->height = event->u.expose.height; 2449 ev->count = event->u.expose.count; 2450 } 2451 break; 2452 case GraphicsExpose: 2453 { 2454 register XGraphicsExposeEvent *ev = 2455 (XGraphicsExposeEvent *) re; 2456 ev->drawable = event->u.graphicsExposure.drawable; 2457 ev->x = event->u.graphicsExposure.x; 2458 ev->y = event->u.graphicsExposure.y; 2459 ev->width = event->u.graphicsExposure.width; 2460 ev->height = event->u.graphicsExposure.height; 2461 ev->count = event->u.graphicsExposure.count; 2462 ev->major_code = event->u.graphicsExposure.majorEvent; 2463 ev->minor_code = event->u.graphicsExposure.minorEvent; 2464 } 2465 break; 2466 case NoExpose: 2467 { 2468 register XNoExposeEvent *ev = (XNoExposeEvent *) re; 2469 ev->drawable = event->u.noExposure.drawable; 2470 ev->major_code = event->u.noExposure.majorEvent; 2471 ev->minor_code = event->u.noExposure.minorEvent; 2472 } 2473 break; 2474 case VisibilityNotify: 2475 { 2476 register XVisibilityEvent *ev = (XVisibilityEvent *) re; 2477 ev->window = event->u.visibility.window; 2478 ev->state = event->u.visibility.state; 2479 } 2480 break; 2481 case CreateNotify: 2482 { 2483 register XCreateWindowEvent *ev = 2484 (XCreateWindowEvent *) re; 2485 ev->window = event->u.createNotify.window; 2486 ev->parent = event->u.createNotify.parent; 2487 ev->x = cvtINT16toInt(event->u.createNotify.x); 2488 ev->y = cvtINT16toInt(event->u.createNotify.y); 2489 ev->width = event->u.createNotify.width; 2490 ev->height = event->u.createNotify.height; 2491 ev->border_width = event->u.createNotify.borderWidth; 2492 ev->override_redirect = event->u.createNotify.override; 2493 } 2494 break; 2495 case DestroyNotify: 2496 { 2497 register XDestroyWindowEvent *ev = 2498 (XDestroyWindowEvent *) re; 2499 ev->window = event->u.destroyNotify.window; 2500 ev->event = event->u.destroyNotify.event; 2501 } 2502 break; 2503 case UnmapNotify: 2504 { 2505 register XUnmapEvent *ev = (XUnmapEvent *) re; 2506 ev->window = event->u.unmapNotify.window; 2507 ev->event = event->u.unmapNotify.event; 2508 ev->from_configure = event->u.unmapNotify.fromConfigure; 2509 } 2510 break; 2511 case MapNotify: 2512 { 2513 register XMapEvent *ev = (XMapEvent *) re; 2514 ev->window = event->u.mapNotify.window; 2515 ev->event = event->u.mapNotify.event; 2516 ev->override_redirect = event->u.mapNotify.override; 2517 } 2518 break; 2519 case MapRequest: 2520 { 2521 register XMapRequestEvent *ev = (XMapRequestEvent *) re; 2522 ev->window = event->u.mapRequest.window; 2523 ev->parent = event->u.mapRequest.parent; 2524 } 2525 break; 2526 case ReparentNotify: 2527 { 2528 register XReparentEvent *ev = (XReparentEvent *) re; 2529 ev->event = event->u.reparent.event; 2530 ev->window = event->u.reparent.window; 2531 ev->parent = event->u.reparent.parent; 2532 ev->x = cvtINT16toInt(event->u.reparent.x); 2533 ev->y = cvtINT16toInt(event->u.reparent.y); 2534 ev->override_redirect = event->u.reparent.override; 2535 } 2536 break; 2537 case ConfigureNotify: 2538 { 2539 register XConfigureEvent *ev = (XConfigureEvent *) re; 2540 ev->event = event->u.configureNotify.event; 2541 ev->window = event->u.configureNotify.window; 2542 ev->above = event->u.configureNotify.aboveSibling; 2543 ev->x = cvtINT16toInt(event->u.configureNotify.x); 2544 ev->y = cvtINT16toInt(event->u.configureNotify.y); 2545 ev->width = event->u.configureNotify.width; 2546 ev->height = event->u.configureNotify.height; 2547 ev->border_width = event->u.configureNotify.borderWidth; 2548 ev->override_redirect = event->u.configureNotify.override; 2549 } 2550 break; 2551 case ConfigureRequest: 2552 { 2553 register XConfigureRequestEvent *ev = 2554 (XConfigureRequestEvent *) re; 2555 ev->window = event->u.configureRequest.window; 2556 ev->parent = event->u.configureRequest.parent; 2557 ev->above = event->u.configureRequest.sibling; 2558 ev->x = cvtINT16toInt(event->u.configureRequest.x); 2559 ev->y = cvtINT16toInt(event->u.configureRequest.y); 2560 ev->width = event->u.configureRequest.width; 2561 ev->height = event->u.configureRequest.height; 2562 ev->border_width = event->u.configureRequest.borderWidth; 2563 ev->value_mask = event->u.configureRequest.valueMask; 2564 ev->detail = event->u.u.detail; 2565 } 2566 break; 2567 case GravityNotify: 2568 { 2569 register XGravityEvent *ev = (XGravityEvent *) re; 2570 ev->window = event->u.gravity.window; 2571 ev->event = event->u.gravity.event; 2572 ev->x = cvtINT16toInt(event->u.gravity.x); 2573 ev->y = cvtINT16toInt(event->u.gravity.y); 2574 } 2575 break; 2576 case ResizeRequest: 2577 { 2578 register XResizeRequestEvent *ev = 2579 (XResizeRequestEvent *) re; 2580 ev->window = event->u.resizeRequest.window; 2581 ev->width = event->u.resizeRequest.width; 2582 ev->height = event->u.resizeRequest.height; 2583 } 2584 break; 2585 case CirculateNotify: 2586 { 2587 register XCirculateEvent *ev = (XCirculateEvent *) re; 2588 ev->window = event->u.circulate.window; 2589 ev->event = event->u.circulate.event; 2590 ev->place = event->u.circulate.place; 2591 } 2592 break; 2593 case CirculateRequest: 2594 { 2595 register XCirculateRequestEvent *ev = 2596 (XCirculateRequestEvent *) re; 2597 ev->window = event->u.circulate.window; 2598 ev->parent = event->u.circulate.event; 2599 ev->place = event->u.circulate.place; 2600 } 2601 break; 2602 case PropertyNotify: 2603 { 2604 register XPropertyEvent *ev = (XPropertyEvent *) re; 2605 ev->window = event->u.property.window; 2606 ev->atom = event->u.property.atom; 2607 ev->time = event->u.property.time; 2608 ev->state = event->u.property.state; 2609 } 2610 break; 2611 case SelectionClear: 2612 { 2613 register XSelectionClearEvent *ev = 2614 (XSelectionClearEvent *) re; 2615 ev->window = event->u.selectionClear.window; 2616 ev->selection = event->u.selectionClear.atom; 2617 ev->time = event->u.selectionClear.time; 2618 } 2619 break; 2620 case SelectionRequest: 2621 { 2622 register XSelectionRequestEvent *ev = 2623 (XSelectionRequestEvent *) re; 2624 ev->owner = event->u.selectionRequest.owner; 2625 ev->requestor = event->u.selectionRequest.requestor; 2626 ev->selection = event->u.selectionRequest.selection; 2627 ev->target = event->u.selectionRequest.target; 2628 ev->property = event->u.selectionRequest.property; 2629 ev->time = event->u.selectionRequest.time; 2630 } 2631 break; 2632 case SelectionNotify: 2633 { 2634 register XSelectionEvent *ev = (XSelectionEvent *) re; 2635 ev->requestor = event->u.selectionNotify.requestor; 2636 ev->selection = event->u.selectionNotify.selection; 2637 ev->target = event->u.selectionNotify.target; 2638 ev->property = event->u.selectionNotify.property; 2639 ev->time = event->u.selectionNotify.time; 2640 } 2641 break; 2642 case ColormapNotify: 2643 { 2644 register XColormapEvent *ev = (XColormapEvent *) re; 2645 ev->window = event->u.colormap.window; 2646 ev->colormap = event->u.colormap.colormap; 2647 ev->new = event->u.colormap.new; 2648 ev->state = event->u.colormap.state; 2649 } 2650 break; 2651 case ClientMessage: 2652 { 2653 register int i; 2654 register XClientMessageEvent *ev 2655 = (XClientMessageEvent *) re; 2656 ev->window = event->u.clientMessage.window; 2657 ev->format = event->u.u.detail; 2658 switch (ev->format) { 2659 case 8: 2660 ev->message_type = event->u.clientMessage.u.b.type; 2661 for (i = 0; i < 20; i++) 2662 ev->data.b[i] = event->u.clientMessage.u.b.bytes[i]; 2663 break; 2664 case 16: 2665 ev->message_type = event->u.clientMessage.u.s.type; 2666 ev->data.s[0] = cvtINT16toShort(event->u.clientMessage.u.s.shorts0); 2667 ev->data.s[1] = cvtINT16toShort(event->u.clientMessage.u.s.shorts1); 2668 ev->data.s[2] = cvtINT16toShort(event->u.clientMessage.u.s.shorts2); 2669 ev->data.s[3] = cvtINT16toShort(event->u.clientMessage.u.s.shorts3); 2670 ev->data.s[4] = cvtINT16toShort(event->u.clientMessage.u.s.shorts4); 2671 ev->data.s[5] = cvtINT16toShort(event->u.clientMessage.u.s.shorts5); 2672 ev->data.s[6] = cvtINT16toShort(event->u.clientMessage.u.s.shorts6); 2673 ev->data.s[7] = cvtINT16toShort(event->u.clientMessage.u.s.shorts7); 2674 ev->data.s[8] = cvtINT16toShort(event->u.clientMessage.u.s.shorts8); 2675 ev->data.s[9] = cvtINT16toShort(event->u.clientMessage.u.s.shorts9); 2676 break; 2677 case 32: 2678 ev->message_type = event->u.clientMessage.u.l.type; 2679 ev->data.l[0] = cvtINT32toLong(event->u.clientMessage.u.l.longs0); 2680 ev->data.l[1] = cvtINT32toLong(event->u.clientMessage.u.l.longs1); 2681 ev->data.l[2] = cvtINT32toLong(event->u.clientMessage.u.l.longs2); 2682 ev->data.l[3] = cvtINT32toLong(event->u.clientMessage.u.l.longs3); 2683 ev->data.l[4] = cvtINT32toLong(event->u.clientMessage.u.l.longs4); 2684 break; 2685 default: /* XXX should never occur */ 2686 break; 2687 } 2688 } 2689 break; 2690 case MappingNotify: 2691 { 2692 register XMappingEvent *ev = (XMappingEvent *)re; 2693 ev->window = 0; 2694 ev->first_keycode = event->u.mappingNotify.firstKeyCode; 2695 ev->request = event->u.mappingNotify.request; 2696 ev->count = event->u.mappingNotify.count; 2697 } 2698 break; 2699 default: 2700 return(_XUnknownWireEvent(dpy, re, event)); 2701 } 2702 return(True); 2703} 2704 2705 2706/* 2707 * _XDefaultIOError - Default fatal system error reporting routine. Called 2708 * when an X internal system error is encountered. 2709 */ 2710int _XDefaultIOError( 2711 Display *dpy) 2712{ 2713 if (ECHECK(EPIPE)) { 2714 (void) fprintf (stderr, 2715 "X connection to %s broken (explicit kill or server shutdown).\r\n", 2716 DisplayString (dpy)); 2717 } else { 2718 (void) fprintf (stderr, 2719 "XIO: fatal IO error %d (%s) on X server \"%s\"\r\n", 2720#ifdef WIN32 2721 WSAGetLastError(), strerror(WSAGetLastError()), 2722#else 2723 errno, strerror (errno), 2724#endif 2725 DisplayString (dpy)); 2726 (void) fprintf (stderr, 2727 " after %lu requests (%lu known processed) with %d events remaining.\r\n", 2728 NextRequest(dpy) - 1, LastKnownRequestProcessed(dpy), 2729 QLength(dpy)); 2730 2731 } 2732 exit(1); 2733 return(0); /* dummy - function should never return */ 2734} 2735 2736 2737static int _XPrintDefaultError( 2738 Display *dpy, 2739 XErrorEvent *event, 2740 FILE *fp) 2741{ 2742 char buffer[BUFSIZ]; 2743 char mesg[BUFSIZ]; 2744 char number[32]; 2745 const char *mtype = "XlibMessage"; 2746 register _XExtension *ext = (_XExtension *)NULL; 2747 _XExtension *bext = (_XExtension *)NULL; 2748 XGetErrorText(dpy, event->error_code, buffer, BUFSIZ); 2749 XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ); 2750 (void) fprintf(fp, "%s: %s\n ", mesg, buffer); 2751 XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", 2752 mesg, BUFSIZ); 2753 (void) fprintf(fp, mesg, event->request_code); 2754 if (event->request_code < 128) { 2755 sprintf(number, "%d", event->request_code); 2756 XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ); 2757 } else { 2758 for (ext = dpy->ext_procs; 2759 ext && (ext->codes.major_opcode != event->request_code); 2760 ext = ext->next) 2761 ; 2762 if (ext) 2763 strcpy(buffer, ext->name); 2764 else 2765 buffer[0] = '\0'; 2766 } 2767 (void) fprintf(fp, " (%s)\n", buffer); 2768 if (event->request_code >= 128) { 2769 XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d", 2770 mesg, BUFSIZ); 2771 fputs(" ", fp); 2772 (void) fprintf(fp, mesg, event->minor_code); 2773 if (ext) { 2774 sprintf(mesg, "%s.%d", ext->name, event->minor_code); 2775 XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ); 2776 (void) fprintf(fp, " (%s)", buffer); 2777 } 2778 fputs("\n", fp); 2779 } 2780 if (event->error_code >= 128) { 2781 /* kludge, try to find the extension that caused it */ 2782 buffer[0] = '\0'; 2783 for (ext = dpy->ext_procs; ext; ext = ext->next) { 2784 if (ext->error_string) 2785 (*ext->error_string)(dpy, event->error_code, &ext->codes, 2786 buffer, BUFSIZ); 2787 if (buffer[0]) { 2788 bext = ext; 2789 break; 2790 } 2791 if (ext->codes.first_error && 2792 ext->codes.first_error < (int)event->error_code && 2793 (!bext || ext->codes.first_error > bext->codes.first_error)) 2794 bext = ext; 2795 } 2796 if (bext) 2797 sprintf(buffer, "%s.%d", bext->name, 2798 event->error_code - bext->codes.first_error); 2799 else 2800 strcpy(buffer, "Value"); 2801 XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ); 2802 if (mesg[0]) { 2803 fputs(" ", fp); 2804 (void) fprintf(fp, mesg, event->resourceid); 2805 fputs("\n", fp); 2806 } 2807 /* let extensions try to print the values */ 2808 for (ext = dpy->ext_procs; ext; ext = ext->next) { 2809 if (ext->error_values) 2810 (*ext->error_values)(dpy, event, fp); 2811 } 2812 } else if ((event->error_code == BadWindow) || 2813 (event->error_code == BadPixmap) || 2814 (event->error_code == BadCursor) || 2815 (event->error_code == BadFont) || 2816 (event->error_code == BadDrawable) || 2817 (event->error_code == BadColor) || 2818 (event->error_code == BadGC) || 2819 (event->error_code == BadIDChoice) || 2820 (event->error_code == BadValue) || 2821 (event->error_code == BadAtom)) { 2822 if (event->error_code == BadValue) 2823 XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x", 2824 mesg, BUFSIZ); 2825 else if (event->error_code == BadAtom) 2826 XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x", 2827 mesg, BUFSIZ); 2828 else 2829 XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x", 2830 mesg, BUFSIZ); 2831 fputs(" ", fp); 2832 (void) fprintf(fp, mesg, event->resourceid); 2833 fputs("\n", fp); 2834 } 2835 XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", 2836 mesg, BUFSIZ); 2837 fputs(" ", fp); 2838 (void) fprintf(fp, mesg, event->serial); 2839 XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d", 2840 mesg, BUFSIZ); 2841 fputs("\n ", fp); 2842 (void) fprintf(fp, mesg, dpy->request); 2843 fputs("\n", fp); 2844 if (event->error_code == BadImplementation) return 0; 2845 return 1; 2846} 2847 2848int _XDefaultError( 2849 Display *dpy, 2850 XErrorEvent *event) 2851{ 2852 if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0; 2853 exit(1); 2854 /*NOTREACHED*/ 2855} 2856 2857/*ARGSUSED*/ 2858Bool _XDefaultWireError(display, he, we) 2859 Display *display; 2860 XErrorEvent *he; 2861 xError *we; 2862{ 2863 return True; 2864} 2865 2866/* 2867 * _XError - upcall internal or user protocol error handler 2868 */ 2869int _XError ( 2870 Display *dpy, 2871 register xError *rep) 2872{ 2873 /* 2874 * X_Error packet encountered! We need to unpack the error before 2875 * giving it to the user. 2876 */ 2877 XEvent event; /* make it a large event */ 2878 register _XAsyncHandler *async, *next; 2879 2880 event.xerror.serial = _XSetLastRequestRead(dpy, (xGenericReply *)rep); 2881 2882 for (async = dpy->async_handlers; async; async = next) { 2883 next = async->next; 2884 if ((*async->handler)(dpy, (xReply *)rep, 2885 (char *)rep, SIZEOF(xError), async->data)) 2886 return 0; 2887 } 2888 2889 event.xerror.display = dpy; 2890 event.xerror.type = X_Error; 2891 event.xerror.resourceid = rep->resourceID; 2892 event.xerror.error_code = rep->errorCode; 2893 event.xerror.request_code = rep->majorCode; 2894 event.xerror.minor_code = rep->minorCode; 2895 if (dpy->error_vec && 2896 !(*dpy->error_vec[rep->errorCode])(dpy, &event.xerror, rep)) 2897 return 0; 2898 if (_XErrorFunction != NULL) { 2899 int rtn_val; 2900#if defined(XTHREADS) && !USE_XCB 2901 if (dpy->lock) 2902 (*dpy->lock->user_lock_display)(dpy); 2903 UnlockDisplay(dpy); 2904#endif /* XTHREADS && !USE_XCB */ 2905 rtn_val = (*_XErrorFunction)(dpy, (XErrorEvent *)&event); /* upcall */ 2906#if defined(XTHREADS) && !USE_XCB 2907 LockDisplay(dpy); 2908 if (dpy->lock) 2909 (*dpy->lock->user_unlock_display)(dpy); 2910#endif /* XTHREADS && !USE_XCB */ 2911 return rtn_val; 2912 } else { 2913 return _XDefaultError(dpy, (XErrorEvent *)&event); 2914 } 2915} 2916 2917/* 2918 * _XIOError - call user connection error handler and exit 2919 */ 2920int 2921_XIOError ( 2922 Display *dpy) 2923{ 2924 dpy->flags |= XlibDisplayIOError; 2925#ifdef WIN32 2926 errno = WSAGetLastError(); 2927#endif 2928 2929 /* This assumes that the thread calling exit will call any atexit handlers. 2930 * If this does not hold, then an alternate solution would involve 2931 * registering an atexit handler to take over the lock, which would only 2932 * assume that the same thread calls all the atexit handlers. */ 2933#ifdef XTHREADS 2934 if (dpy->lock) 2935 (*dpy->lock->user_lock_display)(dpy); 2936#endif 2937 UnlockDisplay(dpy); 2938 2939 if (_XIOErrorFunction != NULL) 2940 (*_XIOErrorFunction)(dpy); 2941 else 2942 _XDefaultIOError(dpy); 2943 exit (1); 2944 return 0; 2945} 2946 2947 2948/* 2949 * This routine can be used to (cheaply) get some memory within a single 2950 * Xlib routine for scratch space. A single buffer is reused each time 2951 * if possible. To be MT safe, you can only call this between a call to 2952 * GetReq* and a call to Data* or _XSend*, or in a context when the thread 2953 * is guaranteed to not unlock the display. 2954 */ 2955char *_XAllocScratch( 2956 register Display *dpy, 2957 unsigned long nbytes) 2958{ 2959 if (nbytes > dpy->scratch_length) { 2960 if (dpy->scratch_buffer) Xfree (dpy->scratch_buffer); 2961 if ((dpy->scratch_buffer = Xmalloc((unsigned) nbytes))) 2962 dpy->scratch_length = nbytes; 2963 else dpy->scratch_length = 0; 2964 } 2965 return (dpy->scratch_buffer); 2966} 2967 2968/* 2969 * Scratch space allocator you can call any time, multiple times, and be 2970 * MT safe, but you must hand the buffer back with _XFreeTemp. 2971 */ 2972char *_XAllocTemp( 2973 register Display *dpy, 2974 unsigned long nbytes) 2975{ 2976 char *buf; 2977 2978 buf = _XAllocScratch(dpy, nbytes); 2979 dpy->scratch_buffer = NULL; 2980 dpy->scratch_length = 0; 2981 return buf; 2982} 2983 2984void _XFreeTemp( 2985 register Display *dpy, 2986 char *buf, 2987 unsigned long nbytes) 2988{ 2989 if (dpy->scratch_buffer) 2990 Xfree(dpy->scratch_buffer); 2991 dpy->scratch_buffer = buf; 2992 dpy->scratch_length = nbytes; 2993} 2994 2995/* 2996 * Given a visual id, find the visual structure for this id on this display. 2997 */ 2998Visual *_XVIDtoVisual( 2999 Display *dpy, 3000 VisualID id) 3001{ 3002 register int i, j, k; 3003 register Screen *sp; 3004 register Depth *dp; 3005 register Visual *vp; 3006 for (i = 0; i < dpy->nscreens; i++) { 3007 sp = &dpy->screens[i]; 3008 for (j = 0; j < sp->ndepths; j++) { 3009 dp = &sp->depths[j]; 3010 /* if nvisuals == 0 then visuals will be NULL */ 3011 for (k = 0; k < dp->nvisuals; k++) { 3012 vp = &dp->visuals[k]; 3013 if (vp->visualid == id) return (vp); 3014 } 3015 } 3016 } 3017 return (NULL); 3018} 3019 3020int 3021XFree (void *data) 3022{ 3023 Xfree (data); 3024 return 1; 3025} 3026 3027#ifdef _XNEEDBCOPYFUNC 3028void _Xbcopy(b1, b2, length) 3029 register char *b1, *b2; 3030 register length; 3031{ 3032 if (b1 < b2) { 3033 b2 += length; 3034 b1 += length; 3035 while (length--) 3036 *--b2 = *--b1; 3037 } else { 3038 while (length--) 3039 *b2++ = *b1++; 3040 } 3041} 3042#endif 3043 3044#ifdef DataRoutineIsProcedure 3045void Data( 3046 Display *dpy, 3047 char *data, 3048 long len) 3049{ 3050 if (dpy->bufptr + (len) <= dpy->bufmax) { 3051 memcpy(dpy->bufptr, data, (int)len); 3052 dpy->bufptr += ((len) + 3) & ~3; 3053 } else { 3054 _XSend(dpy, data, len); 3055 } 3056} 3057#endif /* DataRoutineIsProcedure */ 3058 3059 3060#ifdef LONG64 3061int 3062_XData32( 3063 Display *dpy, 3064 register long *data, 3065 unsigned len) 3066{ 3067 register int *buf; 3068 register long i; 3069 3070 while (len) { 3071 buf = (int *)dpy->bufptr; 3072 i = dpy->bufmax - (char *)buf; 3073 if (!i) { 3074 _XFlush(dpy); 3075 continue; 3076 } 3077 if (len < i) 3078 i = len; 3079 dpy->bufptr = (char *)buf + i; 3080 len -= i; 3081 i >>= 2; 3082 while (--i >= 0) 3083 *buf++ = *data++; 3084 } 3085 return 0; 3086} 3087#endif /* LONG64 */ 3088 3089#ifdef WORD64 3090 3091/* 3092 * XXX This is a *really* stupid way of doing this. It should just use 3093 * dpy->bufptr directly, taking into account where in the word it is. 3094 */ 3095 3096/* 3097 * Data16 - Place 16 bit data in the buffer. 3098 * 3099 * "dpy" is a pointer to a Display. 3100 * "data" is a pointer to the data. 3101 * "len" is the length in bytes of the data. 3102 */ 3103 3104static doData16( 3105 register Display *dpy, 3106 short *data, 3107 unsigned len, 3108 char *packbuffer) 3109{ 3110 long *lp,*lpack; 3111 long i, nwords,bits; 3112 long mask16 = 0x000000000000ffff; 3113 3114 lp = (long *)data; 3115 lpack = (long *)packbuffer; 3116 3117/* nwords is the number of 16 bit values to be packed, 3118 * the low order 16 bits of each word will be packed 3119 * into 64 bit words 3120 */ 3121 nwords = len >> 1; 3122 bits = 48; 3123 3124 for(i=0;i<nwords;i++){ 3125 if (bits == 48) *lpack = 0; 3126 *lpack ^= (*lp & mask16) << bits; 3127 bits -= 16 ; 3128 lp++; 3129 if(bits < 0){ 3130 lpack++; 3131 bits = 48; 3132 } 3133 } 3134 Data(dpy, packbuffer, len); 3135} 3136 3137_XData16 ( 3138 Display *dpy, 3139 short *data, 3140 unsigned len) 3141{ 3142 char packbuffer[PACKBUFFERSIZE]; 3143 unsigned nunits = PACKBUFFERSIZE >> 1; 3144 3145 for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) { 3146 doData16 (dpy, data, PACKBUFFERSIZE, packbuffer); 3147 } 3148 if (len) doData16 (dpy, data, len, packbuffer); 3149} 3150 3151/* 3152 * Data32 - Place 32 bit data in the buffer. 3153 * 3154 * "dpy" is a pointer to a Display. 3155 * "data" is a pointer to the data. 3156 * "len" is the length in bytes of the data. 3157 */ 3158 3159static doData32( 3160 register Display *dpy 3161 long *data, 3162 unsigned len, 3163 char *packbuffer) 3164{ 3165 long *lp,*lpack; 3166 long i,bits,nwords; 3167 long mask32 = 0x00000000ffffffff; 3168 3169 lpack = (long *) packbuffer; 3170 lp = data; 3171 3172/* nwords is the number of 32 bit values to be packed 3173 * the low order 32 bits of each word will be packed 3174 * into 64 bit words 3175 */ 3176 nwords = len >> 2; 3177 bits = 32; 3178 3179 for(i=0;i<nwords;i++){ 3180 if (bits == 32) *lpack = 0; 3181 *lpack ^= (*lp & mask32) << bits; 3182 bits = bits ^32; 3183 lp++; 3184 if(bits) 3185 lpack++; 3186 } 3187 Data(dpy, packbuffer, len); 3188} 3189 3190void _XData32( 3191 Display *dpy, 3192 long *data, 3193 unsigned len, 3194{ 3195 char packbuffer[PACKBUFFERSIZE]; 3196 unsigned nunits = PACKBUFFERSIZE >> 2; 3197 3198 for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) { 3199 doData32 (dpy, data, PACKBUFFERSIZE, packbuffer); 3200 } 3201 if (len) doData32 (dpy, data, len, packbuffer); 3202} 3203 3204#endif /* WORD64 */ 3205 3206 3207/* Make sure this produces the same string as DefineLocal/DefineSelf in xdm. 3208 * Otherwise, Xau will not be able to find your cookies in the Xauthority file. 3209 * 3210 * Note: POSIX says that the ``nodename'' member of utsname does _not_ have 3211 * to have sufficient information for interfacing to the network, 3212 * and so, you may be better off using gethostname (if it exists). 3213 */ 3214 3215#if (defined(_POSIX_SOURCE) && !defined(AIXV3) && !defined(__QNX__)) || defined(hpux) || defined(USG) || defined(SVR4) 3216#define NEED_UTSNAME 3217#include <sys/utsname.h> 3218#endif 3219 3220/* 3221 * _XGetHostname - similar to gethostname but allows special processing. 3222 */ 3223int _XGetHostname ( 3224 char *buf, 3225 int maxlen) 3226{ 3227 int len; 3228 3229#ifdef NEED_UTSNAME 3230 struct utsname name; 3231 3232 if (maxlen <= 0 || buf == NULL) 3233 return 0; 3234 3235 uname (&name); 3236 len = strlen (name.nodename); 3237 if (len >= maxlen) len = maxlen - 1; 3238 strncpy (buf, name.nodename, len); 3239 buf[len] = '\0'; 3240#else 3241 if (maxlen <= 0 || buf == NULL) 3242 return 0; 3243 3244 buf[0] = '\0'; 3245 (void) gethostname (buf, maxlen); 3246 buf [maxlen - 1] = '\0'; 3247 len = strlen(buf); 3248#endif /* NEED_UTSNAME */ 3249 return len; 3250} 3251 3252 3253/* 3254 * _XScreenOfWindow - get the Screen of a given window 3255 */ 3256 3257Screen *_XScreenOfWindow (dpy, w) 3258 Display *dpy; 3259 Window w; 3260{ 3261 register int i; 3262 Window root; 3263 int x, y; /* dummy variables */ 3264 unsigned int width, height, bw, depth; /* dummy variables */ 3265 3266 if (XGetGeometry (dpy, w, &root, &x, &y, &width, &height, 3267 &bw, &depth) == False) { 3268 return None; 3269 } 3270 for (i = 0; i < ScreenCount (dpy); i++) { /* find root from list */ 3271 if (root == RootWindow (dpy, i)) { 3272 return ScreenOfDisplay (dpy, i); 3273 } 3274 } 3275 return NULL; 3276} 3277 3278 3279#if defined(WIN32) 3280 3281/* 3282 * These functions are intended to be used internally to Xlib only. 3283 * These functions will always prefix the path with a DOS drive in the 3284 * form "<drive-letter>:". As such, these functions are only suitable 3285 * for use by Xlib function that supply a root-based path to some 3286 * particular file, e.g. <ProjectRoot>/lib/X11/locale/locale.dir will 3287 * be converted to "C:/usr/X11R6.3/lib/X11/locale/locale.dir". 3288 */ 3289 3290static int access_file (path, pathbuf, len_pathbuf, pathret) 3291 char* path; 3292 char* pathbuf; 3293 int len_pathbuf; 3294 char** pathret; 3295{ 3296 if (access (path, F_OK) == 0) { 3297 if (strlen (path) < len_pathbuf) 3298 *pathret = pathbuf; 3299 else 3300 *pathret = Xmalloc (strlen (path) + 1); 3301 if (*pathret) { 3302 strcpy (*pathret, path); 3303 return 1; 3304 } 3305 } 3306 return 0; 3307} 3308 3309static int AccessFile (path, pathbuf, len_pathbuf, pathret) 3310 char* path; 3311 char* pathbuf; 3312 int len_pathbuf; 3313 char** pathret; 3314{ 3315 unsigned long drives; 3316 int i, len; 3317 char* drive; 3318 char buf[MAX_PATH]; 3319 char* bufp; 3320 3321 /* just try the "raw" name first and see if it works */ 3322 if (access_file (path, pathbuf, len_pathbuf, pathret)) 3323 return 1; 3324 3325 /* try the places set in the environment */ 3326 drive = getenv ("_XBASEDRIVE"); 3327#ifdef __UNIXOS2__ 3328 if (!drive) 3329 drive = getenv ("X11ROOT"); 3330#endif 3331 if (!drive) 3332 drive = "C:"; 3333 len = strlen (drive) + strlen (path); 3334 if (len < MAX_PATH) bufp = buf; 3335 else bufp = Xmalloc (len + 1); 3336 strcpy (bufp, drive); 3337 strcat (bufp, path); 3338 if (access_file (bufp, pathbuf, len_pathbuf, pathret)) { 3339 if (bufp != buf) Xfree (bufp); 3340 return 1; 3341 } 3342 3343#ifndef __UNIXOS2__ 3344 /* one last place to look */ 3345 drive = getenv ("HOMEDRIVE"); 3346 if (drive) { 3347 len = strlen (drive) + strlen (path); 3348 if (len < MAX_PATH) bufp = buf; 3349 else bufp = Xmalloc (len + 1); 3350 strcpy (bufp, drive); 3351 strcat (bufp, path); 3352 if (access_file (bufp, pathbuf, len_pathbuf, pathret)) { 3353 if (bufp != buf) Xfree (bufp); 3354 return 1; 3355 } 3356 } 3357 3358 /* tried everywhere else, go fishing */ 3359#define C_DRIVE ('C' - 'A') 3360#define Z_DRIVE ('Z' - 'A') 3361 /* does OS/2 (with or with gcc-emx) have getdrives? */ 3362 drives = _getdrives (); 3363 for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */ 3364 if ((1 << i) & drives) { 3365 len = 2 + strlen (path); 3366 if (len < MAX_PATH) bufp = buf; 3367 else bufp = Xmalloc (len + 1); 3368 *bufp = 'A' + i; 3369 *(bufp + 1) = ':'; 3370 *(bufp + 2) = '\0'; 3371 strcat (bufp, path); 3372 if (access_file (bufp, pathbuf, len_pathbuf, pathret)) { 3373 if (bufp != buf) Xfree (bufp); 3374 return 1; 3375 } 3376 } 3377 } 3378#endif 3379 return 0; 3380} 3381 3382int _XOpenFile(path, flags) 3383 _Xconst char* path; 3384 int flags; 3385{ 3386 char buf[MAX_PATH]; 3387 char* bufp = NULL; 3388 int ret = -1; 3389 UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS); 3390 3391 if (AccessFile (path, buf, MAX_PATH, &bufp)) 3392 ret = open (bufp, flags); 3393 3394 (void) SetErrorMode (olderror); 3395 3396 if (bufp != buf) Xfree (bufp); 3397 3398 return ret; 3399} 3400 3401int _XOpenFileMode(path, flags, mode) 3402 _Xconst char* path; 3403 int flags; 3404 mode_t mode; 3405{ 3406 char buf[MAX_PATH]; 3407 char* bufp = NULL; 3408 int ret = -1; 3409 UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS); 3410 3411 if (AccessFile (path, buf, MAX_PATH, &bufp)) 3412 ret = open (bufp, flags, mode); 3413 3414 (void) SetErrorMode (olderror); 3415 3416 if (bufp != buf) Xfree (bufp); 3417 3418 return ret; 3419} 3420 3421void* _XFopenFile(path, mode) 3422 _Xconst char* path; 3423 _Xconst char* mode; 3424{ 3425 char buf[MAX_PATH]; 3426 char* bufp = NULL; 3427 void* ret = NULL; 3428 UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS); 3429 3430 if (AccessFile (path, buf, MAX_PATH, &bufp)) 3431 ret = fopen (bufp, mode); 3432 3433 (void) SetErrorMode (olderror); 3434 3435 if (bufp != buf) Xfree (bufp); 3436 3437 return ret; 3438} 3439 3440int _XAccessFile(path) 3441 _Xconst char* path; 3442{ 3443 char buf[MAX_PATH]; 3444 char* bufp; 3445 int ret = -1; 3446 UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS); 3447 3448 ret = AccessFile (path, buf, MAX_PATH, &bufp); 3449 3450 (void) SetErrorMode (olderror); 3451 3452 if (bufp != buf) Xfree (bufp); 3453 3454 return ret; 3455} 3456 3457#endif 3458 3459#ifdef WIN32 3460#undef _Xdebug 3461int _Xdebug = 0; 3462int *_Xdebug_p = &_Xdebug; 3463void (**_XCreateMutex_fn_p)(LockInfoPtr) = &_XCreateMutex_fn; 3464void (**_XFreeMutex_fn_p)(LockInfoPtr) = &_XFreeMutex_fn; 3465void (**_XLockMutex_fn_p)(LockInfoPtr 3466#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE) 3467 , char * /* file */ 3468 , int /* line */ 3469#endif 3470 ) = &_XLockMutex_fn; 3471void (**_XUnlockMutex_fn_p)(LockInfoPtr 3472#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE) 3473 , char * /* file */ 3474 , int /* line */ 3475#endif 3476 ) = &_XUnlockMutex_fn; 3477LockInfoPtr *_Xglobal_lock_p = &_Xglobal_lock; 3478#endif 3479