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