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