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