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