NextEvent.c revision d8f07471
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#endif
583
584WaitLoop:
585    app->rebuild_fdlist = TRUE;
586
587    while (1) {
588	AdjustTimes (app, block, howlong, ignoreTimers, &wt);
589
590	if (block && app->block_hook_list) {
591	    BlockHook hook;
592	    for (hook = app->block_hook_list;
593		 hook != NULL;
594		 hook = hook->next)
595		(*hook->proc) (hook->closure);
596
597	    if (!ignoreEvents)
598		/* see if the hook(s) generated any protocol */
599		for (dd = 0; dd < app->count; dd++)
600		    if (XEventsQueued(app->list[dd], QueuedAlready)) {
601#ifdef USE_POLL
602			XtStackFree ((XtPointer) wf.fdlist, fdlist);
603#endif
604			return dd;
605		    }
606	}
607
608	if (app->rebuild_fdlist)
609	    InitFds (app, ignoreEvents, ignoreInputs, &wf);
610
611#ifdef XTHREADS /* { */
612	if (drop_lock) {
613	    YIELD_APP_LOCK(app, &push_thread, &pushed_thread, &level);
614	    nfds = IoWait (&wt, &wf);
615	    RESTORE_APP_LOCK(app, level, &pushed_thread);
616	} else
617#endif /* } */
618	nfds = IoWait (&wt, &wf);
619	if (nfds == -1) {
620	    /*
621	     *  interrupt occured recalculate time value and wait again.
622	     */
623	    if (errno == EINTR || errno == EAGAIN) {
624		if (errno == EAGAIN) {
625		    errno = 0;  /* errno is not self reseting */
626		    continue;
627		}
628	        errno = 0;  /* errno is not self reseting */
629
630		/* was it interrupted by a signal that we care about? */
631		if (!ignoreSignals && app->signalQueue != NULL) {
632		    SignalEventRec *se_ptr = app->signalQueue;
633		    while (se_ptr != NULL) {
634			if (se_ptr->se_notice) {
635			    if (block && howlong != NULL)
636				AdjustHowLong (howlong, &wt.start_time);
637#ifdef USE_POLL
638			    XtStackFree ((XtPointer) wf.fdlist, fdlist);
639#endif
640			    return -1;
641			}
642			se_ptr = se_ptr->se_next;
643		    }
644		}
645
646		if (!ignoreEvents)
647		    /* get Xlib to detect a bad connection */
648		    for (dd = 0; dd < app->count; dd++)
649			if (XEventsQueued(app->list[dd], QueuedAfterReading)) {
650#ifdef USE_POLL
651			    XtStackFree ((XtPointer) wf.fdlist, fdlist);
652#endif
653			    return dd;
654			}
655
656		if (block) {
657#ifndef USE_POLL
658		    if (wt.wait_time_ptr == NULL)
659#else
660		    if (wt.poll_wait == X_BLOCK)
661#endif
662			continue;
663		    X_GETTIMEOFDAY (&wt.new_time);
664		    FIXUP_TIMEVAL (wt.new_time);
665		    TIMEDELTA (wt.time_spent, wt.new_time, wt.cur_time);
666		    wt.cur_time = wt.new_time;
667#ifndef USE_POLL
668		    if (IS_AFTER (wt.time_spent, *wt.wait_time_ptr)) {
669			TIMEDELTA (wt.wait_time, *wt.wait_time_ptr, wt.time_spent);
670			wt.wait_time_ptr = &wt.wait_time;
671			continue;
672		    } else
673#else
674		    if ((wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000) < wt.poll_wait) {
675			wt.poll_wait -= (wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000);
676			continue;
677		    } else
678#endif
679			nfds = 0;
680		}
681	    } else {
682		char Errno[12];
683		String param = Errno;
684		Cardinal param_count = 1;
685
686		sprintf( Errno, "%d", errno);
687		XtAppWarningMsg(app, "communicationError","select",
688			XtCXtToolkitError,"Select failed; error code %s",
689			&param, &param_count);
690		continue;
691	    }
692	} /* timed out or input available */
693	break;
694    }
695
696    if (nfds == 0) {
697	/* Timed out */
698	if (howlong)
699	    *howlong = (unsigned long)0;
700#ifdef USE_POLL
701	XtStackFree ((XtPointer) wf.fdlist, fdlist);
702#endif
703	return -1;
704    }
705
706    if (block && howlong != NULL)
707	AdjustHowLong (howlong, &wt.start_time);
708
709    if (ignoreInputs && ignoreEvents) {
710#ifdef USE_POLL
711	XtStackFree ((XtPointer) wf.fdlist, fdlist);
712#endif
713	return -1;
714    } else
715	FindInputs (app, &wf, nfds,
716		    ignoreEvents, ignoreInputs,
717		    &dpy_no, &found_input);
718
719    if (dpy_no >= 0 || found_input) {
720#ifdef USE_POLL
721	XtStackFree ((XtPointer) wf.fdlist, fdlist);
722#endif
723	return dpy_no;
724    }
725    goto WaitLoop;
726}
727
728#define IeCallProc(ptr) \
729    (*ptr->ie_proc) (ptr->ie_closure, &ptr->ie_source, (XtInputId*)&ptr);
730
731#define TeCallProc(ptr) \
732    (*ptr->te_proc) (ptr->te_closure, (XtIntervalId*)&ptr);
733
734#define SeCallProc(ptr) \
735    (*ptr->se_proc) (ptr->se_closure, (XtSignalId*)&ptr);
736
737/*
738 * Public Routines
739 */
740
741XtIntervalId XtAddTimeOut(
742	unsigned long interval,
743	XtTimerCallbackProc proc,
744	XtPointer closure)
745{
746	return XtAppAddTimeOut(_XtDefaultAppContext(),
747		interval, proc, closure);
748}
749
750static void QueueTimerEvent(
751    XtAppContext app,
752    TimerEventRec *ptr)
753{
754        TimerEventRec *t,**tt;
755        tt = &app->timerQueue;
756        t  = *tt;
757        while (t != NULL &&
758                IS_AFTER(t->te_timer_value, ptr->te_timer_value)) {
759          tt = &t->te_next;
760          t  = *tt;
761         }
762         ptr->te_next = t;
763         *tt = ptr;
764}
765
766XtIntervalId XtAppAddTimeOut(
767	XtAppContext app,
768	unsigned long interval,
769	XtTimerCallbackProc proc,
770	XtPointer closure)
771{
772	TimerEventRec *tptr;
773	struct timeval current_time;
774
775	LOCK_APP(app);
776	LOCK_PROCESS;
777	if (freeTimerRecs) {
778	    tptr = freeTimerRecs;
779	    freeTimerRecs = tptr->te_next;
780	}
781	else tptr = XtNew(TimerEventRec);
782	UNLOCK_PROCESS;
783
784	tptr->te_next = NULL;
785	tptr->te_closure = closure;
786	tptr->te_proc = proc;
787	tptr->app = app;
788	tptr->te_timer_value.tv_sec = interval/1000;
789	tptr->te_timer_value.tv_usec = (interval%1000)*1000;
790        X_GETTIMEOFDAY (&current_time);
791	FIXUP_TIMEVAL(current_time);
792        ADD_TIME(tptr->te_timer_value,tptr->te_timer_value,current_time);
793	QueueTimerEvent(app, tptr);
794	UNLOCK_APP(app);
795	return( (XtIntervalId) tptr);
796}
797
798void  XtRemoveTimeOut(
799	XtIntervalId id)
800{
801	TimerEventRec *t, *last, *tid = (TimerEventRec *) id;
802	XtAppContext app = tid->app;
803
804	/* find it */
805	LOCK_APP(app);
806	for(t = app->timerQueue, last = NULL;
807	    t != NULL && t != tid;
808	    t = t->te_next) last = t;
809
810	if (t == NULL) {
811	    UNLOCK_APP(app);
812	    return; /* couldn't find it */
813	}
814	if(last == NULL) { /* first one on the list */
815	    app->timerQueue = t->te_next;
816	} else last->te_next = t->te_next;
817
818	LOCK_PROCESS;
819	t->te_next = freeTimerRecs;
820	freeTimerRecs = t;
821	UNLOCK_PROCESS;
822	UNLOCK_APP(app);
823}
824
825XtWorkProcId XtAddWorkProc(
826	XtWorkProc proc,
827	XtPointer closure)
828{
829	return XtAppAddWorkProc(_XtDefaultAppContext(), proc, closure);
830}
831
832XtWorkProcId XtAppAddWorkProc(
833	XtAppContext app,
834	XtWorkProc proc,
835	XtPointer closure)
836{
837	WorkProcRec *wptr;
838
839	LOCK_APP(app);
840	LOCK_PROCESS;
841	if (freeWorkRecs) {
842	    wptr = freeWorkRecs;
843	    freeWorkRecs = wptr->next;
844	} else wptr = XtNew(WorkProcRec);
845	UNLOCK_PROCESS;
846	wptr->next = app->workQueue;
847	wptr->closure = closure;
848	wptr->proc = proc;
849	wptr->app = app;
850	app->workQueue = wptr;
851	UNLOCK_APP(app);
852	return (XtWorkProcId) wptr;
853}
854
855void  XtRemoveWorkProc(
856	XtWorkProcId id)
857{
858	WorkProcRec *wid= (WorkProcRec *) id, *w, *last;
859	XtAppContext app = wid->app;
860
861	LOCK_APP(app);
862	/* find it */
863	for(w = app->workQueue, last = NULL;
864	    w != NULL && w != wid; w = w->next) last = w;
865
866	if (w == NULL) {
867	    UNLOCK_APP(app);
868	    return; /* couldn't find it */
869	}
870
871	if(last == NULL) app->workQueue = w->next;
872	else last->next = w->next;
873	LOCK_PROCESS;
874	w->next = freeWorkRecs;
875	freeWorkRecs = w;
876	UNLOCK_PROCESS;
877	UNLOCK_APP(app);
878}
879
880XtSignalId XtAddSignal(
881	XtSignalCallbackProc proc,
882	XtPointer closure)
883{
884	return XtAppAddSignal(_XtDefaultAppContext(), proc, closure);
885}
886
887XtSignalId XtAppAddSignal(
888	XtAppContext app,
889	XtSignalCallbackProc proc,
890	XtPointer closure)
891{
892	SignalEventRec *sptr;
893
894	LOCK_APP(app);
895	LOCK_PROCESS;
896	if (freeSignalRecs) {
897	    sptr = freeSignalRecs;
898	    freeSignalRecs = sptr->se_next;
899	} else
900	    sptr = XtNew(SignalEventRec);
901	UNLOCK_PROCESS;
902	sptr->se_next = app->signalQueue;
903	sptr->se_closure = closure;
904	sptr->se_proc = proc;
905	sptr->app = app;
906	sptr->se_notice = FALSE;
907	app->signalQueue = sptr;
908	UNLOCK_APP(app);
909	return (XtSignalId) sptr;
910}
911
912void XtRemoveSignal(
913	XtSignalId id)
914{
915	SignalEventRec *sid = (SignalEventRec*) id, *s, *last = NULL;
916	XtAppContext app = sid->app;
917
918	LOCK_APP(app);
919	for (s = app->signalQueue; s != NULL && s != sid; s = s->se_next)
920	    last = s;
921	if (s == NULL) {
922	    UNLOCK_APP(app);
923	    return;
924	}
925	if (last == NULL)
926	    app->signalQueue = s->se_next;
927	else
928	    last->se_next = s->se_next;
929	LOCK_PROCESS;
930	s->se_next = freeSignalRecs;
931	freeSignalRecs = s;
932	UNLOCK_PROCESS;
933	UNLOCK_APP(app);
934}
935
936void XtNoticeSignal(
937	XtSignalId id)
938{
939	/*
940	 * It would be overkill to lock the app to set this flag.
941	 * In the worst case, 2..n threads would be modifying this
942	 * flag. The last one wins. Since signals occur asynchronously
943	 * anyway, this can occur with or without threads.
944	 *
945	 * The other issue is that thread t1 sets the flag in a
946	 * signalrec that has been deleted in thread t2. We rely
947	 * on a detail of the implementation, i.e. free'd signalrecs
948	 * aren't really free'd, they're just moved to a list of
949	 * free recs, so deref'ing one won't hurt anything.
950	 *
951	 * Lastly, and perhaps most importantly, since POSIX threads
952	 * says that the handling of asynchronous signals in a synchronous
953	 * threads environment is undefined. Therefor it would be an
954	 * error for both signals and threads to be in use in the same
955	 * program.
956	 */
957	SignalEventRec *sid = (SignalEventRec*) id;
958	sid->se_notice = TRUE;
959}
960
961XtInputId XtAddInput(
962	int source,
963	XtPointer Condition,
964	XtInputCallbackProc proc,
965	XtPointer closure)
966{
967	return XtAppAddInput(_XtDefaultAppContext(),
968		source, Condition, proc, closure);
969}
970
971XtInputId XtAppAddInput(
972	XtAppContext app,
973	int source,
974	XtPointer Condition,
975	XtInputCallbackProc proc,
976	XtPointer closure)
977{
978	InputEvent* sptr;
979	XtInputMask condition = (XtInputMask) Condition;
980
981	LOCK_APP(app);
982	if (!condition ||
983	    condition & ~(XtInputReadMask|XtInputWriteMask|XtInputExceptMask))
984	    XtAppErrorMsg(app,"invalidParameter","xtAddInput",XtCXtToolkitError,
985			  "invalid condition passed to XtAppAddInput",
986			  (String *)NULL, (Cardinal *)NULL);
987
988	if (app->input_max <= source) {
989	    Cardinal n = source + 1;
990	    int ii;
991	    app->input_list = (InputEvent**)XtRealloc((char*) app->input_list,
992						      n * sizeof(InputEvent*));
993	    for (ii = app->input_max; ii < (int) n; ii++)
994		app->input_list[ii] = (InputEvent*) NULL;
995	    app->input_max = n;
996	}
997	sptr = XtNew(InputEvent);
998	sptr->ie_proc = proc;
999	sptr->ie_closure = closure;
1000	sptr->app = app;
1001	sptr->ie_oq = NULL;
1002	sptr->ie_source = source;
1003	sptr->ie_condition = condition;
1004	sptr->ie_next = app->input_list[source];
1005	app->input_list[source] = sptr;
1006
1007#ifndef USE_POLL
1008	if (condition & XtInputReadMask)   FD_SET(source, &app->fds.rmask);
1009	if (condition & XtInputWriteMask)  FD_SET(source, &app->fds.wmask);
1010	if (condition & XtInputExceptMask) FD_SET(source, &app->fds.emask);
1011
1012	if (app->fds.nfds < (source+1)) app->fds.nfds = source+1;
1013#else
1014	if (sptr->ie_next == NULL)
1015	    app->fds.nfds++;
1016#endif
1017	app->input_count++;
1018	app->rebuild_fdlist = TRUE;
1019	UNLOCK_APP(app);
1020	return((XtInputId)sptr);
1021}
1022
1023void XtRemoveInput(
1024	register XtInputId  id)
1025{
1026  	register InputEvent *sptr, *lptr;
1027	XtAppContext app = ((InputEvent *)id)->app;
1028	register int source = ((InputEvent *)id)->ie_source;
1029	Boolean found = False;
1030
1031	LOCK_APP(app);
1032	sptr = app->outstandingQueue;
1033	lptr = NULL;
1034	for (; sptr != NULL; sptr = sptr->ie_oq) {
1035	    if (sptr == (InputEvent *)id) {
1036		if (lptr == NULL) app->outstandingQueue = sptr->ie_oq;
1037		else lptr->ie_oq = sptr->ie_oq;
1038	    }
1039	    lptr = sptr;
1040	}
1041
1042	if(app->input_list && (sptr = app->input_list[source]) != NULL) {
1043		for( lptr = NULL ; sptr; sptr = sptr->ie_next ){
1044			if(sptr == (InputEvent *) id) {
1045#ifndef USE_POLL
1046				XtInputMask condition = 0;
1047#endif
1048				if(lptr == NULL) {
1049				    app->input_list[source] = sptr->ie_next;
1050				} else {
1051				    lptr->ie_next = sptr->ie_next;
1052				}
1053#ifndef USE_POLL
1054				for (lptr = app->input_list[source];
1055				     lptr; lptr = lptr->ie_next)
1056				    condition |= lptr->ie_condition;
1057				if ((sptr->ie_condition & XtInputReadMask) &&
1058				    !(condition & XtInputReadMask))
1059				   FD_CLR(source, &app->fds.rmask);
1060				if ((sptr->ie_condition & XtInputWriteMask) &&
1061				    !(condition & XtInputWriteMask))
1062				   FD_CLR(source, &app->fds.wmask);
1063				if ((sptr->ie_condition & XtInputExceptMask) &&
1064				    !(condition & XtInputExceptMask))
1065				   FD_CLR(source, &app->fds.emask);
1066#endif
1067				XtFree((char *) sptr);
1068				found = True;
1069				break;
1070			}
1071			lptr = sptr;
1072		}
1073	}
1074
1075	if (found) {
1076	    app->input_count--;
1077#ifdef USE_POLL
1078	    if (app->input_list[source] == NULL)
1079		app->fds.nfds--;
1080#endif
1081	    app->rebuild_fdlist = TRUE;
1082	} else
1083	    XtAppWarningMsg(app, "invalidProcedure","inputHandler",
1084			    XtCXtToolkitError,
1085			    "XtRemoveInput: Input handler not found",
1086			    (String *)NULL, (Cardinal *)NULL);
1087	UNLOCK_APP(app);
1088}
1089
1090void _XtRemoveAllInputs(
1091    XtAppContext app)
1092{
1093    int i;
1094    for (i = 0; i < app->input_max; i++) {
1095	InputEvent* ep = app->input_list[i];
1096	while (ep) {
1097	    InputEvent *next = ep->ie_next;
1098	    XtFree( (char*)ep );
1099	    ep = next;
1100	}
1101    }
1102    XtFree((char *) app->input_list);
1103}
1104
1105/* Do alternate input and timer callbacks if there are any */
1106
1107static void DoOtherSources(
1108	XtAppContext app)
1109{
1110	TimerEventRec *te_ptr;
1111	InputEvent *ie_ptr;
1112	struct timeval  cur_time;
1113
1114#define DrainQueue() \
1115	for (ie_ptr = app->outstandingQueue; ie_ptr != NULL;) { \
1116	    app->outstandingQueue = ie_ptr->ie_oq;		\
1117	    ie_ptr ->ie_oq = NULL;				\
1118	    IeCallProc(ie_ptr);					\
1119	    ie_ptr = app->outstandingQueue;			\
1120	}
1121/*enddef*/
1122	DrainQueue();
1123	if (app->input_count > 0) {
1124	    /* Call _XtWaitForSomething to get input queued up */
1125	    (void) _XtWaitForSomething (app,
1126					TRUE, TRUE, FALSE, TRUE,
1127					FALSE,
1128#ifdef XTHREADS
1129					TRUE,
1130#endif
1131					(unsigned long *)NULL);
1132	    DrainQueue();
1133	}
1134	if (app->timerQueue != NULL) {	/* check timeout queue */
1135	    X_GETTIMEOFDAY (&cur_time);
1136	    FIXUP_TIMEVAL(cur_time);
1137	    while(IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time)) {
1138		te_ptr = app->timerQueue;
1139		app->timerQueue = te_ptr->te_next;
1140		te_ptr->te_next = NULL;
1141		if (te_ptr->te_proc != NULL)
1142		    TeCallProc(te_ptr);
1143		LOCK_PROCESS;
1144		te_ptr->te_next = freeTimerRecs;
1145		freeTimerRecs = te_ptr;
1146		UNLOCK_PROCESS;
1147		if (app->timerQueue == NULL) break;
1148	    }
1149	}
1150	if (app->signalQueue != NULL) {
1151	    SignalEventRec *se_ptr = app->signalQueue;
1152	    while (se_ptr != NULL) {
1153		if (se_ptr->se_notice) {
1154		    se_ptr->se_notice = FALSE;
1155		    if (se_ptr->se_proc != NULL)
1156			SeCallProc(se_ptr);
1157		}
1158		se_ptr = se_ptr->se_next;
1159	    }
1160	}
1161#undef DrainQueue
1162}
1163
1164/* If there are any work procs, call them.  Return whether we did so */
1165
1166static Boolean CallWorkProc(
1167	XtAppContext app)
1168{
1169	register WorkProcRec *w = app->workQueue;
1170	Boolean delete;
1171
1172	if (w == NULL) return FALSE;
1173
1174	app->workQueue = w->next;
1175
1176	delete = (*(w->proc)) (w->closure);
1177
1178	if (delete) {
1179	    LOCK_PROCESS;
1180	    w->next = freeWorkRecs;
1181	    freeWorkRecs = w;
1182	    UNLOCK_PROCESS;
1183	}
1184	else {
1185	    w->next = app->workQueue;
1186	    app->workQueue = w;
1187	}
1188	return TRUE;
1189}
1190
1191/*
1192 * XtNextEvent()
1193 * return next event;
1194 */
1195
1196void XtNextEvent(
1197	XEvent *event)
1198{
1199	XtAppNextEvent(_XtDefaultAppContext(), event);
1200}
1201
1202void _XtRefreshMapping(
1203    XEvent* event,
1204    _XtBoolean dispatch)
1205{
1206    XtPerDisplay pd;
1207
1208    LOCK_PROCESS;
1209    pd = _XtGetPerDisplay(event->xmapping.display);
1210    if (event->xmapping.request != MappingPointer &&
1211	pd && pd->keysyms && (event->xmapping.serial >= pd->keysyms_serial))
1212	_XtBuildKeysymTables( event->xmapping.display, pd );
1213    XRefreshKeyboardMapping(&event->xmapping);
1214    if (dispatch && pd && pd->mapping_callbacks)
1215	XtCallCallbackList((Widget) NULL,
1216			   (XtCallbackList)pd->mapping_callbacks,
1217			   (XtPointer)event );
1218    UNLOCK_PROCESS;
1219}
1220
1221void XtAppNextEvent(
1222	XtAppContext app,
1223	XEvent *event)
1224{
1225    int i, d;
1226
1227    LOCK_APP(app);
1228    for (;;) {
1229	if (app->count == 0)
1230	    DoOtherSources(app);
1231	else {
1232	    for (i = 1; i <= app->count; i++) {
1233		d = (i + app->last) % app->count;
1234		if (d == 0) DoOtherSources(app);
1235		if (XEventsQueued(app->list[d], QueuedAfterReading))
1236		    goto GotEvent;
1237	    }
1238	    for (i = 1; i <= app->count; i++) {
1239		d = (i + app->last) % app->count;
1240		if (XEventsQueued(app->list[d], QueuedAfterFlush))
1241		    goto GotEvent;
1242	    }
1243	}
1244
1245	/* We're ready to wait...if there is a work proc, call it */
1246	if (CallWorkProc(app)) continue;
1247
1248	d = _XtWaitForSomething (app,
1249				 FALSE, FALSE, FALSE, FALSE,
1250				 TRUE,
1251#ifdef XTHREADS
1252				 TRUE,
1253#endif
1254				 (unsigned long *) NULL);
1255
1256	if (d != -1) {
1257	  GotEvent:
1258	    XNextEvent (app->list[d], event);
1259#ifdef XTHREADS
1260	    /* assert(app->list[d] == event->xany.display); */
1261#endif
1262	    app->last = d;
1263	    if (event->xany.type == MappingNotify)
1264		_XtRefreshMapping(event, False);
1265	    UNLOCK_APP(app);
1266	    return;
1267	}
1268
1269    } /* for */
1270}
1271
1272void XtProcessEvent(
1273	XtInputMask mask)
1274{
1275	XtAppProcessEvent(_XtDefaultAppContext(), mask);
1276}
1277
1278void XtAppProcessEvent(
1279	XtAppContext app,
1280	XtInputMask mask)
1281{
1282	int i, d;
1283	XEvent event;
1284	struct timeval cur_time;
1285
1286	LOCK_APP(app);
1287	if (mask == 0) {
1288	    UNLOCK_APP(app);
1289	    return;
1290	}
1291
1292	for (;;) {
1293
1294	    if (mask & XtIMSignal && app->signalQueue != NULL) {
1295		SignalEventRec *se_ptr = app->signalQueue;
1296		while (se_ptr != NULL) {
1297		    if (se_ptr->se_notice) {
1298			se_ptr->se_notice = FALSE;
1299			SeCallProc(se_ptr);
1300			UNLOCK_APP(app);
1301			return;
1302		    }
1303		    se_ptr = se_ptr->se_next;
1304		}
1305	    }
1306
1307	    if (mask & XtIMTimer && app->timerQueue != NULL) {
1308		X_GETTIMEOFDAY (&cur_time);
1309		FIXUP_TIMEVAL(cur_time);
1310		if (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)){
1311		    TimerEventRec *te_ptr = app->timerQueue;
1312		    app->timerQueue = app->timerQueue->te_next;
1313		    te_ptr->te_next = NULL;
1314                    if (te_ptr->te_proc != NULL)
1315		        TeCallProc(te_ptr);
1316		    LOCK_PROCESS;
1317		    te_ptr->te_next = freeTimerRecs;
1318		    freeTimerRecs = te_ptr;
1319		    UNLOCK_PROCESS;
1320		    UNLOCK_APP(app);
1321		    return;
1322		}
1323	    }
1324
1325	    if (mask & XtIMAlternateInput) {
1326		if (app->input_count > 0 && app->outstandingQueue == NULL) {
1327		    /* Call _XtWaitForSomething to get input queued up */
1328		    (void) _XtWaitForSomething (app,
1329						TRUE, TRUE, FALSE, TRUE,
1330						FALSE,
1331#ifdef XTHREADS
1332						TRUE,
1333#endif
1334						(unsigned long *)NULL);
1335		}
1336		if (app->outstandingQueue != NULL) {
1337		    InputEvent *ie_ptr = app->outstandingQueue;
1338		    app->outstandingQueue = ie_ptr->ie_oq;
1339		    ie_ptr->ie_oq = NULL;
1340		    IeCallProc(ie_ptr);
1341		    UNLOCK_APP(app);
1342		    return;
1343		}
1344	    }
1345
1346	    if (mask & XtIMXEvent) {
1347		for (i = 1; i <= app->count; i++) {
1348		    d = (i + app->last) % app->count;
1349		    if (XEventsQueued(app->list[d], QueuedAfterReading))
1350			goto GotEvent;
1351		}
1352		for (i = 1; i <= app->count; i++) {
1353		    d = (i + app->last) % app->count;
1354		    if (XEventsQueued(app->list[d], QueuedAfterFlush))
1355			goto GotEvent;
1356		}
1357	    }
1358
1359	    /* Nothing to do...wait for something */
1360
1361	    if (CallWorkProc(app)) continue;
1362
1363	    d = _XtWaitForSomething (app,
1364				    (mask & XtIMXEvent ? FALSE : TRUE),
1365				    (mask & XtIMTimer ? FALSE : TRUE),
1366				    (mask & XtIMAlternateInput ? FALSE : TRUE),
1367				    (mask & XtIMSignal ? FALSE : TRUE),
1368				    TRUE,
1369#ifdef XTHREADS
1370				    TRUE,
1371#endif
1372				    (unsigned long *) NULL);
1373
1374	    if (mask & XtIMXEvent && d != -1) {
1375	      GotEvent:
1376		XNextEvent(app->list[d], &event);
1377#ifdef XTHREADS
1378		/* assert(app->list[d] == event.xany.display); */
1379#endif
1380		app->last = d;
1381		if (event.xany.type == MappingNotify) {
1382		    _XtRefreshMapping(&event, False);
1383		}
1384		XtDispatchEvent(&event);
1385		UNLOCK_APP(app);
1386		return;
1387	    }
1388
1389	}
1390}
1391
1392Boolean XtPending(void)
1393{
1394	return (XtAppPending(_XtDefaultAppContext()) != 0);
1395}
1396
1397XtInputMask XtAppPending(
1398	XtAppContext app)
1399{
1400	struct timeval cur_time;
1401	int d;
1402	XtInputMask ret = 0;
1403
1404/*
1405 * Check for pending X events
1406 */
1407	LOCK_APP(app);
1408	for (d = 0; d < app->count; d++) {
1409	    if (XEventsQueued(app->list[d], QueuedAfterReading)) {
1410		ret = XtIMXEvent;
1411		break;
1412	    }
1413	}
1414	if (ret == 0) {
1415	    for (d = 0; d < app->count; d++) {
1416		if (XEventsQueued(app->list[d], QueuedAfterFlush)) {
1417		    ret = XtIMXEvent;
1418		    break;
1419		}
1420	    }
1421	}
1422
1423	if (app->signalQueue != NULL) {
1424	    SignalEventRec *se_ptr = app->signalQueue;
1425	    while (se_ptr != NULL) {
1426		if (se_ptr->se_notice) {
1427		    ret |= XtIMSignal;
1428		    break;
1429		}
1430		se_ptr = se_ptr->se_next;
1431	    }
1432	}
1433
1434/*
1435 * Check for pending alternate input
1436 */
1437	if (app->timerQueue != NULL) {	/* check timeout queue */
1438	    X_GETTIMEOFDAY (&cur_time);
1439	    FIXUP_TIMEVAL(cur_time);
1440	    if ((IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time))  &&
1441                (app->timerQueue->te_proc != 0)) {
1442		ret |= XtIMTimer;
1443	    }
1444	}
1445
1446	if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput;
1447	else {
1448	    /* This won't cause a wait, but will enqueue any input */
1449
1450	    if(_XtWaitForSomething (app,
1451				    FALSE, TRUE, FALSE, TRUE,
1452				    FALSE,
1453#ifdef XTHREADS
1454				    TRUE,
1455#endif
1456				    (unsigned long *) NULL) != -1)
1457		ret |= XtIMXEvent;
1458	    if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput;
1459	}
1460	UNLOCK_APP(app);
1461	return ret;
1462}
1463
1464/* Peek at alternate input and timer callbacks if there are any */
1465
1466static Boolean PeekOtherSources(
1467	XtAppContext app)
1468{
1469	struct timeval  cur_time;
1470
1471	if (app->outstandingQueue != NULL) return TRUE;
1472
1473	if (app->signalQueue != NULL) {
1474	    SignalEventRec *se_ptr = app->signalQueue;
1475	    while (se_ptr != NULL) {
1476		if (se_ptr->se_notice)
1477		    return TRUE;
1478		se_ptr = se_ptr->se_next;
1479	    }
1480	}
1481
1482	if (app->input_count > 0) {
1483	    /* Call _XtWaitForSomething to get input queued up */
1484	    (void) _XtWaitForSomething (app,
1485					TRUE, TRUE, FALSE, TRUE,
1486					FALSE,
1487#ifdef XTHREADS
1488					TRUE,
1489#endif
1490					(unsigned long *)NULL);
1491	    if (app->outstandingQueue != NULL) return TRUE;
1492	}
1493
1494	if (app->timerQueue != NULL) {	/* check timeout queue */
1495	    X_GETTIMEOFDAY (&cur_time);
1496	    FIXUP_TIMEVAL(cur_time);
1497	    if (IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time))
1498		return TRUE;
1499	}
1500
1501	return FALSE;
1502}
1503
1504Boolean XtPeekEvent(
1505	XEvent *event)
1506{
1507	return XtAppPeekEvent(_XtDefaultAppContext(), event);
1508}
1509
1510Boolean XtAppPeekEvent_SkipTimer;
1511
1512Boolean XtAppPeekEvent(
1513	XtAppContext app,
1514	XEvent *event)
1515{
1516	int i, d;
1517	Boolean foundCall = FALSE;
1518
1519	LOCK_APP(app);
1520	for (i = 1; i <= app->count; i++) {
1521	    d = (i + app->last) % app->count;
1522	    if (d == 0) foundCall = PeekOtherSources(app);
1523	    if (XEventsQueued(app->list[d], QueuedAfterReading))
1524		goto GotEvent;
1525	}
1526	for (i = 1; i <= app->count; i++) {
1527	    d = (i + app->last) % app->count;
1528	    if (XEventsQueued(app->list[d], QueuedAfterFlush))
1529		goto GotEvent;
1530	}
1531
1532	if (foundCall) {
1533	    event->xany.type = 0;
1534	    event->xany.display = NULL;
1535	    event->xany.window = 0;
1536	    UNLOCK_APP(app);
1537	    return FALSE;
1538	}
1539
1540	while (1) {
1541		d = _XtWaitForSomething (app,
1542			FALSE, FALSE, FALSE, FALSE,
1543			TRUE,
1544#ifdef XTHREADS
1545			TRUE,
1546#endif
1547			(unsigned long *) NULL);
1548
1549		if (d != -1) {  /* event */
1550			GotEvent:
1551			XPeekEvent(app->list[d], event);
1552			app->last = (d == 0 ? app->count : d) - 1;
1553			UNLOCK_APP(app);
1554			return TRUE;
1555		}
1556		else {  /* input or timer or signal */
1557			/*
1558			 * Check to see why a -1 was returned, if a timer expired,
1559			 * call it and block some more
1560			 */
1561			if ((app->timerQueue != NULL) && ! XtAppPeekEvent_SkipTimer) {  /* timer */
1562				struct timeval cur_time;
1563				Bool did_timer = False;
1564
1565				X_GETTIMEOFDAY (&cur_time);
1566				FIXUP_TIMEVAL(cur_time);
1567				while (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) {
1568					TimerEventRec *te_ptr = app->timerQueue;
1569					app->timerQueue = app->timerQueue->te_next;
1570					te_ptr->te_next = NULL;
1571					if (te_ptr->te_proc != NULL) {
1572					    TeCallProc(te_ptr);
1573					    did_timer = True;
1574					}
1575					LOCK_PROCESS;
1576					te_ptr->te_next = freeTimerRecs;
1577					freeTimerRecs = te_ptr;
1578					UNLOCK_PROCESS;
1579					if (app->timerQueue == NULL) break;
1580				}
1581				if (did_timer)
1582				{
1583				    for (d = 0; d < app->count; d++)
1584				    /* the timer's procedure may have caused an event */
1585					    if (XEventsQueued(app->list[d], QueuedAfterFlush)) {
1586						    goto GotEvent;
1587					    }
1588				    continue;  /* keep blocking */
1589				}
1590			}
1591			/*
1592			 * spec is vague here; we'll assume signals also return FALSE,
1593			 * of course to determine whether a signal is pending requires
1594			 * walking the signalQueue looking for se_notice flags which
1595			 * this code doesn't do.
1596			 */
1597#if 0
1598			if (app->signalQueue != NULL) {  /* signal */
1599				event->xany.type = 0;
1600				event->xany.display = NULL;
1601				event->xany.window = 0;
1602				UNLOCK_APP(app);
1603				return FALSE;
1604			}
1605			else
1606#endif
1607			{  /* input */
1608				event->xany.type = 0;
1609				event->xany.display = NULL;
1610				event->xany.window = 0;
1611				UNLOCK_APP(app);
1612				return FALSE;
1613			}
1614		}
1615	} /* end while */
1616}
1617