NextEvent.c revision a7daef0c
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 wf.fdlistlen = wf.num_dpys = 0; 583#endif 584 585WaitLoop: 586 app->rebuild_fdlist = TRUE; 587 588 while (1) { 589 AdjustTimes (app, block, howlong, ignoreTimers, &wt); 590 591 if (block && app->block_hook_list) { 592 BlockHook hook; 593 for (hook = app->block_hook_list; 594 hook != NULL; 595 hook = hook->next) 596 (*hook->proc) (hook->closure); 597 598 if (!ignoreEvents) 599 /* see if the hook(s) generated any protocol */ 600 for (dd = 0; dd < app->count; dd++) 601 if (XEventsQueued(app->list[dd], QueuedAlready)) { 602#ifdef USE_POLL 603 XtStackFree ((XtPointer) wf.fdlist, fdlist); 604#endif 605 return dd; 606 } 607 } 608 609 if (app->rebuild_fdlist) 610 InitFds (app, ignoreEvents, ignoreInputs, &wf); 611 612#ifdef XTHREADS /* { */ 613 if (drop_lock) { 614 YIELD_APP_LOCK(app, &push_thread, &pushed_thread, &level); 615 nfds = IoWait (&wt, &wf); 616 RESTORE_APP_LOCK(app, level, &pushed_thread); 617 } else 618#endif /* } */ 619 nfds = IoWait (&wt, &wf); 620 if (nfds == -1) { 621 /* 622 * interrupt occured recalculate time value and wait again. 623 */ 624 if (errno == EINTR || errno == EAGAIN) { 625 if (errno == EAGAIN) { 626 errno = 0; /* errno is not self reseting */ 627 continue; 628 } 629 errno = 0; /* errno is not self reseting */ 630 631 /* was it interrupted by a signal that we care about? */ 632 if (!ignoreSignals && app->signalQueue != NULL) { 633 SignalEventRec *se_ptr = app->signalQueue; 634 while (se_ptr != NULL) { 635 if (se_ptr->se_notice) { 636 if (block && howlong != NULL) 637 AdjustHowLong (howlong, &wt.start_time); 638#ifdef USE_POLL 639 XtStackFree ((XtPointer) wf.fdlist, fdlist); 640#endif 641 return -1; 642 } 643 se_ptr = se_ptr->se_next; 644 } 645 } 646 647 if (!ignoreEvents) 648 /* get Xlib to detect a bad connection */ 649 for (dd = 0; dd < app->count; dd++) 650 if (XEventsQueued(app->list[dd], QueuedAfterReading)) { 651#ifdef USE_POLL 652 XtStackFree ((XtPointer) wf.fdlist, fdlist); 653#endif 654 return dd; 655 } 656 657 if (block) { 658#ifndef USE_POLL 659 if (wt.wait_time_ptr == NULL) 660#else 661 if (wt.poll_wait == X_BLOCK) 662#endif 663 continue; 664 X_GETTIMEOFDAY (&wt.new_time); 665 FIXUP_TIMEVAL (wt.new_time); 666 TIMEDELTA (wt.time_spent, wt.new_time, wt.cur_time); 667 wt.cur_time = wt.new_time; 668#ifndef USE_POLL 669 if (IS_AFTER (wt.time_spent, *wt.wait_time_ptr)) { 670 TIMEDELTA (wt.wait_time, *wt.wait_time_ptr, wt.time_spent); 671 wt.wait_time_ptr = &wt.wait_time; 672 continue; 673 } else 674#else 675 if ((wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000) < wt.poll_wait) { 676 wt.poll_wait -= (wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000); 677 continue; 678 } else 679#endif 680 nfds = 0; 681 } 682 } else { 683 char Errno[12]; 684 String param = Errno; 685 Cardinal param_count = 1; 686 687 sprintf( Errno, "%d", errno); 688 XtAppWarningMsg(app, "communicationError","select", 689 XtCXtToolkitError,"Select failed; error code %s", 690 ¶m, ¶m_count); 691 continue; 692 } 693 } /* timed out or input available */ 694 break; 695 } 696 697 if (nfds == 0) { 698 /* Timed out */ 699 if (howlong) 700 *howlong = (unsigned long)0; 701#ifdef USE_POLL 702 XtStackFree ((XtPointer) wf.fdlist, fdlist); 703#endif 704 return -1; 705 } 706 707 if (block && howlong != NULL) 708 AdjustHowLong (howlong, &wt.start_time); 709 710 if (ignoreInputs && ignoreEvents) { 711#ifdef USE_POLL 712 XtStackFree ((XtPointer) wf.fdlist, fdlist); 713#endif 714 return -1; 715 } else 716 FindInputs (app, &wf, nfds, 717 ignoreEvents, ignoreInputs, 718 &dpy_no, &found_input); 719 720 if (dpy_no >= 0 || found_input) { 721#ifdef USE_POLL 722 XtStackFree ((XtPointer) wf.fdlist, fdlist); 723#endif 724 return dpy_no; 725 } 726 goto WaitLoop; 727} 728 729#define IeCallProc(ptr) \ 730 (*ptr->ie_proc) (ptr->ie_closure, &ptr->ie_source, (XtInputId*)&ptr); 731 732#define TeCallProc(ptr) \ 733 (*ptr->te_proc) (ptr->te_closure, (XtIntervalId*)&ptr); 734 735#define SeCallProc(ptr) \ 736 (*ptr->se_proc) (ptr->se_closure, (XtSignalId*)&ptr); 737 738/* 739 * Public Routines 740 */ 741 742XtIntervalId XtAddTimeOut( 743 unsigned long interval, 744 XtTimerCallbackProc proc, 745 XtPointer closure) 746{ 747 return XtAppAddTimeOut(_XtDefaultAppContext(), 748 interval, proc, closure); 749} 750 751static void QueueTimerEvent( 752 XtAppContext app, 753 TimerEventRec *ptr) 754{ 755 TimerEventRec *t,**tt; 756 tt = &app->timerQueue; 757 t = *tt; 758 while (t != NULL && 759 IS_AFTER(t->te_timer_value, ptr->te_timer_value)) { 760 tt = &t->te_next; 761 t = *tt; 762 } 763 ptr->te_next = t; 764 *tt = ptr; 765} 766 767XtIntervalId XtAppAddTimeOut( 768 XtAppContext app, 769 unsigned long interval, 770 XtTimerCallbackProc proc, 771 XtPointer closure) 772{ 773 TimerEventRec *tptr; 774 struct timeval current_time; 775 776 LOCK_APP(app); 777 LOCK_PROCESS; 778 if (freeTimerRecs) { 779 tptr = freeTimerRecs; 780 freeTimerRecs = tptr->te_next; 781 } 782 else tptr = XtNew(TimerEventRec); 783 UNLOCK_PROCESS; 784 785 tptr->te_next = NULL; 786 tptr->te_closure = closure; 787 tptr->te_proc = proc; 788 tptr->app = app; 789 tptr->te_timer_value.tv_sec = interval/1000; 790 tptr->te_timer_value.tv_usec = (interval%1000)*1000; 791 X_GETTIMEOFDAY (¤t_time); 792 FIXUP_TIMEVAL(current_time); 793 ADD_TIME(tptr->te_timer_value,tptr->te_timer_value,current_time); 794 QueueTimerEvent(app, tptr); 795 UNLOCK_APP(app); 796 return( (XtIntervalId) tptr); 797} 798 799void XtRemoveTimeOut( 800 XtIntervalId id) 801{ 802 TimerEventRec *t, *last, *tid = (TimerEventRec *) id; 803 XtAppContext app = tid->app; 804 805 /* find it */ 806 LOCK_APP(app); 807 for(t = app->timerQueue, last = NULL; 808 t != NULL && t != tid; 809 t = t->te_next) last = t; 810 811 if (t == NULL) { 812 UNLOCK_APP(app); 813 return; /* couldn't find it */ 814 } 815 if(last == NULL) { /* first one on the list */ 816 app->timerQueue = t->te_next; 817 } else last->te_next = t->te_next; 818 819 LOCK_PROCESS; 820 t->te_next = freeTimerRecs; 821 freeTimerRecs = t; 822 UNLOCK_PROCESS; 823 UNLOCK_APP(app); 824} 825 826XtWorkProcId XtAddWorkProc( 827 XtWorkProc proc, 828 XtPointer closure) 829{ 830 return XtAppAddWorkProc(_XtDefaultAppContext(), proc, closure); 831} 832 833XtWorkProcId XtAppAddWorkProc( 834 XtAppContext app, 835 XtWorkProc proc, 836 XtPointer closure) 837{ 838 WorkProcRec *wptr; 839 840 LOCK_APP(app); 841 LOCK_PROCESS; 842 if (freeWorkRecs) { 843 wptr = freeWorkRecs; 844 freeWorkRecs = wptr->next; 845 } else wptr = XtNew(WorkProcRec); 846 UNLOCK_PROCESS; 847 wptr->next = app->workQueue; 848 wptr->closure = closure; 849 wptr->proc = proc; 850 wptr->app = app; 851 app->workQueue = wptr; 852 UNLOCK_APP(app); 853 return (XtWorkProcId) wptr; 854} 855 856void XtRemoveWorkProc( 857 XtWorkProcId id) 858{ 859 WorkProcRec *wid= (WorkProcRec *) id, *w, *last; 860 XtAppContext app = wid->app; 861 862 LOCK_APP(app); 863 /* find it */ 864 for(w = app->workQueue, last = NULL; 865 w != NULL && w != wid; w = w->next) last = w; 866 867 if (w == NULL) { 868 UNLOCK_APP(app); 869 return; /* couldn't find it */ 870 } 871 872 if(last == NULL) app->workQueue = w->next; 873 else last->next = w->next; 874 LOCK_PROCESS; 875 w->next = freeWorkRecs; 876 freeWorkRecs = w; 877 UNLOCK_PROCESS; 878 UNLOCK_APP(app); 879} 880 881XtSignalId XtAddSignal( 882 XtSignalCallbackProc proc, 883 XtPointer closure) 884{ 885 return XtAppAddSignal(_XtDefaultAppContext(), proc, closure); 886} 887 888XtSignalId XtAppAddSignal( 889 XtAppContext app, 890 XtSignalCallbackProc proc, 891 XtPointer closure) 892{ 893 SignalEventRec *sptr; 894 895 LOCK_APP(app); 896 LOCK_PROCESS; 897 if (freeSignalRecs) { 898 sptr = freeSignalRecs; 899 freeSignalRecs = sptr->se_next; 900 } else 901 sptr = XtNew(SignalEventRec); 902 UNLOCK_PROCESS; 903 sptr->se_next = app->signalQueue; 904 sptr->se_closure = closure; 905 sptr->se_proc = proc; 906 sptr->app = app; 907 sptr->se_notice = FALSE; 908 app->signalQueue = sptr; 909 UNLOCK_APP(app); 910 return (XtSignalId) sptr; 911} 912 913void XtRemoveSignal( 914 XtSignalId id) 915{ 916 SignalEventRec *sid = (SignalEventRec*) id, *s, *last = NULL; 917 XtAppContext app = sid->app; 918 919 LOCK_APP(app); 920 for (s = app->signalQueue; s != NULL && s != sid; s = s->se_next) 921 last = s; 922 if (s == NULL) { 923 UNLOCK_APP(app); 924 return; 925 } 926 if (last == NULL) 927 app->signalQueue = s->se_next; 928 else 929 last->se_next = s->se_next; 930 LOCK_PROCESS; 931 s->se_next = freeSignalRecs; 932 freeSignalRecs = s; 933 UNLOCK_PROCESS; 934 UNLOCK_APP(app); 935} 936 937void XtNoticeSignal( 938 XtSignalId id) 939{ 940 /* 941 * It would be overkill to lock the app to set this flag. 942 * In the worst case, 2..n threads would be modifying this 943 * flag. The last one wins. Since signals occur asynchronously 944 * anyway, this can occur with or without threads. 945 * 946 * The other issue is that thread t1 sets the flag in a 947 * signalrec that has been deleted in thread t2. We rely 948 * on a detail of the implementation, i.e. free'd signalrecs 949 * aren't really free'd, they're just moved to a list of 950 * free recs, so deref'ing one won't hurt anything. 951 * 952 * Lastly, and perhaps most importantly, since POSIX threads 953 * says that the handling of asynchronous signals in a synchronous 954 * threads environment is undefined. Therefor it would be an 955 * error for both signals and threads to be in use in the same 956 * program. 957 */ 958 SignalEventRec *sid = (SignalEventRec*) id; 959 sid->se_notice = TRUE; 960} 961 962XtInputId XtAddInput( 963 int source, 964 XtPointer Condition, 965 XtInputCallbackProc proc, 966 XtPointer closure) 967{ 968 return XtAppAddInput(_XtDefaultAppContext(), 969 source, Condition, proc, closure); 970} 971 972XtInputId XtAppAddInput( 973 XtAppContext app, 974 int source, 975 XtPointer Condition, 976 XtInputCallbackProc proc, 977 XtPointer closure) 978{ 979 InputEvent* sptr; 980 XtInputMask condition = (XtInputMask) Condition; 981 982 LOCK_APP(app); 983 if (!condition || 984 condition & ~(XtInputReadMask|XtInputWriteMask|XtInputExceptMask)) 985 XtAppErrorMsg(app,"invalidParameter","xtAddInput",XtCXtToolkitError, 986 "invalid condition passed to XtAppAddInput", 987 (String *)NULL, (Cardinal *)NULL); 988 989 if (app->input_max <= source) { 990 Cardinal n = source + 1; 991 int ii; 992 app->input_list = (InputEvent**)XtRealloc((char*) app->input_list, 993 n * sizeof(InputEvent*)); 994 for (ii = app->input_max; ii < (int) n; ii++) 995 app->input_list[ii] = (InputEvent*) NULL; 996 app->input_max = n; 997 } 998 sptr = XtNew(InputEvent); 999 sptr->ie_proc = proc; 1000 sptr->ie_closure = closure; 1001 sptr->app = app; 1002 sptr->ie_oq = NULL; 1003 sptr->ie_source = source; 1004 sptr->ie_condition = condition; 1005 sptr->ie_next = app->input_list[source]; 1006 app->input_list[source] = sptr; 1007 1008#ifndef USE_POLL 1009 if (condition & XtInputReadMask) FD_SET(source, &app->fds.rmask); 1010 if (condition & XtInputWriteMask) FD_SET(source, &app->fds.wmask); 1011 if (condition & XtInputExceptMask) FD_SET(source, &app->fds.emask); 1012 1013 if (app->fds.nfds < (source+1)) app->fds.nfds = source+1; 1014#else 1015 if (sptr->ie_next == NULL) 1016 app->fds.nfds++; 1017#endif 1018 app->input_count++; 1019 app->rebuild_fdlist = TRUE; 1020 UNLOCK_APP(app); 1021 return((XtInputId)sptr); 1022} 1023 1024void XtRemoveInput( 1025 register XtInputId id) 1026{ 1027 register InputEvent *sptr, *lptr; 1028 XtAppContext app = ((InputEvent *)id)->app; 1029 register int source = ((InputEvent *)id)->ie_source; 1030 Boolean found = False; 1031 1032 LOCK_APP(app); 1033 sptr = app->outstandingQueue; 1034 lptr = NULL; 1035 for (; sptr != NULL; sptr = sptr->ie_oq) { 1036 if (sptr == (InputEvent *)id) { 1037 if (lptr == NULL) app->outstandingQueue = sptr->ie_oq; 1038 else lptr->ie_oq = sptr->ie_oq; 1039 } 1040 lptr = sptr; 1041 } 1042 1043 if(app->input_list && (sptr = app->input_list[source]) != NULL) { 1044 for( lptr = NULL ; sptr; sptr = sptr->ie_next ){ 1045 if(sptr == (InputEvent *) id) { 1046#ifndef USE_POLL 1047 XtInputMask condition = 0; 1048#endif 1049 if(lptr == NULL) { 1050 app->input_list[source] = sptr->ie_next; 1051 } else { 1052 lptr->ie_next = sptr->ie_next; 1053 } 1054#ifndef USE_POLL 1055 for (lptr = app->input_list[source]; 1056 lptr; lptr = lptr->ie_next) 1057 condition |= lptr->ie_condition; 1058 if ((sptr->ie_condition & XtInputReadMask) && 1059 !(condition & XtInputReadMask)) 1060 FD_CLR(source, &app->fds.rmask); 1061 if ((sptr->ie_condition & XtInputWriteMask) && 1062 !(condition & XtInputWriteMask)) 1063 FD_CLR(source, &app->fds.wmask); 1064 if ((sptr->ie_condition & XtInputExceptMask) && 1065 !(condition & XtInputExceptMask)) 1066 FD_CLR(source, &app->fds.emask); 1067#endif 1068 XtFree((char *) sptr); 1069 found = True; 1070 break; 1071 } 1072 lptr = sptr; 1073 } 1074 } 1075 1076 if (found) { 1077 app->input_count--; 1078#ifdef USE_POLL 1079 if (app->input_list[source] == NULL) 1080 app->fds.nfds--; 1081#endif 1082 app->rebuild_fdlist = TRUE; 1083 } else 1084 XtAppWarningMsg(app, "invalidProcedure","inputHandler", 1085 XtCXtToolkitError, 1086 "XtRemoveInput: Input handler not found", 1087 (String *)NULL, (Cardinal *)NULL); 1088 UNLOCK_APP(app); 1089} 1090 1091void _XtRemoveAllInputs( 1092 XtAppContext app) 1093{ 1094 int i; 1095 for (i = 0; i < app->input_max; i++) { 1096 InputEvent* ep = app->input_list[i]; 1097 while (ep) { 1098 InputEvent *next = ep->ie_next; 1099 XtFree( (char*)ep ); 1100 ep = next; 1101 } 1102 } 1103 XtFree((char *) app->input_list); 1104} 1105 1106/* Do alternate input and timer callbacks if there are any */ 1107 1108static void DoOtherSources( 1109 XtAppContext app) 1110{ 1111 TimerEventRec *te_ptr; 1112 InputEvent *ie_ptr; 1113 struct timeval cur_time; 1114 1115#define DrainQueue() \ 1116 for (ie_ptr = app->outstandingQueue; ie_ptr != NULL;) { \ 1117 app->outstandingQueue = ie_ptr->ie_oq; \ 1118 ie_ptr ->ie_oq = NULL; \ 1119 IeCallProc(ie_ptr); \ 1120 ie_ptr = app->outstandingQueue; \ 1121 } 1122/*enddef*/ 1123 DrainQueue(); 1124 if (app->input_count > 0) { 1125 /* Call _XtWaitForSomething to get input queued up */ 1126 (void) _XtWaitForSomething (app, 1127 TRUE, TRUE, FALSE, TRUE, 1128 FALSE, 1129#ifdef XTHREADS 1130 TRUE, 1131#endif 1132 (unsigned long *)NULL); 1133 DrainQueue(); 1134 } 1135 if (app->timerQueue != NULL) { /* check timeout queue */ 1136 X_GETTIMEOFDAY (&cur_time); 1137 FIXUP_TIMEVAL(cur_time); 1138 while(IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time)) { 1139 te_ptr = app->timerQueue; 1140 app->timerQueue = te_ptr->te_next; 1141 te_ptr->te_next = NULL; 1142 if (te_ptr->te_proc != NULL) 1143 TeCallProc(te_ptr); 1144 LOCK_PROCESS; 1145 te_ptr->te_next = freeTimerRecs; 1146 freeTimerRecs = te_ptr; 1147 UNLOCK_PROCESS; 1148 if (app->timerQueue == NULL) break; 1149 } 1150 } 1151 if (app->signalQueue != NULL) { 1152 SignalEventRec *se_ptr = app->signalQueue; 1153 while (se_ptr != NULL) { 1154 if (se_ptr->se_notice) { 1155 se_ptr->se_notice = FALSE; 1156 if (se_ptr->se_proc != NULL) 1157 SeCallProc(se_ptr); 1158 } 1159 se_ptr = se_ptr->se_next; 1160 } 1161 } 1162#undef DrainQueue 1163} 1164 1165/* If there are any work procs, call them. Return whether we did so */ 1166 1167static Boolean CallWorkProc( 1168 XtAppContext app) 1169{ 1170 register WorkProcRec *w = app->workQueue; 1171 Boolean delete; 1172 1173 if (w == NULL) return FALSE; 1174 1175 app->workQueue = w->next; 1176 1177 delete = (*(w->proc)) (w->closure); 1178 1179 if (delete) { 1180 LOCK_PROCESS; 1181 w->next = freeWorkRecs; 1182 freeWorkRecs = w; 1183 UNLOCK_PROCESS; 1184 } 1185 else { 1186 w->next = app->workQueue; 1187 app->workQueue = w; 1188 } 1189 return TRUE; 1190} 1191 1192/* 1193 * XtNextEvent() 1194 * return next event; 1195 */ 1196 1197void XtNextEvent( 1198 XEvent *event) 1199{ 1200 XtAppNextEvent(_XtDefaultAppContext(), event); 1201} 1202 1203void _XtRefreshMapping( 1204 XEvent* event, 1205 _XtBoolean dispatch) 1206{ 1207 XtPerDisplay pd; 1208 1209 LOCK_PROCESS; 1210 pd = _XtGetPerDisplay(event->xmapping.display); 1211 if (event->xmapping.request != MappingPointer && 1212 pd && pd->keysyms && (event->xmapping.serial >= pd->keysyms_serial)) 1213 _XtBuildKeysymTables( event->xmapping.display, pd ); 1214 XRefreshKeyboardMapping(&event->xmapping); 1215 if (dispatch && pd && pd->mapping_callbacks) 1216 XtCallCallbackList((Widget) NULL, 1217 (XtCallbackList)pd->mapping_callbacks, 1218 (XtPointer)event ); 1219 UNLOCK_PROCESS; 1220} 1221 1222void XtAppNextEvent( 1223 XtAppContext app, 1224 XEvent *event) 1225{ 1226 int i, d; 1227 1228 LOCK_APP(app); 1229 for (;;) { 1230 if (app->count == 0) 1231 DoOtherSources(app); 1232 else { 1233 for (i = 1; i <= app->count; i++) { 1234 d = (i + app->last) % app->count; 1235 if (d == 0) DoOtherSources(app); 1236 if (XEventsQueued(app->list[d], QueuedAfterReading)) 1237 goto GotEvent; 1238 } 1239 for (i = 1; i <= app->count; i++) { 1240 d = (i + app->last) % app->count; 1241 if (XEventsQueued(app->list[d], QueuedAfterFlush)) 1242 goto GotEvent; 1243 } 1244 } 1245 1246 /* We're ready to wait...if there is a work proc, call it */ 1247 if (CallWorkProc(app)) continue; 1248 1249 d = _XtWaitForSomething (app, 1250 FALSE, FALSE, FALSE, FALSE, 1251 TRUE, 1252#ifdef XTHREADS 1253 TRUE, 1254#endif 1255 (unsigned long *) NULL); 1256 1257 if (d != -1) { 1258 GotEvent: 1259 XNextEvent (app->list[d], event); 1260#ifdef XTHREADS 1261 /* assert(app->list[d] == event->xany.display); */ 1262#endif 1263 app->last = d; 1264 if (event->xany.type == MappingNotify) 1265 _XtRefreshMapping(event, False); 1266 UNLOCK_APP(app); 1267 return; 1268 } 1269 1270 } /* for */ 1271} 1272 1273void XtProcessEvent( 1274 XtInputMask mask) 1275{ 1276 XtAppProcessEvent(_XtDefaultAppContext(), mask); 1277} 1278 1279void XtAppProcessEvent( 1280 XtAppContext app, 1281 XtInputMask mask) 1282{ 1283 int i, d; 1284 XEvent event; 1285 struct timeval cur_time; 1286 1287 LOCK_APP(app); 1288 if (mask == 0) { 1289 UNLOCK_APP(app); 1290 return; 1291 } 1292 1293 for (;;) { 1294 1295 if (mask & XtIMSignal && app->signalQueue != NULL) { 1296 SignalEventRec *se_ptr = app->signalQueue; 1297 while (se_ptr != NULL) { 1298 if (se_ptr->se_notice) { 1299 se_ptr->se_notice = FALSE; 1300 SeCallProc(se_ptr); 1301 UNLOCK_APP(app); 1302 return; 1303 } 1304 se_ptr = se_ptr->se_next; 1305 } 1306 } 1307 1308 if (mask & XtIMTimer && app->timerQueue != NULL) { 1309 X_GETTIMEOFDAY (&cur_time); 1310 FIXUP_TIMEVAL(cur_time); 1311 if (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)){ 1312 TimerEventRec *te_ptr = app->timerQueue; 1313 app->timerQueue = app->timerQueue->te_next; 1314 te_ptr->te_next = NULL; 1315 if (te_ptr->te_proc != NULL) 1316 TeCallProc(te_ptr); 1317 LOCK_PROCESS; 1318 te_ptr->te_next = freeTimerRecs; 1319 freeTimerRecs = te_ptr; 1320 UNLOCK_PROCESS; 1321 UNLOCK_APP(app); 1322 return; 1323 } 1324 } 1325 1326 if (mask & XtIMAlternateInput) { 1327 if (app->input_count > 0 && app->outstandingQueue == NULL) { 1328 /* Call _XtWaitForSomething to get input queued up */ 1329 (void) _XtWaitForSomething (app, 1330 TRUE, TRUE, FALSE, TRUE, 1331 FALSE, 1332#ifdef XTHREADS 1333 TRUE, 1334#endif 1335 (unsigned long *)NULL); 1336 } 1337 if (app->outstandingQueue != NULL) { 1338 InputEvent *ie_ptr = app->outstandingQueue; 1339 app->outstandingQueue = ie_ptr->ie_oq; 1340 ie_ptr->ie_oq = NULL; 1341 IeCallProc(ie_ptr); 1342 UNLOCK_APP(app); 1343 return; 1344 } 1345 } 1346 1347 if (mask & XtIMXEvent) { 1348 for (i = 1; i <= app->count; i++) { 1349 d = (i + app->last) % app->count; 1350 if (XEventsQueued(app->list[d], QueuedAfterReading)) 1351 goto GotEvent; 1352 } 1353 for (i = 1; i <= app->count; i++) { 1354 d = (i + app->last) % app->count; 1355 if (XEventsQueued(app->list[d], QueuedAfterFlush)) 1356 goto GotEvent; 1357 } 1358 } 1359 1360 /* Nothing to do...wait for something */ 1361 1362 if (CallWorkProc(app)) continue; 1363 1364 d = _XtWaitForSomething (app, 1365 (mask & XtIMXEvent ? FALSE : TRUE), 1366 (mask & XtIMTimer ? FALSE : TRUE), 1367 (mask & XtIMAlternateInput ? FALSE : TRUE), 1368 (mask & XtIMSignal ? FALSE : TRUE), 1369 TRUE, 1370#ifdef XTHREADS 1371 TRUE, 1372#endif 1373 (unsigned long *) NULL); 1374 1375 if (mask & XtIMXEvent && d != -1) { 1376 GotEvent: 1377 XNextEvent(app->list[d], &event); 1378#ifdef XTHREADS 1379 /* assert(app->list[d] == event.xany.display); */ 1380#endif 1381 app->last = d; 1382 if (event.xany.type == MappingNotify) { 1383 _XtRefreshMapping(&event, False); 1384 } 1385 XtDispatchEvent(&event); 1386 UNLOCK_APP(app); 1387 return; 1388 } 1389 1390 } 1391} 1392 1393Boolean XtPending(void) 1394{ 1395 return (XtAppPending(_XtDefaultAppContext()) != 0); 1396} 1397 1398XtInputMask XtAppPending( 1399 XtAppContext app) 1400{ 1401 struct timeval cur_time; 1402 int d; 1403 XtInputMask ret = 0; 1404 1405/* 1406 * Check for pending X events 1407 */ 1408 LOCK_APP(app); 1409 for (d = 0; d < app->count; d++) { 1410 if (XEventsQueued(app->list[d], QueuedAfterReading)) { 1411 ret = XtIMXEvent; 1412 break; 1413 } 1414 } 1415 if (ret == 0) { 1416 for (d = 0; d < app->count; d++) { 1417 if (XEventsQueued(app->list[d], QueuedAfterFlush)) { 1418 ret = XtIMXEvent; 1419 break; 1420 } 1421 } 1422 } 1423 1424 if (app->signalQueue != NULL) { 1425 SignalEventRec *se_ptr = app->signalQueue; 1426 while (se_ptr != NULL) { 1427 if (se_ptr->se_notice) { 1428 ret |= XtIMSignal; 1429 break; 1430 } 1431 se_ptr = se_ptr->se_next; 1432 } 1433 } 1434 1435/* 1436 * Check for pending alternate input 1437 */ 1438 if (app->timerQueue != NULL) { /* check timeout queue */ 1439 X_GETTIMEOFDAY (&cur_time); 1440 FIXUP_TIMEVAL(cur_time); 1441 if ((IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) && 1442 (app->timerQueue->te_proc != NULL)) { 1443 ret |= XtIMTimer; 1444 } 1445 } 1446 1447 if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput; 1448 else { 1449 /* This won't cause a wait, but will enqueue any input */ 1450 1451 if(_XtWaitForSomething (app, 1452 FALSE, TRUE, FALSE, TRUE, 1453 FALSE, 1454#ifdef XTHREADS 1455 TRUE, 1456#endif 1457 (unsigned long *) NULL) != -1) 1458 ret |= XtIMXEvent; 1459 if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput; 1460 } 1461 UNLOCK_APP(app); 1462 return ret; 1463} 1464 1465/* Peek at alternate input and timer callbacks if there are any */ 1466 1467static Boolean PeekOtherSources( 1468 XtAppContext app) 1469{ 1470 struct timeval cur_time; 1471 1472 if (app->outstandingQueue != NULL) return TRUE; 1473 1474 if (app->signalQueue != NULL) { 1475 SignalEventRec *se_ptr = app->signalQueue; 1476 while (se_ptr != NULL) { 1477 if (se_ptr->se_notice) 1478 return TRUE; 1479 se_ptr = se_ptr->se_next; 1480 } 1481 } 1482 1483 if (app->input_count > 0) { 1484 /* Call _XtWaitForSomething to get input queued up */ 1485 (void) _XtWaitForSomething (app, 1486 TRUE, TRUE, FALSE, TRUE, 1487 FALSE, 1488#ifdef XTHREADS 1489 TRUE, 1490#endif 1491 (unsigned long *)NULL); 1492 if (app->outstandingQueue != NULL) return TRUE; 1493 } 1494 1495 if (app->timerQueue != NULL) { /* check timeout queue */ 1496 X_GETTIMEOFDAY (&cur_time); 1497 FIXUP_TIMEVAL(cur_time); 1498 if (IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time)) 1499 return TRUE; 1500 } 1501 1502 return FALSE; 1503} 1504 1505Boolean XtPeekEvent( 1506 XEvent *event) 1507{ 1508 return XtAppPeekEvent(_XtDefaultAppContext(), event); 1509} 1510 1511Boolean XtAppPeekEvent_SkipTimer; 1512 1513Boolean XtAppPeekEvent( 1514 XtAppContext app, 1515 XEvent *event) 1516{ 1517 int i, d; 1518 Boolean foundCall = FALSE; 1519 1520 LOCK_APP(app); 1521 for (i = 1; i <= app->count; i++) { 1522 d = (i + app->last) % app->count; 1523 if (d == 0) foundCall = PeekOtherSources(app); 1524 if (XEventsQueued(app->list[d], QueuedAfterReading)) 1525 goto GotEvent; 1526 } 1527 for (i = 1; i <= app->count; i++) { 1528 d = (i + app->last) % app->count; 1529 if (XEventsQueued(app->list[d], QueuedAfterFlush)) 1530 goto GotEvent; 1531 } 1532 1533 if (foundCall) { 1534 event->xany.type = 0; 1535 event->xany.display = NULL; 1536 event->xany.window = 0; 1537 UNLOCK_APP(app); 1538 return FALSE; 1539 } 1540 1541 while (1) { 1542 d = _XtWaitForSomething (app, 1543 FALSE, FALSE, FALSE, FALSE, 1544 TRUE, 1545#ifdef XTHREADS 1546 TRUE, 1547#endif 1548 (unsigned long *) NULL); 1549 1550 if (d != -1) { /* event */ 1551 GotEvent: 1552 XPeekEvent(app->list[d], event); 1553 app->last = (d == 0 ? app->count : d) - 1; 1554 UNLOCK_APP(app); 1555 return TRUE; 1556 } 1557 else { /* input or timer or signal */ 1558 /* 1559 * Check to see why a -1 was returned, if a timer expired, 1560 * call it and block some more 1561 */ 1562 if ((app->timerQueue != NULL) && ! XtAppPeekEvent_SkipTimer) { /* timer */ 1563 struct timeval cur_time; 1564 Bool did_timer = False; 1565 1566 X_GETTIMEOFDAY (&cur_time); 1567 FIXUP_TIMEVAL(cur_time); 1568 while (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) { 1569 TimerEventRec *te_ptr = app->timerQueue; 1570 app->timerQueue = app->timerQueue->te_next; 1571 te_ptr->te_next = NULL; 1572 if (te_ptr->te_proc != NULL) { 1573 TeCallProc(te_ptr); 1574 did_timer = True; 1575 } 1576 LOCK_PROCESS; 1577 te_ptr->te_next = freeTimerRecs; 1578 freeTimerRecs = te_ptr; 1579 UNLOCK_PROCESS; 1580 if (app->timerQueue == NULL) break; 1581 } 1582 if (did_timer) 1583 { 1584 for (d = 0; d < app->count; d++) 1585 /* the timer's procedure may have caused an event */ 1586 if (XEventsQueued(app->list[d], QueuedAfterFlush)) { 1587 goto GotEvent; 1588 } 1589 continue; /* keep blocking */ 1590 } 1591 } 1592 /* 1593 * spec is vague here; we'll assume signals also return FALSE, 1594 * of course to determine whether a signal is pending requires 1595 * walking the signalQueue looking for se_notice flags which 1596 * this code doesn't do. 1597 */ 1598#if 0 1599 if (app->signalQueue != NULL) { /* signal */ 1600 event->xany.type = 0; 1601 event->xany.display = NULL; 1602 event->xany.window = 0; 1603 UNLOCK_APP(app); 1604 return FALSE; 1605 } 1606 else 1607#endif 1608 { /* input */ 1609 event->xany.type = 0; 1610 event->xany.display = NULL; 1611 event->xany.window = 0; 1612 UNLOCK_APP(app); 1613 return FALSE; 1614 } 1615 } 1616 } /* end while */ 1617} 1618