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