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