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