Home | History | Annotate | Line # | Download | only in src
      1 /***********************************************************
      2 Copyright (c) 1993, Oracle and/or its affiliates.
      3 
      4 Permission is hereby granted, free of charge, to any person obtaining a
      5 copy of this software and associated documentation files (the "Software"),
      6 to deal in the Software without restriction, including without limitation
      7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 and/or sell copies of the Software, and to permit persons to whom the
      9 Software is furnished to do so, subject to the following conditions:
     10 
     11 The above copyright notice and this permission notice (including the next
     12 paragraph) shall be included in all copies or substantial portions of the
     13 Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21 DEALINGS IN THE SOFTWARE.
     22 
     23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
     24 
     25                         All Rights Reserved
     26 
     27 Permission to use, copy, modify, and distribute this software and its
     28 documentation for any purpose and without fee is hereby granted,
     29 provided that the above copyright notice appear in all copies and that
     30 both that copyright notice and this permission notice appear in
     31 supporting documentation, and that the name of Digital not be
     32 used in advertising or publicity pertaining to distribution of the
     33 software without specific, written prior permission.
     34 
     35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     41 SOFTWARE.
     42 
     43 ******************************************************************/
     44 
     45 /*
     46 
     47 Copyright 1987, 1988, 1994, 1998, 2001  The Open Group
     48 
     49 Permission to use, copy, modify, distribute, and sell this software and its
     50 documentation for any purpose is hereby granted without fee, provided that
     51 the above copyright notice appear in all copies and that both that
     52 copyright notice and this permission notice appear in supporting
     53 documentation.
     54 
     55 The above copyright notice and this permission notice shall be included in
     56 all copies or substantial portions of the Software.
     57 
     58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     64 
     65 Except as contained in this notice, the name of The Open Group shall not be
     66 used in advertising or otherwise to promote the sale, use or other dealings
     67 in 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
     79 typedef long suseconds_t;
     80 #endif
     81 
     82 static TimerEventRec *freeTimerRecs;
     83 static WorkProcRec *freeWorkRecs;
     84 static 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 #ifdef sun
     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 
    146 static void
    147 AdjustHowLong(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 
    165 typedef 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 
    179 static struct timeval zero_time = { 0, 0 };
    180 
    181 #ifdef USE_POLL
    182 #define X_BLOCK -1
    183 #define X_DONT_BLOCK 0
    184 #else
    185 static fd_set zero_fd;
    186 #endif
    187 
    188 static void
    189 InitTimes(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 
    225 typedef 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 
    236 static void
    237 InitFds(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 
    330 static void
    331 AdjustTimes(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 
    368 static int
    369 IoWait(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 
    379 static void
    380 FindInputs(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  */
    573 int
    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", &param,
    727                                 &param_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 
    787 XtIntervalId
    788 XtAddTimeOut(unsigned long interval,
    789              XtTimerCallbackProc proc,
    790              XtPointer closure)
    791 {
    792     return XtAppAddTimeOut(_XtDefaultAppContext(), interval, proc, closure);
    793 }
    794 
    795 static void
    796 QueueTimerEvent(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 
    810 XtIntervalId
    811 XtAppAddTimeOut(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(&current_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 
    844 void
    845 XtRemoveTimeOut(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 
    873 XtWorkProcId
    874 XtAddWorkProc(XtWorkProc proc, XtPointer closure)
    875 {
    876     return XtAppAddWorkProc(_XtDefaultAppContext(), proc, closure);
    877 }
    878 
    879 XtWorkProcId
    880 XtAppAddWorkProc(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 
    904 void
    905 XtRemoveWorkProc(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 
    931 XtSignalId
    932 XtAddSignal(XtSignalCallbackProc proc, XtPointer closure)
    933 {
    934     return XtAppAddSignal(_XtDefaultAppContext(), proc, closure);
    935 }
    936 
    937 XtSignalId
    938 XtAppAddSignal(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 
    962 void
    963 XtRemoveSignal(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 
    986 void
    987 XtNoticeSignal(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 
   1012 XtInputId
   1013 XtAddInput(int source,
   1014            XtPointer Condition,
   1015            XtInputCallbackProc proc,
   1016            XtPointer closure)
   1017 {
   1018     return XtAppAddInput(_XtDefaultAppContext(),
   1019                          source, Condition, proc, closure);
   1020 }
   1021 
   1022 XtInputId
   1023 XtAppAddInput(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 
   1081 void
   1082 XtRemoveInput(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 
   1150 void
   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 
   1170 static void
   1171 DoOtherSources(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 
   1227 static Boolean
   1228 CallWorkProc(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 
   1258 void
   1259 XtNextEvent(XEvent *event)
   1260 {
   1261     XtAppNextEvent(_XtDefaultAppContext(), event);
   1262 }
   1263 
   1264 void
   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 
   1284 void
   1285 XtAppNextEvent(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 
   1329 void
   1330 XtProcessEvent(XtInputMask mask)
   1331 {
   1332     XtAppProcessEvent(_XtDefaultAppContext(), mask);
   1333 }
   1334 
   1335 void
   1336 XtAppProcessEvent(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 
   1441 Boolean
   1442 XtPending(void)
   1443 {
   1444     return (XtAppPending(_XtDefaultAppContext()) != 0);
   1445 }
   1446 
   1447 XtInputMask
   1448 XtAppPending(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 
   1515 static Boolean
   1516 PeekOtherSources(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 
   1552 Boolean
   1553 XtPeekEvent(XEvent *event)
   1554 {
   1555     return XtAppPeekEvent(_XtDefaultAppContext(), event);
   1556 }
   1557 
   1558 Boolean XtAppPeekEvent_SkipTimer;
   1559 
   1560 Boolean
   1561 XtAppPeekEvent(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