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