1 /***********************************************************
2 Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
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 #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 
146 static void
AdjustHowLong(unsigned long * howlong,struct timeval * start_time)147 AdjustHowLong(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 
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
InitTimes(Boolean block,unsigned long * howlong,wait_times_ptr_t wt)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
InitFds(XtAppContext app,Boolean ignoreEvents,Boolean ignoreInputs,wait_fds_ptr_t wf)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 = (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 
332 static void
AdjustTimes(XtAppContext app,Boolean block,unsigned long * howlong,Boolean ignoreTimers,wait_times_ptr_t wt)333 AdjustTimes(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 
370 static int
IoWait(wait_times_ptr_t wt,wait_fds_ptr_t wf)371 IoWait(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 
381 static void
FindInputs(XtAppContext app,wait_fds_ptr_t wf,int nfds _X_UNUSED,Boolean ignoreEvents,Boolean ignoreInputs,int * dpy_no,int * found_input)382 FindInputs(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  */
575 int
_XtWaitForSomething(XtAppContext app,_XtBoolean ignoreEvents,_XtBoolean ignoreTimers,_XtBoolean ignoreInputs,_XtBoolean ignoreSignals,_XtBoolean block,_XtBoolean drop_lock,unsigned long * howlong)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 
789 XtIntervalId
XtAddTimeOut(unsigned long interval,XtTimerCallbackProc proc,XtPointer closure)790 XtAddTimeOut(unsigned long interval,
791              XtTimerCallbackProc proc,
792              XtPointer closure)
793 {
794     return XtAppAddTimeOut(_XtDefaultAppContext(), interval, proc, closure);
795 }
796 
797 static void
QueueTimerEvent(XtAppContext app,TimerEventRec * ptr)798 QueueTimerEvent(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 
812 XtIntervalId
XtAppAddTimeOut(XtAppContext app,unsigned long interval,XtTimerCallbackProc proc,XtPointer closure)813 XtAppAddTimeOut(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 
846 void
XtRemoveTimeOut(XtIntervalId id)847 XtRemoveTimeOut(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 
875 XtWorkProcId
XtAddWorkProc(XtWorkProc proc,XtPointer closure)876 XtAddWorkProc(XtWorkProc proc, XtPointer closure)
877 {
878     return XtAppAddWorkProc(_XtDefaultAppContext(), proc, closure);
879 }
880 
881 XtWorkProcId
XtAppAddWorkProc(XtAppContext app,XtWorkProc proc,XtPointer closure)882 XtAppAddWorkProc(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 
906 void
XtRemoveWorkProc(XtWorkProcId id)907 XtRemoveWorkProc(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 
933 XtSignalId
XtAddSignal(XtSignalCallbackProc proc,XtPointer closure)934 XtAddSignal(XtSignalCallbackProc proc, XtPointer closure)
935 {
936     return XtAppAddSignal(_XtDefaultAppContext(), proc, closure);
937 }
938 
939 XtSignalId
XtAppAddSignal(XtAppContext app,XtSignalCallbackProc proc,XtPointer closure)940 XtAppAddSignal(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 
964 void
XtRemoveSignal(XtSignalId id)965 XtRemoveSignal(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 
988 void
XtNoticeSignal(XtSignalId id)989 XtNoticeSignal(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 
1014 XtInputId
XtAddInput(int source,XtPointer Condition,XtInputCallbackProc proc,XtPointer closure)1015 XtAddInput(int source,
1016            XtPointer Condition,
1017            XtInputCallbackProc proc,
1018            XtPointer closure)
1019 {
1020     return XtAppAddInput(_XtDefaultAppContext(),
1021                          source, Condition, proc, closure);
1022 }
1023 
1024 XtInputId
XtAppAddInput(XtAppContext app,int source,XtPointer Condition,XtInputCallbackProc proc,XtPointer closure)1025 XtAppAddInput(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 
1086 void
XtRemoveInput(register XtInputId id)1087 XtRemoveInput(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 
1155 void
_XtRemoveAllInputs(XtAppContext app)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 
1175 static void
DoOtherSources(XtAppContext app)1176 DoOtherSources(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 
1232 static Boolean
CallWorkProc(XtAppContext app)1233 CallWorkProc(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 
1263 void
XtNextEvent(XEvent * event)1264 XtNextEvent(XEvent *event)
1265 {
1266     XtAppNextEvent(_XtDefaultAppContext(), event);
1267 }
1268 
1269 void
_XtRefreshMapping(XEvent * event,_XtBoolean dispatch)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 
1289 void
XtAppNextEvent(XtAppContext app,XEvent * event)1290 XtAppNextEvent(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 
1334 void
XtProcessEvent(XtInputMask mask)1335 XtProcessEvent(XtInputMask mask)
1336 {
1337     XtAppProcessEvent(_XtDefaultAppContext(), mask);
1338 }
1339 
1340 void
XtAppProcessEvent(XtAppContext app,XtInputMask mask)1341 XtAppProcessEvent(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 
1446 Boolean
XtPending(void)1447 XtPending(void)
1448 {
1449     return (XtAppPending(_XtDefaultAppContext()) != 0);
1450 }
1451 
1452 XtInputMask
XtAppPending(XtAppContext app)1453 XtAppPending(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 
1520 static Boolean
PeekOtherSources(XtAppContext app)1521 PeekOtherSources(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 
1557 Boolean
XtPeekEvent(XEvent * event)1558 XtPeekEvent(XEvent *event)
1559 {
1560     return XtAppPeekEvent(_XtDefaultAppContext(), event);
1561 }
1562 
1563 Boolean XtAppPeekEvent_SkipTimer;
1564 
1565 Boolean
XtAppPeekEvent(XtAppContext app,XEvent * event)1566 XtAppPeekEvent(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