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