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