NextEvent.c revision 697b1baf
1/* $Xorg: NextEvent.c,v 1.8 2001/02/09 02:03:55 xorgcvs Exp $ */ 2 3/*********************************************************** 4Copyright 1993 Sun Microsystems, Inc. All rights reserved. 5 6Permission is hereby granted, free of charge, to any person obtaining a 7copy of this software and associated documentation files (the "Software"), 8to deal in the Software without restriction, including without limitation 9the rights to use, copy, modify, merge, publish, distribute, sublicense, 10and/or sell copies of the Software, and to permit persons to whom the 11Software is furnished to do so, subject to the following conditions: 12 13The above copyright notice and this permission notice (including the next 14paragraph) shall be included in all copies or substantial portions of the 15Software. 16 17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23DEALINGS IN THE SOFTWARE. 24 25Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 26 27 All Rights Reserved 28 29Permission to use, copy, modify, and distribute this software and its 30documentation for any purpose and without fee is hereby granted, 31provided that the above copyright notice appear in all copies and that 32both that copyright notice and this permission notice appear in 33supporting documentation, and that the name of Digital not be 34used in advertising or publicity pertaining to distribution of the 35software without specific, written prior permission. 36 37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 43SOFTWARE. 44 45******************************************************************/ 46 47/* 48 49Copyright 1987, 1988, 1994, 1998, 2001 The Open Group 50 51Permission to use, copy, modify, distribute, and sell this software and its 52documentation for any purpose is hereby granted without fee, provided that 53the above copyright notice appear in all copies and that both that 54copyright notice and this permission notice appear in supporting 55documentation. 56 57The above copyright notice and this permission notice shall be included in 58all copies or substantial portions of the Software. 59 60THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 61IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 62FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 63OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 64AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 65CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 66 67Except as contained in this notice, the name of The Open Group shall not be 68used in advertising or otherwise to promote the sale, use or other dealings 69in this Software without prior written authorization from The Open Group. 70 71*/ 72/* $XFree86: xc/lib/Xt/NextEvent.c,v 3.26 2002/06/04 21:55:42 dawes Exp $ */ 73 74#ifdef HAVE_CONFIG_H 75#include <config.h> 76#endif 77#include "IntrinsicI.h" 78#include <stdio.h> 79#include <errno.h> 80 81#ifdef __UNIXOS2__ 82#include <sys/time.h> 83#endif 84 85static TimerEventRec* freeTimerRecs; 86static WorkProcRec* freeWorkRecs; 87static SignalEventRec* freeSignalRecs; 88 89/* Some systems running NTP daemons are known to return strange usec 90 * values from gettimeofday. 91 */ 92 93#ifndef NEEDS_NTPD_FIXUP 94# if defined(sun) || defined(MOTOROLA) || (defined(__osf__) && defined(__alpha)) 95# define NEEDS_NTPD_FIXUP 1 96# else 97# define NEEDS_NTPD_FIXUP 0 98# endif 99#endif 100 101#if NEEDS_NTPD_FIXUP 102#define FIXUP_TIMEVAL(t) { \ 103 while ((t).tv_usec >= 1000000) { \ 104 (t).tv_usec -= 1000000; \ 105 (t).tv_sec++; \ 106 } \ 107 while ((t).tv_usec < 0) { \ 108 if ((t).tv_sec > 0) { \ 109 (t).tv_usec += 1000000; \ 110 (t).tv_sec--; \ 111 } else { \ 112 (t).tv_usec = 0; \ 113 break; \ 114 } \ 115 }} 116#else 117#define FIXUP_TIMEVAL(t) 118#endif /*NEEDS_NTPD_FIXUP*/ 119 120/* 121 * Private routines 122 */ 123#define ADD_TIME(dest, src1, src2) { \ 124 if(((dest).tv_usec = (src1).tv_usec + (src2).tv_usec) >= 1000000) {\ 125 (dest).tv_usec -= 1000000;\ 126 (dest).tv_sec = (src1).tv_sec + (src2).tv_sec + 1 ; \ 127 } else { (dest).tv_sec = (src1).tv_sec + (src2).tv_sec ; \ 128 if(((dest).tv_sec >= 1) && (((dest).tv_usec <0))) { \ 129 (dest).tv_sec --;(dest).tv_usec += 1000000; } } } 130 131 132#define TIMEDELTA(dest, src1, src2) { \ 133 if(((dest).tv_usec = (src1).tv_usec - (src2).tv_usec) < 0) {\ 134 (dest).tv_usec += 1000000;\ 135 (dest).tv_sec = (src1).tv_sec - (src2).tv_sec - 1;\ 136 } else (dest).tv_sec = (src1).tv_sec - (src2).tv_sec; } 137 138#define IS_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \ 139 || (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec > (t1).tv_usec))) 140 141#define IS_AT_OR_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \ 142 || (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec >= (t1).tv_usec))) 143 144#ifdef USE_POLL 145#ifndef XT_DEFAULT_FDLIST_SIZE 146#define XT_DEFAULT_FDLIST_SIZE 32 147#endif 148#endif 149 150static void AdjustHowLong ( 151 unsigned long *howlong, 152 struct timeval *start_time) 153{ 154 struct timeval new_time, time_spent, lstart_time; 155 156 lstart_time = *start_time; 157 X_GETTIMEOFDAY (&new_time); 158 FIXUP_TIMEVAL(new_time); 159 TIMEDELTA(time_spent, new_time, lstart_time); 160 if(*howlong <= (unsigned long)(time_spent.tv_sec*1000+time_spent.tv_usec/1000)) 161 *howlong = (unsigned long)0; /* Timed out */ 162 else 163 *howlong -= (time_spent.tv_sec*1000+time_spent.tv_usec/1000); 164} 165 166typedef struct { 167 struct timeval cur_time; 168 struct timeval start_time; 169 struct timeval wait_time; 170 struct timeval new_time; 171 struct timeval time_spent; 172 struct timeval max_wait_time; 173#ifndef USE_POLL 174 struct timeval *wait_time_ptr; 175#else 176 int poll_wait; 177#endif 178} wait_times_t, *wait_times_ptr_t; 179 180static struct timeval zero_time = { 0 , 0}; 181#ifndef USE_POLL 182static fd_set zero_fd; 183#else 184#define X_BLOCK -1 185#define X_DONT_BLOCK 0 186#endif 187 188static void InitTimes ( 189 Boolean block, 190 unsigned long* howlong, 191 wait_times_ptr_t wt) 192{ 193 if (block) { 194 X_GETTIMEOFDAY (&wt->cur_time); 195 FIXUP_TIMEVAL(wt->cur_time); 196 wt->start_time = wt->cur_time; 197 if(howlong == NULL) { /* special case for ever */ 198#ifndef USE_POLL 199 wt->wait_time_ptr = NULL; 200#else 201 wt->poll_wait = X_BLOCK; 202#endif 203 } else { /* block until at most */ 204 wt->max_wait_time.tv_sec = *howlong/1000; 205 wt->max_wait_time.tv_usec = (*howlong %1000)*1000; 206#ifndef USE_POLL 207 wt->wait_time_ptr = &wt->max_wait_time; 208#else 209 wt->poll_wait = *howlong; 210#endif 211 } 212 } else { /* don't block */ 213 wt->max_wait_time = zero_time; 214#ifndef USE_POLL 215 wt->wait_time_ptr = &wt->max_wait_time; 216#else 217 wt->poll_wait = X_DONT_BLOCK; 218#endif 219 } 220} 221 222typedef struct { 223#ifndef USE_POLL 224 fd_set rmask, wmask, emask; 225 int nfds; 226#else 227 struct pollfd* fdlist; 228 struct pollfd* stack; 229 int fdlistlen, num_dpys; 230#endif 231} wait_fds_t, *wait_fds_ptr_t; 232 233static void InitFds ( 234 XtAppContext app, 235 Boolean ignoreEvents, 236 Boolean ignoreInputs, 237 wait_fds_ptr_t wf) 238{ 239 int ii; 240 app->rebuild_fdlist = FALSE; 241#ifndef USE_POLL 242 wf->nfds = app->fds.nfds; 243 if( !ignoreInputs ) { 244 wf->rmask = app->fds.rmask; 245 wf->wmask = app->fds.wmask; 246 wf->emask = app->fds.emask; 247 } else 248 wf->rmask = wf->wmask = wf->emask = zero_fd; 249 250 if (!ignoreEvents) 251 for (ii = 0; ii < app->count; ii++) { 252 FD_SET (ConnectionNumber(app->list[ii]), &wf->rmask); 253 } 254#else 255#ifndef POLLRDNORM 256#define POLLRDNORM 0 257#endif 258 259#ifndef POLLRDBAND 260#define POLLRDBAND 0 261#endif 262 263#ifndef POLLWRNORM 264#define POLLWRNORM 0 265#endif 266 267#ifndef POLLWRBAND 268#define POLLWRBAND 0 269#endif 270 271#define XPOLL_READ (POLLIN|POLLRDNORM|POLLPRI|POLLRDBAND) 272#define XPOLL_WRITE (POLLOUT|POLLWRNORM|POLLWRBAND) 273#define XPOLL_EXCEPT 0 274 275 if (!ignoreEvents) 276 wf->fdlistlen = wf->num_dpys = app->count; 277 else 278 wf->fdlistlen = wf->num_dpys = 0; 279 280 if (!ignoreInputs && app->input_list != NULL) { 281 int ii; 282 for (ii = 0; ii < (int) app->input_max; ii++) 283 if (app->input_list[ii] != NULL) 284 wf->fdlistlen++; 285 } 286 287 if (!wf->fdlist || wf->fdlist == wf->stack) { 288 wf->fdlist = (struct pollfd*) 289 XtStackAlloc (sizeof (struct pollfd) * wf->fdlistlen, wf->stack); 290 } else { 291 wf->fdlist = (struct pollfd*) 292 XtRealloc ((char*) wf->fdlist, 293 sizeof (struct pollfd) * wf->fdlistlen); 294 } 295 296 if (wf->fdlistlen) { 297 struct pollfd* fdlp = wf->fdlist; 298 InputEvent* iep; 299 300 if (!ignoreEvents) 301 for (ii = 0 ; ii < wf->num_dpys; ii++, fdlp++) { 302 fdlp->fd = ConnectionNumber (app->list[ii]); 303 fdlp->events = POLLIN; 304 } 305 if (!ignoreInputs && app->input_list != NULL) 306 for (ii = 0; ii < app->input_max; ii++) 307 if (app->input_list[ii] != NULL) { 308 iep = app->input_list[ii]; 309 fdlp->fd = ii; 310 fdlp->events = 0; 311 for ( ; iep; iep = iep->ie_next) { 312 if (iep->ie_condition & XtInputReadMask) 313 fdlp->events |= XPOLL_READ; 314 if (iep->ie_condition & XtInputWriteMask) 315 fdlp->events |= XPOLL_WRITE; 316 if (iep->ie_condition & XtInputExceptMask) 317 fdlp->events |= XPOLL_EXCEPT; 318 } 319 fdlp++; 320 } 321 } 322#endif 323} 324 325static void AdjustTimes ( 326 XtAppContext app, 327 Boolean block, 328 unsigned long* howlong, 329 Boolean ignoreTimers, 330 wait_times_ptr_t wt) 331{ 332 if (app->timerQueue != NULL && !ignoreTimers && block) { 333 if (IS_AFTER (wt->cur_time, app->timerQueue->te_timer_value)) { 334 TIMEDELTA (wt->wait_time, app->timerQueue->te_timer_value, wt->cur_time); 335 if (howlong == NULL || IS_AFTER (wt->wait_time, wt->max_wait_time)) 336#ifndef USE_POLL 337 wt->wait_time_ptr = &wt->wait_time; 338 else 339 wt->wait_time_ptr = &wt->max_wait_time; 340 } else 341 wt->wait_time_ptr = &zero_time; 342 } 343#else 344 wt->poll_wait = wt->wait_time.tv_sec * 1000 + wt->wait_time.tv_usec / 1000; 345 else 346 wt->poll_wait = wt->max_wait_time.tv_sec * 1000 + wt->max_wait_time.tv_usec / 1000; 347 } else 348 wt->poll_wait = X_DONT_BLOCK; 349 } 350#endif 351} 352 353 354static int IoWait ( 355 wait_times_ptr_t wt, 356 wait_fds_ptr_t wf) 357{ 358#ifndef USE_POLL 359 return Select (wf->nfds, &wf->rmask, &wf->wmask, &wf->emask, 360 wt->wait_time_ptr); 361#else 362 return poll (wf->fdlist, wf->fdlistlen, wt->poll_wait); 363#endif 364} 365 366 367static void FindInputs ( 368 XtAppContext app, 369 wait_fds_ptr_t wf, 370 int nfds, 371 Boolean ignoreEvents, 372 Boolean ignoreInputs, 373 int* dpy_no, 374 int* found_input) 375{ 376 XtInputMask condition; 377 InputEvent *ep; 378 int ii; 379#ifndef USE_POLL /* { check ready file descriptors block */ 380#ifdef XTHREADS 381 fd_set rmask; 382#endif 383 int dd; 384 *dpy_no = -1; 385 *found_input = False; 386 387#ifdef XTHREADS 388 rmask = app->fds.rmask; 389 for (dd = app->count; dd-- > 0; ) 390 FD_SET (ConnectionNumber (app->list[dd]), &rmask); 391#endif 392 393 for (ii = 0; ii < wf->nfds && nfds > 0; ii++) { 394 condition = 0; 395 if (FD_ISSET (ii, &wf->rmask) 396#ifdef XTHREADS 397 && FD_ISSET (ii, &rmask) 398#endif 399 ) { 400 nfds--; 401 if (!ignoreEvents) { 402 for (dd = 0; dd < app->count; dd++) { 403 if (ii == ConnectionNumber (app->list[dd])) { 404 if (*dpy_no == -1) { 405 if (XEventsQueued (app->list[dd], QueuedAfterReading )) 406 *dpy_no = dd; 407 /* 408 * An error event could have arrived 409 * without any real events, or events 410 * could have been swallowed by Xlib, 411 * or the connection may be broken. 412 * We can't tell the difference, so 413 * assume Xlib will eventually discover 414 * a broken connection. 415 */ 416 } 417 goto ENDILOOP; 418 } 419 } 420 } 421 condition = XtInputReadMask; 422 } 423 if (FD_ISSET (ii, &wf->wmask) 424#ifdef XTHREADS 425 && FD_ISSET (ii, &app->fds.wmask) 426#endif 427 ) { 428 condition |= XtInputWriteMask; 429 nfds--; 430 } 431 if (FD_ISSET (ii, &wf->emask) 432#ifdef XTHREADS 433 && FD_ISSET (ii, &app->fds.emask) 434#endif 435 ) { 436 condition |= XtInputExceptMask; 437 nfds--; 438 } 439 if (condition) { 440 for (ep = app->input_list[ii]; ep; ep = ep->ie_next) 441 if (condition & ep->ie_condition) { 442 /* make sure this input isn't already marked outstanding */ 443 InputEvent *oq; 444 for (oq = app->outstandingQueue; oq; oq = oq->ie_oq) 445 if (oq == ep) 446 break; 447 if (!oq) 448 { 449 ep->ie_oq = app->outstandingQueue; 450 app->outstandingQueue = ep; 451 } 452 } 453 *found_input = True; 454 } 455ENDILOOP: ; 456 } /* endfor */ 457#else /* }{ */ 458 struct pollfd* fdlp; 459 460 *dpy_no = -1; 461 *found_input = False; 462 463 if (!ignoreEvents) { 464 fdlp = wf->fdlist; 465 for (ii = 0; ii < wf->num_dpys; ii++, fdlp++) { 466 if (*dpy_no == -1 && fdlp->revents & (POLLIN|POLLHUP|POLLERR) && 467#ifdef XTHREADS 468 !(fdlp->revents & POLLNVAL) && 469#endif 470 XEventsQueued (app->list[ii], QueuedAfterReading)) { 471 *dpy_no = ii; 472 break; 473 } 474 } 475 } 476 477 if (!ignoreInputs) { 478 fdlp = &wf->fdlist[wf->num_dpys]; 479 for (ii = wf->num_dpys; ii < wf->fdlistlen; ii++, fdlp++) { 480 condition = 0; 481 if (fdlp->revents) { 482 if (fdlp->revents & (XPOLL_READ|POLLHUP|POLLERR) 483#ifdef XTHREADS 484 && !(fdlp->revents & POLLNVAL) 485#endif 486 ) 487 condition = XtInputReadMask; 488 if (fdlp->revents & XPOLL_WRITE) 489 condition |= XtInputWriteMask; 490 if (fdlp->revents & XPOLL_EXCEPT) 491 condition |= XtInputExceptMask; 492 } 493 if (condition) { 494 *found_input = True; 495 for (ep = app->input_list[fdlp->fd]; ep; ep = ep->ie_next) 496 if (condition & ep->ie_condition) { 497 InputEvent *oq; 498 /* make sure this input isn't already marked outstanding */ 499 for (oq = app->outstandingQueue; oq; oq = oq->ie_oq) 500 if (oq == ep) 501 break; 502 if (!oq) 503 { 504 ep->ie_oq = app->outstandingQueue; 505 app->outstandingQueue = ep; 506 } 507 } 508 } 509 } 510 } 511#endif /* } */ 512} 513 514/* 515 * Routine to block in the toolkit. This should be the only call to select. 516 * 517 * This routine returns when there is something to be done. 518 * 519 * Before calling this with ignoreInputs==False, app->outstandingQueue should 520 * be checked; this routine will not verify that an alternate input source 521 * has not already been enqueued. 522 * 523 * 524 * _XtWaitForSomething( appContext, 525 * ignoreEvent, ignoreTimers, ignoreInputs, ignoreSignals, 526 * block, drop_lock, howlong) 527 * XtAppContext app; (Displays to check wait on) 528 * 529 * Boolean ignoreEvents; (Don't return if XEvents are available 530 * Also implies forget XEvents exist) 531 * 532 * Boolean ignoreTimers; (Ditto for timers) 533 * 534 * Boolean ignoreInputs; (Ditto for input callbacks ) 535 * 536 * Boolean ignoreSignals; (Ditto for signals) 537 * 538 * Boolean block; (Okay to block) 539 * 540 * Boolean drop_lock (drop lock before going into select/poll) 541 * 542 * TimeVal howlong; (howlong to wait for if blocking and not 543 * doing Timers... Null means forever. 544 * Maybe should mean shortest of both) 545 * Returns display for which input is available, if any 546 * and if ignoreEvents==False, else returns -1 547 * 548 * if ignoring everything && block=True && howlong=NULL, you'll have 549 * lots of time for coffee; better not try it! In fact, it probably 550 * makes little sense to do this regardless of the value of howlong 551 * (bottom line is, we don't bother checking here). 552 * 553 * If drop_lock is FALSE, the app->lock->mutex is not unlocked before 554 * entering select/poll. It is illegal for drop_lock to be FALSE if 555 * ignoreTimers, ignoreInputs, or ignoreSignals is FALSE. 556 */ 557int _XtWaitForSomething( 558 XtAppContext app, 559 _XtBoolean ignoreEvents, 560 _XtBoolean ignoreTimers, 561 _XtBoolean ignoreInputs, 562 _XtBoolean ignoreSignals, 563 _XtBoolean block, 564#ifdef XTHREADS 565 _XtBoolean drop_lock, 566#endif 567 unsigned long *howlong) 568{ 569 wait_times_t wt; 570 wait_fds_t wf; 571 int nfds, dpy_no, found_input, dd; 572#ifdef XTHREADS 573 Boolean push_thread = TRUE; 574 Boolean pushed_thread = FALSE; 575 int level = 0; 576#endif 577#ifdef USE_POLL 578 struct pollfd fdlist[XT_DEFAULT_FDLIST_SIZE]; 579#endif 580 581#ifdef XTHREADS 582 /* assert ((ignoreTimers && ignoreInputs && ignoreSignals) || drop_lock); */ 583 /* If not multi-threaded, never drop lock */ 584 if (app->lock == (ThreadAppProc) NULL) 585 drop_lock = FALSE; 586#endif 587 588 InitTimes (block, howlong, &wt); 589 590#ifdef USE_POLL 591 wf.fdlist = NULL; 592 wf.stack = fdlist; 593 wf.fdlistlen = wf.num_dpys = 0; 594#endif 595 596WaitLoop: 597 app->rebuild_fdlist = TRUE; 598 599 while (1) { 600 AdjustTimes (app, block, howlong, ignoreTimers, &wt); 601 602 if (block && app->block_hook_list) { 603 BlockHook hook; 604 for (hook = app->block_hook_list; 605 hook != NULL; 606 hook = hook->next) 607 (*hook->proc) (hook->closure); 608 609 if (!ignoreEvents) 610 /* see if the hook(s) generated any protocol */ 611 for (dd = 0; dd < app->count; dd++) 612 if (XEventsQueued(app->list[dd], QueuedAlready)) { 613#ifdef USE_POLL 614 XtStackFree ((XtPointer) wf.fdlist, fdlist); 615#endif 616 return dd; 617 } 618 } 619 620 if (app->rebuild_fdlist) 621 InitFds (app, ignoreEvents, ignoreInputs, &wf); 622 623#ifdef XTHREADS /* { */ 624 if (drop_lock) { 625 YIELD_APP_LOCK(app, &push_thread, &pushed_thread, &level); 626 nfds = IoWait (&wt, &wf); 627 RESTORE_APP_LOCK(app, level, &pushed_thread); 628 } else 629#endif /* } */ 630 nfds = IoWait (&wt, &wf); 631 if (nfds == -1) { 632 /* 633 * interrupt occured recalculate time value and wait again. 634 */ 635 if (errno == EINTR || errno == EAGAIN) { 636 if (errno == EAGAIN) { 637 errno = 0; /* errno is not self reseting */ 638 continue; 639 } 640 errno = 0; /* errno is not self reseting */ 641 642 /* was it interrupted by a signal that we care about? */ 643 if (!ignoreSignals && app->signalQueue != NULL) { 644 SignalEventRec *se_ptr = app->signalQueue; 645 while (se_ptr != NULL) { 646 if (se_ptr->se_notice) { 647 if (block && howlong != NULL) 648 AdjustHowLong (howlong, &wt.start_time); 649#ifdef USE_POLL 650 XtStackFree ((XtPointer) wf.fdlist, fdlist); 651#endif 652 return -1; 653 } 654 se_ptr = se_ptr->se_next; 655 } 656 } 657 658 if (!ignoreEvents) 659 /* get Xlib to detect a bad connection */ 660 for (dd = 0; dd < app->count; dd++) 661 if (XEventsQueued(app->list[dd], QueuedAfterReading)) { 662#ifdef USE_POLL 663 XtStackFree ((XtPointer) wf.fdlist, fdlist); 664#endif 665 return dd; 666 } 667 668 if (block) { 669#ifndef USE_POLL 670 if (wt.wait_time_ptr == NULL) 671#else 672 if (wt.poll_wait == X_BLOCK) 673#endif 674 continue; 675 X_GETTIMEOFDAY (&wt.new_time); 676 FIXUP_TIMEVAL (wt.new_time); 677 TIMEDELTA (wt.time_spent, wt.new_time, wt.cur_time); 678 wt.cur_time = wt.new_time; 679#ifndef USE_POLL 680 if (IS_AFTER (wt.time_spent, *wt.wait_time_ptr)) { 681 TIMEDELTA (wt.wait_time, *wt.wait_time_ptr, wt.time_spent); 682 wt.wait_time_ptr = &wt.wait_time; 683 continue; 684 } else 685#else 686 if ((wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000) < wt.poll_wait) { 687 wt.poll_wait -= (wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000); 688 continue; 689 } else 690#endif 691 nfds = 0; 692 } 693 } else { 694 char Errno[12]; 695 String param = Errno; 696 Cardinal param_count = 1; 697 698 sprintf( Errno, "%d", errno); 699 XtAppWarningMsg(app, "communicationError","select", 700 XtCXtToolkitError,"Select failed; error code %s", 701 ¶m, ¶m_count); 702 continue; 703 } 704 } /* timed out or input available */ 705 break; 706 } 707 708 if (nfds == 0) { 709 /* Timed out */ 710 if (howlong) 711 *howlong = (unsigned long)0; 712#ifdef USE_POLL 713 XtStackFree ((XtPointer) wf.fdlist, fdlist); 714#endif 715 return -1; 716 } 717 718 if (block && howlong != NULL) 719 AdjustHowLong (howlong, &wt.start_time); 720 721 if (ignoreInputs && ignoreEvents) { 722#ifdef USE_POLL 723 XtStackFree ((XtPointer) wf.fdlist, fdlist); 724#endif 725 return -1; 726 } else 727 FindInputs (app, &wf, nfds, 728 ignoreEvents, ignoreInputs, 729 &dpy_no, &found_input); 730 731 if (dpy_no >= 0 || found_input) { 732#ifdef USE_POLL 733 XtStackFree ((XtPointer) wf.fdlist, fdlist); 734#endif 735 return dpy_no; 736 } 737 goto WaitLoop; 738} 739 740#define IeCallProc(ptr) \ 741 (*ptr->ie_proc) (ptr->ie_closure, &ptr->ie_source, (XtInputId*)&ptr); 742 743#define TeCallProc(ptr) \ 744 (*ptr->te_proc) (ptr->te_closure, (XtIntervalId*)&ptr); 745 746#define SeCallProc(ptr) \ 747 (*ptr->se_proc) (ptr->se_closure, (XtSignalId*)&ptr); 748 749/* 750 * Public Routines 751 */ 752 753XtIntervalId XtAddTimeOut( 754 unsigned long interval, 755 XtTimerCallbackProc proc, 756 XtPointer closure) 757{ 758 return XtAppAddTimeOut(_XtDefaultAppContext(), 759 interval, proc, closure); 760} 761 762static void QueueTimerEvent( 763 XtAppContext app, 764 TimerEventRec *ptr) 765{ 766 TimerEventRec *t,**tt; 767 tt = &app->timerQueue; 768 t = *tt; 769 while (t != NULL && 770 IS_AFTER(t->te_timer_value, ptr->te_timer_value)) { 771 tt = &t->te_next; 772 t = *tt; 773 } 774 ptr->te_next = t; 775 *tt = ptr; 776} 777 778XtIntervalId XtAppAddTimeOut( 779 XtAppContext app, 780 unsigned long interval, 781 XtTimerCallbackProc proc, 782 XtPointer closure) 783{ 784 TimerEventRec *tptr; 785 struct timeval current_time; 786 787 LOCK_APP(app); 788 LOCK_PROCESS; 789 if (freeTimerRecs) { 790 tptr = freeTimerRecs; 791 freeTimerRecs = tptr->te_next; 792 } 793 else tptr = XtNew(TimerEventRec); 794 UNLOCK_PROCESS; 795 796 tptr->te_next = NULL; 797 tptr->te_closure = closure; 798 tptr->te_proc = proc; 799 tptr->app = app; 800 tptr->te_timer_value.tv_sec = interval/1000; 801 tptr->te_timer_value.tv_usec = (interval%1000)*1000; 802 X_GETTIMEOFDAY (¤t_time); 803 FIXUP_TIMEVAL(current_time); 804 ADD_TIME(tptr->te_timer_value,tptr->te_timer_value,current_time); 805 QueueTimerEvent(app, tptr); 806 UNLOCK_APP(app); 807 return( (XtIntervalId) tptr); 808} 809 810void XtRemoveTimeOut( 811 XtIntervalId id) 812{ 813 TimerEventRec *t, *last, *tid = (TimerEventRec *) id; 814 XtAppContext app = tid->app; 815 816 /* find it */ 817 LOCK_APP(app); 818 for(t = app->timerQueue, last = NULL; 819 t != NULL && t != tid; 820 t = t->te_next) last = t; 821 822 if (t == NULL) { 823 UNLOCK_APP(app); 824 return; /* couldn't find it */ 825 } 826 if(last == NULL) { /* first one on the list */ 827 app->timerQueue = t->te_next; 828 } else last->te_next = t->te_next; 829 830 LOCK_PROCESS; 831 t->te_next = freeTimerRecs; 832 freeTimerRecs = t; 833 UNLOCK_PROCESS; 834 UNLOCK_APP(app); 835} 836 837XtWorkProcId XtAddWorkProc( 838 XtWorkProc proc, 839 XtPointer closure) 840{ 841 return XtAppAddWorkProc(_XtDefaultAppContext(), proc, closure); 842} 843 844XtWorkProcId XtAppAddWorkProc( 845 XtAppContext app, 846 XtWorkProc proc, 847 XtPointer closure) 848{ 849 WorkProcRec *wptr; 850 851 LOCK_APP(app); 852 LOCK_PROCESS; 853 if (freeWorkRecs) { 854 wptr = freeWorkRecs; 855 freeWorkRecs = wptr->next; 856 } else wptr = XtNew(WorkProcRec); 857 UNLOCK_PROCESS; 858 wptr->next = app->workQueue; 859 wptr->closure = closure; 860 wptr->proc = proc; 861 wptr->app = app; 862 app->workQueue = wptr; 863 UNLOCK_APP(app); 864 return (XtWorkProcId) wptr; 865} 866 867void XtRemoveWorkProc( 868 XtWorkProcId id) 869{ 870 WorkProcRec *wid= (WorkProcRec *) id, *w, *last; 871 XtAppContext app = wid->app; 872 873 LOCK_APP(app); 874 /* find it */ 875 for(w = app->workQueue, last = NULL; 876 w != NULL && w != wid; w = w->next) last = w; 877 878 if (w == NULL) { 879 UNLOCK_APP(app); 880 return; /* couldn't find it */ 881 } 882 883 if(last == NULL) app->workQueue = w->next; 884 else last->next = w->next; 885 LOCK_PROCESS; 886 w->next = freeWorkRecs; 887 freeWorkRecs = w; 888 UNLOCK_PROCESS; 889 UNLOCK_APP(app); 890} 891 892XtSignalId XtAddSignal( 893 XtSignalCallbackProc proc, 894 XtPointer closure) 895{ 896 return XtAppAddSignal(_XtDefaultAppContext(), proc, closure); 897} 898 899XtSignalId XtAppAddSignal( 900 XtAppContext app, 901 XtSignalCallbackProc proc, 902 XtPointer closure) 903{ 904 SignalEventRec *sptr; 905 906 LOCK_APP(app); 907 LOCK_PROCESS; 908 if (freeSignalRecs) { 909 sptr = freeSignalRecs; 910 freeSignalRecs = sptr->se_next; 911 } else 912 sptr = XtNew(SignalEventRec); 913 UNLOCK_PROCESS; 914 sptr->se_next = app->signalQueue; 915 sptr->se_closure = closure; 916 sptr->se_proc = proc; 917 sptr->app = app; 918 sptr->se_notice = FALSE; 919 app->signalQueue = sptr; 920 UNLOCK_APP(app); 921 return (XtSignalId) sptr; 922} 923 924void XtRemoveSignal( 925 XtSignalId id) 926{ 927 SignalEventRec *sid = (SignalEventRec*) id, *s, *last = NULL; 928 XtAppContext app = sid->app; 929 930 LOCK_APP(app); 931 for (s = app->signalQueue; s != NULL && s != sid; s = s->se_next) 932 last = s; 933 if (s == NULL) { 934 UNLOCK_APP(app); 935 return; 936 } 937 if (last == NULL) 938 app->signalQueue = s->se_next; 939 else 940 last->se_next = s->se_next; 941 LOCK_PROCESS; 942 s->se_next = freeSignalRecs; 943 freeSignalRecs = s; 944 UNLOCK_PROCESS; 945 UNLOCK_APP(app); 946} 947 948void XtNoticeSignal( 949 XtSignalId id) 950{ 951 /* 952 * It would be overkill to lock the app to set this flag. 953 * In the worst case, 2..n threads would be modifying this 954 * flag. The last one wins. Since signals occur asynchronously 955 * anyway, this can occur with or without threads. 956 * 957 * The other issue is that thread t1 sets the flag in a 958 * signalrec that has been deleted in thread t2. We rely 959 * on a detail of the implementation, i.e. free'd signalrecs 960 * aren't really free'd, they're just moved to a list of 961 * free recs, so deref'ing one won't hurt anything. 962 * 963 * Lastly, and perhaps most importantly, since POSIX threads 964 * says that the handling of asynchronous signals in a synchronous 965 * threads environment is undefined. Therefor it would be an 966 * error for both signals and threads to be in use in the same 967 * program. 968 */ 969 SignalEventRec *sid = (SignalEventRec*) id; 970 sid->se_notice = TRUE; 971} 972 973XtInputId XtAddInput( 974 int source, 975 XtPointer Condition, 976 XtInputCallbackProc proc, 977 XtPointer closure) 978{ 979 return XtAppAddInput(_XtDefaultAppContext(), 980 source, Condition, proc, closure); 981} 982 983XtInputId XtAppAddInput( 984 XtAppContext app, 985 int source, 986 XtPointer Condition, 987 XtInputCallbackProc proc, 988 XtPointer closure) 989{ 990 InputEvent* sptr; 991 XtInputMask condition = (XtInputMask) Condition; 992 993 LOCK_APP(app); 994 if (!condition || 995 condition & ~(XtInputReadMask|XtInputWriteMask|XtInputExceptMask)) 996 XtAppErrorMsg(app,"invalidParameter","xtAddInput",XtCXtToolkitError, 997 "invalid condition passed to XtAppAddInput", 998 (String *)NULL, (Cardinal *)NULL); 999 1000 if (app->input_max <= source) { 1001 Cardinal n = source + 1; 1002 int ii; 1003 app->input_list = (InputEvent**)XtRealloc((char*) app->input_list, 1004 n * sizeof(InputEvent*)); 1005 for (ii = app->input_max; ii < (int) n; ii++) 1006 app->input_list[ii] = (InputEvent*) NULL; 1007 app->input_max = n; 1008 } 1009 sptr = XtNew(InputEvent); 1010 sptr->ie_proc = proc; 1011 sptr->ie_closure = closure; 1012 sptr->app = app; 1013 sptr->ie_oq = NULL; 1014 sptr->ie_source = source; 1015 sptr->ie_condition = condition; 1016 sptr->ie_next = app->input_list[source]; 1017 app->input_list[source] = sptr; 1018 1019#ifndef USE_POLL 1020 if (condition & XtInputReadMask) FD_SET(source, &app->fds.rmask); 1021 if (condition & XtInputWriteMask) FD_SET(source, &app->fds.wmask); 1022 if (condition & XtInputExceptMask) FD_SET(source, &app->fds.emask); 1023 1024 if (app->fds.nfds < (source+1)) app->fds.nfds = source+1; 1025#else 1026 if (sptr->ie_next == NULL) 1027 app->fds.nfds++; 1028#endif 1029 app->input_count++; 1030 app->rebuild_fdlist = TRUE; 1031 UNLOCK_APP(app); 1032 return((XtInputId)sptr); 1033} 1034 1035void XtRemoveInput( 1036 register XtInputId id) 1037{ 1038 register InputEvent *sptr, *lptr; 1039 XtAppContext app = ((InputEvent *)id)->app; 1040 register int source = ((InputEvent *)id)->ie_source; 1041 Boolean found = False; 1042 1043 LOCK_APP(app); 1044 sptr = app->outstandingQueue; 1045 lptr = NULL; 1046 for (; sptr != NULL; sptr = sptr->ie_oq) { 1047 if (sptr == (InputEvent *)id) { 1048 if (lptr == NULL) app->outstandingQueue = sptr->ie_oq; 1049 else lptr->ie_oq = sptr->ie_oq; 1050 } 1051 lptr = sptr; 1052 } 1053 1054 if(app->input_list && (sptr = app->input_list[source]) != NULL) { 1055 for( lptr = NULL ; sptr; sptr = sptr->ie_next ){ 1056 if(sptr == (InputEvent *) id) { 1057#ifndef USE_POLL 1058 XtInputMask condition = 0; 1059#endif 1060 if(lptr == NULL) { 1061 app->input_list[source] = sptr->ie_next; 1062 } else { 1063 lptr->ie_next = sptr->ie_next; 1064 } 1065#ifndef USE_POLL 1066 for (lptr = app->input_list[source]; 1067 lptr; lptr = lptr->ie_next) 1068 condition |= lptr->ie_condition; 1069 if ((sptr->ie_condition & XtInputReadMask) && 1070 !(condition & XtInputReadMask)) 1071 FD_CLR(source, &app->fds.rmask); 1072 if ((sptr->ie_condition & XtInputWriteMask) && 1073 !(condition & XtInputWriteMask)) 1074 FD_CLR(source, &app->fds.wmask); 1075 if ((sptr->ie_condition & XtInputExceptMask) && 1076 !(condition & XtInputExceptMask)) 1077 FD_CLR(source, &app->fds.emask); 1078#endif 1079 XtFree((char *) sptr); 1080 found = True; 1081 break; 1082 } 1083 lptr = sptr; 1084 } 1085 } 1086 1087 if (found) { 1088 app->input_count--; 1089#ifdef USE_POLL 1090 if (app->input_list[source] == NULL) 1091 app->fds.nfds--; 1092#endif 1093 app->rebuild_fdlist = TRUE; 1094 } else 1095 XtAppWarningMsg(app, "invalidProcedure","inputHandler", 1096 XtCXtToolkitError, 1097 "XtRemoveInput: Input handler not found", 1098 (String *)NULL, (Cardinal *)NULL); 1099 UNLOCK_APP(app); 1100} 1101 1102void _XtRemoveAllInputs( 1103 XtAppContext app) 1104{ 1105 int i; 1106 for (i = 0; i < app->input_max; i++) { 1107 InputEvent* ep = app->input_list[i]; 1108 while (ep) { 1109 InputEvent *next = ep->ie_next; 1110 XtFree( (char*)ep ); 1111 ep = next; 1112 } 1113 } 1114 XtFree((char *) app->input_list); 1115} 1116 1117/* Do alternate input and timer callbacks if there are any */ 1118 1119static void DoOtherSources( 1120 XtAppContext app) 1121{ 1122 TimerEventRec *te_ptr; 1123 InputEvent *ie_ptr; 1124 struct timeval cur_time; 1125 1126#define DrainQueue() \ 1127 for (ie_ptr = app->outstandingQueue; ie_ptr != NULL;) { \ 1128 app->outstandingQueue = ie_ptr->ie_oq; \ 1129 ie_ptr ->ie_oq = NULL; \ 1130 IeCallProc(ie_ptr); \ 1131 ie_ptr = app->outstandingQueue; \ 1132 } 1133/*enddef*/ 1134 DrainQueue(); 1135 if (app->input_count > 0) { 1136 /* Call _XtWaitForSomething to get input queued up */ 1137 (void) _XtWaitForSomething (app, 1138 TRUE, TRUE, FALSE, TRUE, 1139 FALSE, 1140#ifdef XTHREADS 1141 TRUE, 1142#endif 1143 (unsigned long *)NULL); 1144 DrainQueue(); 1145 } 1146 if (app->timerQueue != NULL) { /* check timeout queue */ 1147 X_GETTIMEOFDAY (&cur_time); 1148 FIXUP_TIMEVAL(cur_time); 1149 while(IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time)) { 1150 te_ptr = app->timerQueue; 1151 app->timerQueue = te_ptr->te_next; 1152 te_ptr->te_next = NULL; 1153 if (te_ptr->te_proc != NULL) 1154 TeCallProc(te_ptr); 1155 LOCK_PROCESS; 1156 te_ptr->te_next = freeTimerRecs; 1157 freeTimerRecs = te_ptr; 1158 UNLOCK_PROCESS; 1159 if (app->timerQueue == NULL) break; 1160 } 1161 } 1162 if (app->signalQueue != NULL) { 1163 SignalEventRec *se_ptr = app->signalQueue; 1164 while (se_ptr != NULL) { 1165 if (se_ptr->se_notice) { 1166 se_ptr->se_notice = FALSE; 1167 if (se_ptr->se_proc != NULL) 1168 SeCallProc(se_ptr); 1169 } 1170 se_ptr = se_ptr->se_next; 1171 } 1172 } 1173#undef DrainQueue 1174} 1175 1176/* If there are any work procs, call them. Return whether we did so */ 1177 1178static Boolean CallWorkProc( 1179 XtAppContext app) 1180{ 1181 register WorkProcRec *w = app->workQueue; 1182 Boolean delete; 1183 1184 if (w == NULL) return FALSE; 1185 1186 app->workQueue = w->next; 1187 1188 delete = (*(w->proc)) (w->closure); 1189 1190 if (delete) { 1191 LOCK_PROCESS; 1192 w->next = freeWorkRecs; 1193 freeWorkRecs = w; 1194 UNLOCK_PROCESS; 1195 } 1196 else { 1197 w->next = app->workQueue; 1198 app->workQueue = w; 1199 } 1200 return TRUE; 1201} 1202 1203/* 1204 * XtNextEvent() 1205 * return next event; 1206 */ 1207 1208void XtNextEvent( 1209 XEvent *event) 1210{ 1211 XtAppNextEvent(_XtDefaultAppContext(), event); 1212} 1213 1214void _XtRefreshMapping( 1215 XEvent* event, 1216 _XtBoolean dispatch) 1217{ 1218 XtPerDisplay pd; 1219 1220 LOCK_PROCESS; 1221 pd = _XtGetPerDisplay(event->xmapping.display); 1222 if (event->xmapping.request != MappingPointer && 1223 pd && pd->keysyms && (event->xmapping.serial >= pd->keysyms_serial)) 1224 _XtBuildKeysymTables( event->xmapping.display, pd ); 1225 XRefreshKeyboardMapping(&event->xmapping); 1226 if (dispatch && pd && pd->mapping_callbacks) 1227 XtCallCallbackList((Widget) NULL, 1228 (XtCallbackList)pd->mapping_callbacks, 1229 (XtPointer)event ); 1230 UNLOCK_PROCESS; 1231} 1232 1233void XtAppNextEvent( 1234 XtAppContext app, 1235 XEvent *event) 1236{ 1237 int i, d; 1238 1239 LOCK_APP(app); 1240 for (;;) { 1241 if (app->count == 0) 1242 DoOtherSources(app); 1243 else { 1244 for (i = 1; i <= app->count; i++) { 1245 d = (i + app->last) % app->count; 1246 if (d == 0) DoOtherSources(app); 1247 if (XEventsQueued(app->list[d], QueuedAfterReading)) 1248 goto GotEvent; 1249 } 1250 for (i = 1; i <= app->count; i++) { 1251 d = (i + app->last) % app->count; 1252 if (XEventsQueued(app->list[d], QueuedAfterFlush)) 1253 goto GotEvent; 1254 } 1255 } 1256 1257 /* We're ready to wait...if there is a work proc, call it */ 1258 if (CallWorkProc(app)) continue; 1259 1260 d = _XtWaitForSomething (app, 1261 FALSE, FALSE, FALSE, FALSE, 1262 TRUE, 1263#ifdef XTHREADS 1264 TRUE, 1265#endif 1266 (unsigned long *) NULL); 1267 1268 if (d != -1) { 1269 GotEvent: 1270 XNextEvent (app->list[d], event); 1271#ifdef XTHREADS 1272 /* assert(app->list[d] == event->xany.display); */ 1273#endif 1274 app->last = d; 1275 if (event->xany.type == MappingNotify) 1276 _XtRefreshMapping(event, False); 1277 UNLOCK_APP(app); 1278 return; 1279 } 1280 1281 } /* for */ 1282} 1283 1284void XtProcessEvent( 1285 XtInputMask mask) 1286{ 1287 XtAppProcessEvent(_XtDefaultAppContext(), mask); 1288} 1289 1290void XtAppProcessEvent( 1291 XtAppContext app, 1292 XtInputMask mask) 1293{ 1294 int i, d; 1295 XEvent event; 1296 struct timeval cur_time; 1297 1298 LOCK_APP(app); 1299 if (mask == 0) { 1300 UNLOCK_APP(app); 1301 return; 1302 } 1303 1304 for (;;) { 1305 1306 if (mask & XtIMSignal && app->signalQueue != NULL) { 1307 SignalEventRec *se_ptr = app->signalQueue; 1308 while (se_ptr != NULL) { 1309 if (se_ptr->se_notice) { 1310 se_ptr->se_notice = FALSE; 1311 SeCallProc(se_ptr); 1312 UNLOCK_APP(app); 1313 return; 1314 } 1315 se_ptr = se_ptr->se_next; 1316 } 1317 } 1318 1319 if (mask & XtIMTimer && app->timerQueue != NULL) { 1320 X_GETTIMEOFDAY (&cur_time); 1321 FIXUP_TIMEVAL(cur_time); 1322 if (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)){ 1323 TimerEventRec *te_ptr = app->timerQueue; 1324 app->timerQueue = app->timerQueue->te_next; 1325 te_ptr->te_next = NULL; 1326 if (te_ptr->te_proc != NULL) 1327 TeCallProc(te_ptr); 1328 LOCK_PROCESS; 1329 te_ptr->te_next = freeTimerRecs; 1330 freeTimerRecs = te_ptr; 1331 UNLOCK_PROCESS; 1332 UNLOCK_APP(app); 1333 return; 1334 } 1335 } 1336 1337 if (mask & XtIMAlternateInput) { 1338 if (app->input_count > 0 && app->outstandingQueue == NULL) { 1339 /* Call _XtWaitForSomething to get input queued up */ 1340 (void) _XtWaitForSomething (app, 1341 TRUE, TRUE, FALSE, TRUE, 1342 FALSE, 1343#ifdef XTHREADS 1344 TRUE, 1345#endif 1346 (unsigned long *)NULL); 1347 } 1348 if (app->outstandingQueue != NULL) { 1349 InputEvent *ie_ptr = app->outstandingQueue; 1350 app->outstandingQueue = ie_ptr->ie_oq; 1351 ie_ptr->ie_oq = NULL; 1352 IeCallProc(ie_ptr); 1353 UNLOCK_APP(app); 1354 return; 1355 } 1356 } 1357 1358 if (mask & XtIMXEvent) { 1359 for (i = 1; i <= app->count; i++) { 1360 d = (i + app->last) % app->count; 1361 if (XEventsQueued(app->list[d], QueuedAfterReading)) 1362 goto GotEvent; 1363 } 1364 for (i = 1; i <= app->count; i++) { 1365 d = (i + app->last) % app->count; 1366 if (XEventsQueued(app->list[d], QueuedAfterFlush)) 1367 goto GotEvent; 1368 } 1369 } 1370 1371 /* Nothing to do...wait for something */ 1372 1373 if (CallWorkProc(app)) continue; 1374 1375 d = _XtWaitForSomething (app, 1376 (mask & XtIMXEvent ? FALSE : TRUE), 1377 (mask & XtIMTimer ? FALSE : TRUE), 1378 (mask & XtIMAlternateInput ? FALSE : TRUE), 1379 (mask & XtIMSignal ? FALSE : TRUE), 1380 TRUE, 1381#ifdef XTHREADS 1382 TRUE, 1383#endif 1384 (unsigned long *) NULL); 1385 1386 if (mask & XtIMXEvent && d != -1) { 1387 GotEvent: 1388 XNextEvent(app->list[d], &event); 1389#ifdef XTHREADS 1390 /* assert(app->list[d] == event.xany.display); */ 1391#endif 1392 app->last = d; 1393 if (event.xany.type == MappingNotify) { 1394 _XtRefreshMapping(&event, False); 1395 } 1396 XtDispatchEvent(&event); 1397 UNLOCK_APP(app); 1398 return; 1399 } 1400 1401 } 1402} 1403 1404Boolean XtPending(void) 1405{ 1406 return (XtAppPending(_XtDefaultAppContext()) != 0); 1407} 1408 1409XtInputMask XtAppPending( 1410 XtAppContext app) 1411{ 1412 struct timeval cur_time; 1413 int d; 1414 XtInputMask ret = 0; 1415 1416/* 1417 * Check for pending X events 1418 */ 1419 LOCK_APP(app); 1420 for (d = 0; d < app->count; d++) { 1421 if (XEventsQueued(app->list[d], QueuedAfterReading)) { 1422 ret = XtIMXEvent; 1423 break; 1424 } 1425 } 1426 if (ret == 0) { 1427 for (d = 0; d < app->count; d++) { 1428 if (XEventsQueued(app->list[d], QueuedAfterFlush)) { 1429 ret = XtIMXEvent; 1430 break; 1431 } 1432 } 1433 } 1434 1435 if (app->signalQueue != NULL) { 1436 SignalEventRec *se_ptr = app->signalQueue; 1437 while (se_ptr != NULL) { 1438 if (se_ptr->se_notice) { 1439 ret |= XtIMSignal; 1440 break; 1441 } 1442 se_ptr = se_ptr->se_next; 1443 } 1444 } 1445 1446/* 1447 * Check for pending alternate input 1448 */ 1449 if (app->timerQueue != NULL) { /* check timeout queue */ 1450 X_GETTIMEOFDAY (&cur_time); 1451 FIXUP_TIMEVAL(cur_time); 1452 if ((IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) && 1453 (app->timerQueue->te_proc != NULL)) { 1454 ret |= XtIMTimer; 1455 } 1456 } 1457 1458 if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput; 1459 else { 1460 /* This won't cause a wait, but will enqueue any input */ 1461 1462 if(_XtWaitForSomething (app, 1463 FALSE, TRUE, FALSE, TRUE, 1464 FALSE, 1465#ifdef XTHREADS 1466 TRUE, 1467#endif 1468 (unsigned long *) NULL) != -1) 1469 ret |= XtIMXEvent; 1470 if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput; 1471 } 1472 UNLOCK_APP(app); 1473 return ret; 1474} 1475 1476/* Peek at alternate input and timer callbacks if there are any */ 1477 1478static Boolean PeekOtherSources( 1479 XtAppContext app) 1480{ 1481 struct timeval cur_time; 1482 1483 if (app->outstandingQueue != NULL) return TRUE; 1484 1485 if (app->signalQueue != NULL) { 1486 SignalEventRec *se_ptr = app->signalQueue; 1487 while (se_ptr != NULL) { 1488 if (se_ptr->se_notice) 1489 return TRUE; 1490 se_ptr = se_ptr->se_next; 1491 } 1492 } 1493 1494 if (app->input_count > 0) { 1495 /* Call _XtWaitForSomething to get input queued up */ 1496 (void) _XtWaitForSomething (app, 1497 TRUE, TRUE, FALSE, TRUE, 1498 FALSE, 1499#ifdef XTHREADS 1500 TRUE, 1501#endif 1502 (unsigned long *)NULL); 1503 if (app->outstandingQueue != NULL) return TRUE; 1504 } 1505 1506 if (app->timerQueue != NULL) { /* check timeout queue */ 1507 X_GETTIMEOFDAY (&cur_time); 1508 FIXUP_TIMEVAL(cur_time); 1509 if (IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time)) 1510 return TRUE; 1511 } 1512 1513 return FALSE; 1514} 1515 1516Boolean XtPeekEvent( 1517 XEvent *event) 1518{ 1519 return XtAppPeekEvent(_XtDefaultAppContext(), event); 1520} 1521 1522Boolean XtAppPeekEvent_SkipTimer; 1523 1524Boolean XtAppPeekEvent( 1525 XtAppContext app, 1526 XEvent *event) 1527{ 1528 int i, d; 1529 Boolean foundCall = FALSE; 1530 1531 LOCK_APP(app); 1532 for (i = 1; i <= app->count; i++) { 1533 d = (i + app->last) % app->count; 1534 if (d == 0) foundCall = PeekOtherSources(app); 1535 if (XEventsQueued(app->list[d], QueuedAfterReading)) 1536 goto GotEvent; 1537 } 1538 for (i = 1; i <= app->count; i++) { 1539 d = (i + app->last) % app->count; 1540 if (XEventsQueued(app->list[d], QueuedAfterFlush)) 1541 goto GotEvent; 1542 } 1543 1544 if (foundCall) { 1545 event->xany.type = 0; 1546 event->xany.display = NULL; 1547 event->xany.window = 0; 1548 UNLOCK_APP(app); 1549 return FALSE; 1550 } 1551 1552 while (1) { 1553 d = _XtWaitForSomething (app, 1554 FALSE, FALSE, FALSE, FALSE, 1555 TRUE, 1556#ifdef XTHREADS 1557 TRUE, 1558#endif 1559 (unsigned long *) NULL); 1560 1561 if (d != -1) { /* event */ 1562 GotEvent: 1563 XPeekEvent(app->list[d], event); 1564 app->last = (d == 0 ? app->count : d) - 1; 1565 UNLOCK_APP(app); 1566 return TRUE; 1567 } 1568 else { /* input or timer or signal */ 1569 /* 1570 * Check to see why a -1 was returned, if a timer expired, 1571 * call it and block some more 1572 */ 1573 if ((app->timerQueue != NULL) && ! XtAppPeekEvent_SkipTimer) { /* timer */ 1574 struct timeval cur_time; 1575 Bool did_timer = False; 1576 1577 X_GETTIMEOFDAY (&cur_time); 1578 FIXUP_TIMEVAL(cur_time); 1579 while (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) { 1580 TimerEventRec *te_ptr = app->timerQueue; 1581 app->timerQueue = app->timerQueue->te_next; 1582 te_ptr->te_next = NULL; 1583 if (te_ptr->te_proc != NULL) { 1584 TeCallProc(te_ptr); 1585 did_timer = True; 1586 } 1587 LOCK_PROCESS; 1588 te_ptr->te_next = freeTimerRecs; 1589 freeTimerRecs = te_ptr; 1590 UNLOCK_PROCESS; 1591 if (app->timerQueue == NULL) break; 1592 } 1593 if (did_timer) 1594 { 1595 for (d = 0; d < app->count; d++) 1596 /* the timer's procedure may have caused an event */ 1597 if (XEventsQueued(app->list[d], QueuedAfterFlush)) { 1598 goto GotEvent; 1599 } 1600 continue; /* keep blocking */ 1601 } 1602 } 1603 /* 1604 * spec is vague here; we'll assume signals also return FALSE, 1605 * of course to determine whether a signal is pending requires 1606 * walking the signalQueue looking for se_notice flags which 1607 * this code doesn't do. 1608 */ 1609#if 0 1610 if (app->signalQueue != NULL) { /* signal */ 1611 event->xany.type = 0; 1612 event->xany.display = NULL; 1613 event->xany.window = 0; 1614 UNLOCK_APP(app); 1615 return FALSE; 1616 } 1617 else 1618#endif 1619 { /* input */ 1620 event->xany.type = 0; 1621 event->xany.display = NULL; 1622 event->xany.window = 0; 1623 UNLOCK_APP(app); 1624 return FALSE; 1625 } 1626 } 1627 } /* end while */ 1628} 1629