mirror of
https://github.com/Stichting-MINIX-Research-Foundation/xsrc.git
synced 2025-09-10 21:28:49 -04:00
1614 lines
39 KiB
C
1614 lines
39 KiB
C
/* $Xorg: NextEvent.c,v 1.8 2001/02/09 02:03:55 xorgcvs Exp $ */
|
|
|
|
/***********************************************************
|
|
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
|
|
Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA.
|
|
|
|
All Rights Reserved
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
documentation for any purpose and without fee is hereby granted,
|
|
provided that the above copyright notice appear in all copies and that
|
|
both that copyright notice and this permission notice appear in
|
|
supporting documentation, and that the names of Digital or Sun not be
|
|
used in advertising or publicity pertaining to distribution of the
|
|
software without specific, written prior permission.
|
|
|
|
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
|
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
|
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
|
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
SOFTWARE.
|
|
|
|
SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
|
|
NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI-
|
|
ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
|
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
|
|
THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
******************************************************************/
|
|
|
|
/*
|
|
|
|
Copyright 1987, 1988, 1994, 1998, 2001 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from The Open Group.
|
|
|
|
*/
|
|
/* $XFree86: xc/lib/Xt/NextEvent.c,v 3.29 2004/05/05 00:07:03 dickey Exp $ */
|
|
|
|
#include "IntrinsicI.h"
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#ifdef __UNIXOS2__
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
static TimerEventRec* freeTimerRecs;
|
|
static WorkProcRec* freeWorkRecs;
|
|
static SignalEventRec* freeSignalRecs;
|
|
|
|
/* Some systems running NTP daemons are known to return strange usec
|
|
* values from gettimeofday.
|
|
*/
|
|
|
|
#ifndef NEEDS_NTPD_FIXUP
|
|
# if defined(sun) || defined(MOTOROLA) || (defined(__osf__) && defined(__alpha))
|
|
# define NEEDS_NTPD_FIXUP 1
|
|
# else
|
|
# define NEEDS_NTPD_FIXUP 0
|
|
# endif
|
|
#endif
|
|
|
|
#if NEEDS_NTPD_FIXUP
|
|
#define FIXUP_TIMEVAL(t) { \
|
|
while ((t).tv_usec >= 1000000) { \
|
|
(t).tv_usec -= 1000000; \
|
|
(t).tv_sec++; \
|
|
} \
|
|
while ((t).tv_usec < 0) { \
|
|
if ((t).tv_sec > 0) { \
|
|
(t).tv_usec += 1000000; \
|
|
(t).tv_sec--; \
|
|
} else { \
|
|
(t).tv_usec = 0; \
|
|
break; \
|
|
} \
|
|
}}
|
|
#else
|
|
#define FIXUP_TIMEVAL(t)
|
|
#endif /*NEEDS_NTPD_FIXUP*/
|
|
|
|
/*
|
|
* Private routines
|
|
*/
|
|
#define ADD_TIME(dest, src1, src2) { \
|
|
if(((dest).tv_usec = (src1).tv_usec + (src2).tv_usec) >= 1000000) {\
|
|
(dest).tv_usec -= 1000000;\
|
|
(dest).tv_sec = (src1).tv_sec + (src2).tv_sec + 1 ; \
|
|
} else { (dest).tv_sec = (src1).tv_sec + (src2).tv_sec ; \
|
|
if(((dest).tv_sec >= 1) && (((dest).tv_usec <0))) { \
|
|
(dest).tv_sec --;(dest).tv_usec += 1000000; } } }
|
|
|
|
|
|
#define TIMEDELTA(dest, src1, src2) { \
|
|
if(((dest).tv_usec = (src1).tv_usec - (src2).tv_usec) < 0) {\
|
|
(dest).tv_usec += 1000000;\
|
|
(dest).tv_sec = (src1).tv_sec - (src2).tv_sec - 1;\
|
|
} else (dest).tv_sec = (src1).tv_sec - (src2).tv_sec; }
|
|
|
|
#define IS_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \
|
|
|| (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec > (t1).tv_usec)))
|
|
|
|
#define IS_AT_OR_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \
|
|
|| (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec >= (t1).tv_usec)))
|
|
|
|
#ifdef USE_POLL
|
|
#ifndef XT_DEFAULT_FDLIST_SIZE
|
|
#define XT_DEFAULT_FDLIST_SIZE 32
|
|
#endif
|
|
#endif
|
|
|
|
static void AdjustHowLong (
|
|
unsigned long *howlong,
|
|
struct timeval *start_time)
|
|
{
|
|
struct timeval new_time, time_spent, lstart_time;
|
|
|
|
lstart_time = *start_time;
|
|
X_GETTIMEOFDAY (&new_time);
|
|
FIXUP_TIMEVAL(new_time);
|
|
TIMEDELTA(time_spent, new_time, lstart_time);
|
|
if(*howlong <= (unsigned long)(time_spent.tv_sec*1000+time_spent.tv_usec/1000))
|
|
*howlong = (unsigned long)0; /* Timed out */
|
|
else
|
|
*howlong -= (time_spent.tv_sec*1000+time_spent.tv_usec/1000);
|
|
}
|
|
|
|
typedef struct {
|
|
struct timeval cur_time;
|
|
struct timeval start_time;
|
|
struct timeval wait_time;
|
|
struct timeval new_time;
|
|
struct timeval time_spent;
|
|
struct timeval max_wait_time;
|
|
#ifndef USE_POLL
|
|
struct timeval *wait_time_ptr;
|
|
#else
|
|
int poll_wait;
|
|
#endif
|
|
} wait_times_t, *wait_times_ptr_t;
|
|
|
|
static struct timeval zero_time = { 0 , 0};
|
|
#ifndef USE_POLL
|
|
static fd_set zero_fd;
|
|
#else
|
|
#define X_BLOCK -1
|
|
#define X_DONT_BLOCK 0
|
|
#endif
|
|
|
|
static void InitTimes (
|
|
Boolean block,
|
|
unsigned long* howlong,
|
|
wait_times_ptr_t wt)
|
|
{
|
|
if (block) {
|
|
X_GETTIMEOFDAY (&wt->cur_time);
|
|
FIXUP_TIMEVAL(wt->cur_time);
|
|
wt->start_time = wt->cur_time;
|
|
if(howlong == NULL) { /* special case for ever */
|
|
#ifndef USE_POLL
|
|
wt->wait_time_ptr = NULL;
|
|
#else
|
|
wt->poll_wait = X_BLOCK;
|
|
#endif
|
|
} else { /* block until at most */
|
|
wt->max_wait_time.tv_sec = *howlong/1000;
|
|
wt->max_wait_time.tv_usec = (*howlong %1000)*1000;
|
|
#ifndef USE_POLL
|
|
wt->wait_time_ptr = &wt->max_wait_time;
|
|
#else
|
|
wt->poll_wait = *howlong;
|
|
#endif
|
|
}
|
|
} else { /* don't block */
|
|
wt->max_wait_time = zero_time;
|
|
#ifndef USE_POLL
|
|
wt->wait_time_ptr = &wt->max_wait_time;
|
|
#else
|
|
wt->poll_wait = X_DONT_BLOCK;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
#ifndef USE_POLL
|
|
fd_set rmask, wmask, emask;
|
|
int nfds;
|
|
#else
|
|
struct pollfd* fdlist;
|
|
struct pollfd* stack;
|
|
int fdlistlen, num_dpys;
|
|
#endif
|
|
} wait_fds_t, *wait_fds_ptr_t;
|
|
|
|
static void InitFds (
|
|
XtAppContext app,
|
|
Boolean ignoreEvents,
|
|
Boolean ignoreInputs,
|
|
wait_fds_ptr_t wf)
|
|
{
|
|
int ii;
|
|
app->rebuild_fdlist = FALSE;
|
|
#ifndef USE_POLL
|
|
wf->nfds = app->fds.nfds;
|
|
if( !ignoreInputs ) {
|
|
wf->rmask = app->fds.rmask;
|
|
wf->wmask = app->fds.wmask;
|
|
wf->emask = app->fds.emask;
|
|
} else
|
|
wf->rmask = wf->wmask = wf->emask = zero_fd;
|
|
|
|
if (!ignoreEvents)
|
|
for (ii = 0; ii < app->count; ii++) {
|
|
FD_SET (ConnectionNumber(app->list[ii]), &wf->rmask);
|
|
}
|
|
#else
|
|
#ifndef POLLRDNORM
|
|
#define POLLRDNORM 0
|
|
#endif
|
|
|
|
#ifndef POLLRDBAND
|
|
#define POLLRDBAND 0
|
|
#endif
|
|
|
|
#ifndef POLLWRNORM
|
|
#define POLLWRNORM 0
|
|
#endif
|
|
|
|
#ifndef POLLWRBAND
|
|
#define POLLWRBAND 0
|
|
#endif
|
|
|
|
#define XPOLL_READ (POLLIN|POLLRDNORM|POLLPRI|POLLRDBAND)
|
|
#define XPOLL_WRITE (POLLOUT|POLLWRNORM|POLLWRBAND)
|
|
#define XPOLL_EXCEPT 0
|
|
|
|
if (!ignoreEvents)
|
|
wf->fdlistlen = wf->num_dpys = app->count;
|
|
else
|
|
wf->fdlistlen = wf->num_dpys = 0;
|
|
|
|
if (!ignoreInputs && app->input_list != NULL) {
|
|
int ii;
|
|
for (ii = 0; ii < (int) app->input_max; ii++)
|
|
if (app->input_list[ii] != NULL)
|
|
wf->fdlistlen++;
|
|
}
|
|
|
|
if (!wf->fdlist || wf->fdlist == wf->stack) {
|
|
wf->fdlist = (struct pollfd*)
|
|
XtStackAlloc (sizeof (struct pollfd) * wf->fdlistlen, wf->stack);
|
|
} else {
|
|
wf->fdlist = (struct pollfd*)
|
|
XtRealloc ((char*) wf->fdlist,
|
|
sizeof (struct pollfd) * wf->fdlistlen);
|
|
}
|
|
|
|
if (wf->fdlistlen) {
|
|
struct pollfd* fdlp = wf->fdlist;
|
|
InputEvent* iep;
|
|
|
|
if (!ignoreEvents)
|
|
for (ii = 0 ; ii < wf->num_dpys; ii++, fdlp++) {
|
|
fdlp->fd = ConnectionNumber (app->list[ii]);
|
|
fdlp->events = POLLIN;
|
|
}
|
|
if (!ignoreInputs && app->input_list != NULL)
|
|
for (ii = 0; ii < app->input_max; ii++)
|
|
if (app->input_list[ii] != NULL) {
|
|
iep = app->input_list[ii];
|
|
fdlp->fd = ii;
|
|
fdlp->events = 0;
|
|
for ( ; iep; iep = iep->ie_next) {
|
|
if (iep->ie_condition & XtInputReadMask)
|
|
fdlp->events |= XPOLL_READ;
|
|
if (iep->ie_condition & XtInputWriteMask)
|
|
fdlp->events |= XPOLL_WRITE;
|
|
if (iep->ie_condition & XtInputExceptMask)
|
|
fdlp->events |= XPOLL_EXCEPT;
|
|
}
|
|
fdlp++;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void AdjustTimes (
|
|
XtAppContext app,
|
|
Boolean block,
|
|
unsigned long* howlong,
|
|
Boolean ignoreTimers,
|
|
wait_times_ptr_t wt)
|
|
{
|
|
if (app->timerQueue != NULL && !ignoreTimers && block) {
|
|
if (IS_AFTER (wt->cur_time, app->timerQueue->te_timer_value)) {
|
|
TIMEDELTA (wt->wait_time, app->timerQueue->te_timer_value, wt->cur_time);
|
|
if (howlong == NULL || IS_AFTER (wt->wait_time, wt->max_wait_time))
|
|
#ifndef USE_POLL
|
|
wt->wait_time_ptr = &wt->wait_time;
|
|
else
|
|
wt->wait_time_ptr = &wt->max_wait_time;
|
|
} else
|
|
wt->wait_time_ptr = &zero_time;
|
|
}
|
|
#else
|
|
wt->poll_wait = wt->wait_time.tv_sec * 1000 + wt->wait_time.tv_usec / 1000;
|
|
else
|
|
wt->poll_wait = wt->max_wait_time.tv_sec * 1000 + wt->max_wait_time.tv_usec / 1000;
|
|
} else
|
|
wt->poll_wait = X_DONT_BLOCK;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
static int IoWait (
|
|
wait_times_ptr_t wt,
|
|
wait_fds_ptr_t wf)
|
|
{
|
|
#ifndef USE_POLL
|
|
return Select (wf->nfds, &wf->rmask, &wf->wmask, &wf->emask,
|
|
wt->wait_time_ptr);
|
|
#else
|
|
return poll (wf->fdlist, wf->fdlistlen, wt->poll_wait);
|
|
#endif
|
|
}
|
|
|
|
|
|
static void FindInputs (
|
|
XtAppContext app,
|
|
wait_fds_ptr_t wf,
|
|
int nfds,
|
|
Boolean ignoreEvents,
|
|
Boolean ignoreInputs,
|
|
int* dpy_no,
|
|
int* found_input)
|
|
{
|
|
XtInputMask condition;
|
|
InputEvent *ep;
|
|
int ii;
|
|
#ifndef USE_POLL /* { check ready file descriptors block */
|
|
#ifdef XTHREADS
|
|
fd_set rmask;
|
|
#endif
|
|
int dd;
|
|
*dpy_no = -1;
|
|
*found_input = False;
|
|
|
|
#ifdef XTHREADS
|
|
rmask = app->fds.rmask;
|
|
for (dd = app->count; dd-- > 0; )
|
|
FD_SET (ConnectionNumber (app->list[dd]), &rmask);
|
|
#endif
|
|
|
|
for (ii = 0; ii < wf->nfds && nfds > 0; ii++) {
|
|
condition = 0;
|
|
if (FD_ISSET (ii, &wf->rmask)
|
|
#ifdef XTHREADS
|
|
&& FD_ISSET (ii, &rmask)
|
|
#endif
|
|
) {
|
|
nfds--;
|
|
if (!ignoreEvents) {
|
|
for (dd = 0; dd < app->count; dd++) {
|
|
if (ii == ConnectionNumber (app->list[dd])) {
|
|
if (*dpy_no == -1) {
|
|
if (XEventsQueued (app->list[dd], QueuedAfterReading ))
|
|
*dpy_no = dd;
|
|
/*
|
|
* An error event could have arrived
|
|
* without any real events, or events
|
|
* could have been swallowed by Xlib,
|
|
* or the connection may be broken.
|
|
* We can't tell the difference, so
|
|
* assume Xlib will eventually discover
|
|
* a broken connection.
|
|
*/
|
|
}
|
|
goto ENDILOOP;
|
|
}
|
|
}
|
|
}
|
|
condition = XtInputReadMask;
|
|
}
|
|
if (FD_ISSET (ii, &wf->wmask)
|
|
#ifdef XTHREADS
|
|
&& FD_ISSET (ii, &app->fds.wmask)
|
|
#endif
|
|
) {
|
|
condition |= XtInputWriteMask;
|
|
nfds--;
|
|
}
|
|
if (FD_ISSET (ii, &wf->emask)
|
|
#ifdef XTHREADS
|
|
&& FD_ISSET (ii, &app->fds.emask)
|
|
#endif
|
|
) {
|
|
condition |= XtInputExceptMask;
|
|
nfds--;
|
|
}
|
|
if (condition) {
|
|
for (ep = app->input_list[ii]; ep; ep = ep->ie_next)
|
|
if (condition & ep->ie_condition) {
|
|
/* make sure this input isn't already marked outstanding */
|
|
InputEvent *oq;
|
|
for (oq = app->outstandingQueue; oq; oq = oq->ie_oq)
|
|
if (oq == ep)
|
|
break;
|
|
if (!oq)
|
|
{
|
|
ep->ie_oq = app->outstandingQueue;
|
|
app->outstandingQueue = ep;
|
|
}
|
|
}
|
|
*found_input = True;
|
|
}
|
|
ENDILOOP: ;
|
|
} /* endfor */
|
|
#else /* }{ */
|
|
struct pollfd* fdlp;
|
|
|
|
*dpy_no = -1;
|
|
*found_input = False;
|
|
|
|
if (!ignoreEvents) {
|
|
fdlp = wf->fdlist;
|
|
for (ii = 0; ii < wf->num_dpys; ii++, fdlp++) {
|
|
if (*dpy_no == -1 && fdlp->revents & (POLLIN|POLLHUP|POLLERR) &&
|
|
#ifdef XTHREADS
|
|
!(fdlp->revents & POLLNVAL) &&
|
|
#endif
|
|
XEventsQueued (app->list[ii], QueuedAfterReading)) {
|
|
*dpy_no = ii;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ignoreInputs) {
|
|
fdlp = &wf->fdlist[wf->num_dpys];
|
|
for (ii = wf->num_dpys; ii < wf->fdlistlen; ii++, fdlp++) {
|
|
condition = 0;
|
|
if (fdlp->revents) {
|
|
if (fdlp->revents & (XPOLL_READ|POLLHUP|POLLERR)
|
|
#ifdef XTHREADS
|
|
&& !(fdlp->revents & POLLNVAL)
|
|
#endif
|
|
)
|
|
condition = XtInputReadMask;
|
|
if (fdlp->revents & XPOLL_WRITE)
|
|
condition |= XtInputWriteMask;
|
|
if (fdlp->revents & XPOLL_EXCEPT)
|
|
condition |= XtInputExceptMask;
|
|
}
|
|
if (condition) {
|
|
*found_input = True;
|
|
for (ep = app->input_list[fdlp->fd]; ep; ep = ep->ie_next)
|
|
if (condition & ep->ie_condition) {
|
|
InputEvent *oq;
|
|
/* make sure this input isn't already marked outstanding */
|
|
for (oq = app->outstandingQueue; oq; oq = oq->ie_oq)
|
|
if (oq == ep)
|
|
break;
|
|
if (!oq)
|
|
{
|
|
ep->ie_oq = app->outstandingQueue;
|
|
app->outstandingQueue = ep;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* } */
|
|
}
|
|
|
|
/*
|
|
* Routine to block in the toolkit. This should be the only call to select.
|
|
*
|
|
* This routine returns when there is something to be done.
|
|
*
|
|
* Before calling this with ignoreInputs==False, app->outstandingQueue should
|
|
* be checked; this routine will not verify that an alternate input source
|
|
* has not already been enqueued.
|
|
*
|
|
*
|
|
* _XtWaitForSomething( appContext,
|
|
* ignoreEvent, ignoreTimers, ignoreInputs, ignoreSignals,
|
|
* block, drop_lock, howlong)
|
|
* XtAppContext app; (Displays to check wait on)
|
|
*
|
|
* Boolean ignoreEvents; (Don't return if XEvents are available
|
|
* Also implies forget XEvents exist)
|
|
*
|
|
* Boolean ignoreTimers; (Ditto for timers)
|
|
*
|
|
* Boolean ignoreInputs; (Ditto for input callbacks )
|
|
*
|
|
* Boolean ignoreSignals; (Ditto for signals)
|
|
*
|
|
* Boolean block; (Okay to block)
|
|
*
|
|
* Boolean drop_lock (drop lock before going into select/poll)
|
|
*
|
|
* TimeVal howlong; (howlong to wait for if blocking and not
|
|
* doing Timers... Null means forever.
|
|
* Maybe should mean shortest of both)
|
|
* Returns display for which input is available, if any
|
|
* and if ignoreEvents==False, else returns -1
|
|
*
|
|
* if ignoring everything && block=True && howlong=NULL, you'll have
|
|
* lots of time for coffee; better not try it! In fact, it probably
|
|
* makes little sense to do this regardless of the value of howlong
|
|
* (bottom line is, we don't bother checking here).
|
|
*
|
|
* If drop_lock is FALSE, the app->lock->mutex is not unlocked before
|
|
* entering select/poll. It is illegal for drop_lock to be FALSE if
|
|
* ignoreTimers, ignoreInputs, or ignoreSignals is FALSE.
|
|
*/
|
|
int _XtWaitForSomething(
|
|
XtAppContext app,
|
|
_XtBoolean ignoreEvents,
|
|
_XtBoolean ignoreTimers,
|
|
_XtBoolean ignoreInputs,
|
|
_XtBoolean ignoreSignals,
|
|
_XtBoolean block,
|
|
#ifdef XTHREADS
|
|
_XtBoolean drop_lock,
|
|
#endif
|
|
unsigned long *howlong)
|
|
{
|
|
wait_times_t wt;
|
|
wait_fds_t wf;
|
|
int nfds, dpy_no, found_input, dd;
|
|
#ifdef XTHREADS
|
|
Boolean push_thread = TRUE;
|
|
Boolean pushed_thread = FALSE;
|
|
int level = 0;
|
|
#endif
|
|
#ifdef USE_POLL
|
|
struct pollfd fdlist[XT_DEFAULT_FDLIST_SIZE];
|
|
#endif
|
|
|
|
#ifdef XTHREADS
|
|
/* assert ((ignoreTimers && ignoreInputs && ignoreSignals) || drop_lock); */
|
|
/* If not multi-threaded, never drop lock */
|
|
if (app->lock == (ThreadAppProc) NULL)
|
|
drop_lock = FALSE;
|
|
#endif
|
|
|
|
InitTimes (block, howlong, &wt);
|
|
|
|
#ifdef USE_POLL
|
|
wf.fdlist = NULL;
|
|
wf.stack = fdlist;
|
|
#endif
|
|
|
|
app->rebuild_fdlist = TRUE;
|
|
|
|
while (1) {
|
|
WaitLoop:
|
|
AdjustTimes (app, block, howlong, ignoreTimers, &wt);
|
|
|
|
if (block && app->block_hook_list) {
|
|
BlockHook hook;
|
|
for (hook = app->block_hook_list;
|
|
hook != NULL;
|
|
hook = hook->next)
|
|
(*hook->proc) (hook->closure);
|
|
|
|
if (!ignoreEvents)
|
|
/* see if the hook(s) generated any protocol */
|
|
for (dd = 0; dd < app->count; dd++)
|
|
if (XEventsQueued(app->list[dd], QueuedAlready)) {
|
|
#ifdef USE_POLL
|
|
XtStackFree ((XtPointer) wf.fdlist, fdlist);
|
|
#endif
|
|
return dd;
|
|
}
|
|
}
|
|
|
|
if (app->rebuild_fdlist)
|
|
InitFds (app, ignoreEvents, ignoreInputs, &wf);
|
|
|
|
#ifdef XTHREADS /* { */
|
|
if (drop_lock) {
|
|
YIELD_APP_LOCK(app, &push_thread, &pushed_thread, &level);
|
|
nfds = IoWait (&wt, &wf);
|
|
RESTORE_APP_LOCK(app, level, &pushed_thread);
|
|
} else
|
|
#endif /* } */
|
|
nfds = IoWait (&wt, &wf);
|
|
if (nfds == -1) {
|
|
/*
|
|
* interrupt occured recalculate time value and wait again.
|
|
*/
|
|
if (errno == EINTR || errno == EAGAIN) {
|
|
if (errno == EAGAIN) {
|
|
errno = 0; /* errno is not self reseting */
|
|
continue;
|
|
}
|
|
errno = 0; /* errno is not self reseting */
|
|
|
|
/* was it interrupted by a signal that we care about? */
|
|
if (!ignoreSignals && app->signalQueue != NULL) {
|
|
SignalEventRec *se_ptr = app->signalQueue;
|
|
while (se_ptr != NULL) {
|
|
if (se_ptr->se_notice) {
|
|
if (block && howlong != NULL)
|
|
AdjustHowLong (howlong, &wt.start_time);
|
|
#ifdef USE_POLL
|
|
XtStackFree ((XtPointer) wf.fdlist, fdlist);
|
|
#endif
|
|
return -1;
|
|
}
|
|
se_ptr = se_ptr->se_next;
|
|
}
|
|
}
|
|
|
|
if (!ignoreEvents)
|
|
/* get Xlib to detect a bad connection */
|
|
for (dd = 0; dd < app->count; dd++)
|
|
if (XEventsQueued(app->list[dd], QueuedAfterReading)) {
|
|
#ifdef USE_POLL
|
|
XtStackFree ((XtPointer) wf.fdlist, fdlist);
|
|
#endif
|
|
return dd;
|
|
}
|
|
|
|
if (block) {
|
|
#ifndef USE_POLL
|
|
if (wt.wait_time_ptr == NULL)
|
|
#else
|
|
if (wt.poll_wait == X_BLOCK)
|
|
#endif
|
|
continue;
|
|
X_GETTIMEOFDAY (&wt.new_time);
|
|
FIXUP_TIMEVAL (wt.new_time);
|
|
TIMEDELTA (wt.time_spent, wt.new_time, wt.cur_time);
|
|
wt.cur_time = wt.new_time;
|
|
#ifndef USE_POLL
|
|
if (IS_AFTER (wt.time_spent, *wt.wait_time_ptr)) {
|
|
TIMEDELTA (wt.wait_time, *wt.wait_time_ptr, wt.time_spent);
|
|
wt.wait_time_ptr = &wt.wait_time;
|
|
continue;
|
|
} else
|
|
#else
|
|
if ((wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000) < wt.poll_wait) {
|
|
wt.poll_wait -= (wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000);
|
|
continue;
|
|
} else
|
|
#endif
|
|
nfds = 0;
|
|
}
|
|
} else {
|
|
char Errno[12];
|
|
String param = Errno;
|
|
Cardinal param_count = 1;
|
|
|
|
sprintf( Errno, "%d", errno);
|
|
XtAppWarningMsg(app, "communicationError","select",
|
|
XtCXtToolkitError,"Select failed; error code %s",
|
|
¶m, ¶m_count);
|
|
continue;
|
|
}
|
|
} /* timed out or input available */
|
|
break;
|
|
}
|
|
|
|
if (nfds == 0) {
|
|
/* Timed out */
|
|
if (howlong)
|
|
*howlong = (unsigned long)0;
|
|
#ifdef USE_POLL
|
|
XtStackFree ((XtPointer) wf.fdlist, fdlist);
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
if (block && howlong != NULL)
|
|
AdjustHowLong (howlong, &wt.start_time);
|
|
|
|
if (ignoreInputs && ignoreEvents) {
|
|
#ifdef USE_POLL
|
|
XtStackFree ((XtPointer) wf.fdlist, fdlist);
|
|
#endif
|
|
return -1;
|
|
} else
|
|
FindInputs (app, &wf, nfds,
|
|
ignoreEvents, ignoreInputs,
|
|
&dpy_no, &found_input);
|
|
|
|
if (dpy_no >= 0 || found_input) {
|
|
#ifdef USE_POLL
|
|
XtStackFree ((XtPointer) wf.fdlist, fdlist);
|
|
#endif
|
|
return dpy_no;
|
|
}
|
|
goto WaitLoop;
|
|
}
|
|
|
|
#define IeCallProc(ptr) \
|
|
(*ptr->ie_proc) (ptr->ie_closure, &ptr->ie_source, (XtInputId*)&ptr);
|
|
|
|
#define TeCallProc(ptr) \
|
|
(*ptr->te_proc) (ptr->te_closure, (XtIntervalId*)&ptr);
|
|
|
|
#define SeCallProc(ptr) \
|
|
(*ptr->se_proc) (ptr->se_closure, (XtSignalId*)&ptr);
|
|
|
|
/*
|
|
* Public Routines
|
|
*/
|
|
|
|
XtIntervalId XtAddTimeOut(
|
|
unsigned long interval,
|
|
XtTimerCallbackProc proc,
|
|
XtPointer closure)
|
|
{
|
|
return XtAppAddTimeOut(_XtDefaultAppContext(),
|
|
interval, proc, closure);
|
|
}
|
|
|
|
static void QueueTimerEvent(
|
|
XtAppContext app,
|
|
TimerEventRec *ptr)
|
|
{
|
|
TimerEventRec *t,**tt;
|
|
tt = &app->timerQueue;
|
|
t = *tt;
|
|
while (t != NULL &&
|
|
IS_AFTER(t->te_timer_value, ptr->te_timer_value)) {
|
|
tt = &t->te_next;
|
|
t = *tt;
|
|
}
|
|
ptr->te_next = t;
|
|
*tt = ptr;
|
|
}
|
|
|
|
XtIntervalId XtAppAddTimeOut(
|
|
XtAppContext app,
|
|
unsigned long interval,
|
|
XtTimerCallbackProc proc,
|
|
XtPointer closure)
|
|
{
|
|
TimerEventRec *tptr;
|
|
struct timeval current_time;
|
|
|
|
LOCK_APP(app);
|
|
LOCK_PROCESS;
|
|
if (freeTimerRecs) {
|
|
tptr = freeTimerRecs;
|
|
freeTimerRecs = tptr->te_next;
|
|
}
|
|
else tptr = XtNew(TimerEventRec);
|
|
UNLOCK_PROCESS;
|
|
|
|
tptr->te_next = NULL;
|
|
tptr->te_closure = closure;
|
|
tptr->te_proc = proc;
|
|
tptr->app = app;
|
|
tptr->te_timer_value.tv_sec = interval/1000;
|
|
tptr->te_timer_value.tv_usec = (interval%1000)*1000;
|
|
X_GETTIMEOFDAY (¤t_time);
|
|
FIXUP_TIMEVAL(current_time);
|
|
ADD_TIME(tptr->te_timer_value,tptr->te_timer_value,current_time);
|
|
QueueTimerEvent(app, tptr);
|
|
UNLOCK_APP(app);
|
|
return( (XtIntervalId) tptr);
|
|
}
|
|
|
|
void XtRemoveTimeOut(
|
|
XtIntervalId id)
|
|
{
|
|
TimerEventRec *t, *last, *tid = (TimerEventRec *) id;
|
|
XtAppContext app = tid->app;
|
|
|
|
/* find it */
|
|
LOCK_APP(app);
|
|
for(t = app->timerQueue, last = NULL;
|
|
t != NULL && t != tid;
|
|
t = t->te_next) last = t;
|
|
|
|
if (t == NULL) {
|
|
UNLOCK_APP(app);
|
|
return; /* couldn't find it */
|
|
}
|
|
if(last == NULL) { /* first one on the list */
|
|
app->timerQueue = t->te_next;
|
|
} else last->te_next = t->te_next;
|
|
|
|
LOCK_PROCESS;
|
|
t->te_next = freeTimerRecs;
|
|
freeTimerRecs = t;
|
|
UNLOCK_PROCESS;
|
|
UNLOCK_APP(app);
|
|
}
|
|
|
|
XtWorkProcId XtAddWorkProc(
|
|
XtWorkProc proc,
|
|
XtPointer closure)
|
|
{
|
|
return XtAppAddWorkProc(_XtDefaultAppContext(), proc, closure);
|
|
}
|
|
|
|
XtWorkProcId XtAppAddWorkProc(
|
|
XtAppContext app,
|
|
XtWorkProc proc,
|
|
XtPointer closure)
|
|
{
|
|
WorkProcRec *wptr;
|
|
|
|
LOCK_APP(app);
|
|
LOCK_PROCESS;
|
|
if (freeWorkRecs) {
|
|
wptr = freeWorkRecs;
|
|
freeWorkRecs = wptr->next;
|
|
} else wptr = XtNew(WorkProcRec);
|
|
UNLOCK_PROCESS;
|
|
wptr->next = app->workQueue;
|
|
wptr->closure = closure;
|
|
wptr->proc = proc;
|
|
wptr->app = app;
|
|
app->workQueue = wptr;
|
|
UNLOCK_APP(app);
|
|
return (XtWorkProcId) wptr;
|
|
}
|
|
|
|
void XtRemoveWorkProc(
|
|
XtWorkProcId id)
|
|
{
|
|
WorkProcRec *wid= (WorkProcRec *) id, *w, *last;
|
|
XtAppContext app = wid->app;
|
|
|
|
LOCK_APP(app);
|
|
/* find it */
|
|
for(w = app->workQueue, last = NULL;
|
|
w != NULL && w != wid; w = w->next) last = w;
|
|
|
|
if (w == NULL) {
|
|
UNLOCK_APP(app);
|
|
return; /* couldn't find it */
|
|
}
|
|
|
|
if(last == NULL) app->workQueue = w->next;
|
|
else last->next = w->next;
|
|
LOCK_PROCESS;
|
|
w->next = freeWorkRecs;
|
|
freeWorkRecs = w;
|
|
UNLOCK_PROCESS;
|
|
UNLOCK_APP(app);
|
|
}
|
|
|
|
XtSignalId XtAddSignal(
|
|
XtSignalCallbackProc proc,
|
|
XtPointer closure)
|
|
{
|
|
return XtAppAddSignal(_XtDefaultAppContext(), proc, closure);
|
|
}
|
|
|
|
XtSignalId XtAppAddSignal(
|
|
XtAppContext app,
|
|
XtSignalCallbackProc proc,
|
|
XtPointer closure)
|
|
{
|
|
SignalEventRec *sptr;
|
|
|
|
LOCK_APP(app);
|
|
LOCK_PROCESS;
|
|
if (freeSignalRecs) {
|
|
sptr = freeSignalRecs;
|
|
freeSignalRecs = sptr->se_next;
|
|
} else
|
|
sptr = XtNew(SignalEventRec);
|
|
UNLOCK_PROCESS;
|
|
sptr->se_next = app->signalQueue;
|
|
sptr->se_closure = closure;
|
|
sptr->se_proc = proc;
|
|
sptr->app = app;
|
|
sptr->se_notice = FALSE;
|
|
app->signalQueue = sptr;
|
|
UNLOCK_APP(app);
|
|
return (XtSignalId) sptr;
|
|
}
|
|
|
|
void XtRemoveSignal(
|
|
XtSignalId id)
|
|
{
|
|
SignalEventRec *sid = (SignalEventRec*) id, *s, *last = NULL;
|
|
XtAppContext app = sid->app;
|
|
|
|
LOCK_APP(app);
|
|
for (s = app->signalQueue; s != NULL && s != sid; s = s->se_next)
|
|
last = s;
|
|
if (s == NULL) {
|
|
UNLOCK_APP(app);
|
|
return;
|
|
}
|
|
if (last == NULL)
|
|
app->signalQueue = s->se_next;
|
|
else
|
|
last->se_next = s->se_next;
|
|
LOCK_PROCESS;
|
|
s->se_next = freeSignalRecs;
|
|
freeSignalRecs = s;
|
|
UNLOCK_PROCESS;
|
|
UNLOCK_APP(app);
|
|
}
|
|
|
|
void XtNoticeSignal(
|
|
XtSignalId id)
|
|
{
|
|
/*
|
|
* It would be overkill to lock the app to set this flag.
|
|
* In the worst case, 2..n threads would be modifying this
|
|
* flag. The last one wins. Since signals occur asynchronously
|
|
* anyway, this can occur with or without threads.
|
|
*
|
|
* The other issue is that thread t1 sets the flag in a
|
|
* signalrec that has been deleted in thread t2. We rely
|
|
* on a detail of the implementation, i.e. free'd signalrecs
|
|
* aren't really free'd, they're just moved to a list of
|
|
* free recs, so deref'ing one won't hurt anything.
|
|
*
|
|
* Lastly, and perhaps most importantly, since POSIX threads
|
|
* says that the handling of asynchronous signals in a synchronous
|
|
* threads environment is undefined. Therefor it would be an
|
|
* error for both signals and threads to be in use in the same
|
|
* program.
|
|
*/
|
|
SignalEventRec *sid = (SignalEventRec*) id;
|
|
sid->se_notice = TRUE;
|
|
}
|
|
|
|
XtInputId XtAddInput(
|
|
int source,
|
|
XtPointer Condition,
|
|
XtInputCallbackProc proc,
|
|
XtPointer closure)
|
|
{
|
|
return XtAppAddInput(_XtDefaultAppContext(),
|
|
source, Condition, proc, closure);
|
|
}
|
|
|
|
XtInputId XtAppAddInput(
|
|
XtAppContext app,
|
|
int source,
|
|
XtPointer Condition,
|
|
XtInputCallbackProc proc,
|
|
XtPointer closure)
|
|
{
|
|
InputEvent* sptr;
|
|
XtInputMask condition = (XtInputMask) Condition;
|
|
|
|
LOCK_APP(app);
|
|
if (!condition ||
|
|
condition & ~(XtInputReadMask|XtInputWriteMask|XtInputExceptMask))
|
|
XtAppErrorMsg(app,"invalidParameter","xtAddInput",XtCXtToolkitError,
|
|
"invalid condition passed to XtAppAddInput",
|
|
(String *)NULL, (Cardinal *)NULL);
|
|
|
|
if (app->input_max <= source) {
|
|
Cardinal n = source + 1;
|
|
int ii;
|
|
app->input_list = (InputEvent**)XtRealloc((char*) app->input_list,
|
|
n * sizeof(InputEvent*));
|
|
for (ii = app->input_max; ii < (int) n; ii++)
|
|
app->input_list[ii] = (InputEvent*) NULL;
|
|
app->input_max = n;
|
|
}
|
|
sptr = XtNew(InputEvent);
|
|
sptr->ie_proc = proc;
|
|
sptr->ie_closure = closure;
|
|
sptr->app = app;
|
|
sptr->ie_oq = NULL;
|
|
sptr->ie_source = source;
|
|
sptr->ie_condition = condition;
|
|
sptr->ie_next = app->input_list[source];
|
|
app->input_list[source] = sptr;
|
|
|
|
#ifndef USE_POLL
|
|
if (condition & XtInputReadMask) FD_SET(source, &app->fds.rmask);
|
|
if (condition & XtInputWriteMask) FD_SET(source, &app->fds.wmask);
|
|
if (condition & XtInputExceptMask) FD_SET(source, &app->fds.emask);
|
|
|
|
if (app->fds.nfds < (source+1)) app->fds.nfds = source+1;
|
|
#else
|
|
if (sptr->ie_next == NULL)
|
|
app->fds.nfds++;
|
|
#endif
|
|
app->input_count++;
|
|
app->rebuild_fdlist = TRUE;
|
|
UNLOCK_APP(app);
|
|
return((XtInputId)sptr);
|
|
}
|
|
|
|
void XtRemoveInput(
|
|
register XtInputId id)
|
|
{
|
|
register InputEvent *sptr, *lptr;
|
|
XtAppContext app = ((InputEvent *)id)->app;
|
|
register int source = ((InputEvent *)id)->ie_source;
|
|
Boolean found = False;
|
|
|
|
LOCK_APP(app);
|
|
sptr = app->outstandingQueue;
|
|
lptr = NULL;
|
|
for (; sptr != NULL; sptr = sptr->ie_oq) {
|
|
if (sptr == (InputEvent *)id) {
|
|
if (lptr == NULL) app->outstandingQueue = sptr->ie_oq;
|
|
else lptr->ie_oq = sptr->ie_oq;
|
|
}
|
|
lptr = sptr;
|
|
}
|
|
|
|
if(app->input_list && (sptr = app->input_list[source]) != NULL) {
|
|
for( lptr = NULL ; sptr; sptr = sptr->ie_next ){
|
|
if(sptr == (InputEvent *) id) {
|
|
#ifndef USE_POLL
|
|
XtInputMask condition = 0;
|
|
#endif
|
|
if(lptr == NULL) {
|
|
app->input_list[source] = sptr->ie_next;
|
|
} else {
|
|
lptr->ie_next = sptr->ie_next;
|
|
}
|
|
#ifndef USE_POLL
|
|
for (lptr = app->input_list[source];
|
|
lptr; lptr = lptr->ie_next)
|
|
condition |= lptr->ie_condition;
|
|
if ((sptr->ie_condition & XtInputReadMask) &&
|
|
!(condition & XtInputReadMask))
|
|
FD_CLR(source, &app->fds.rmask);
|
|
if ((sptr->ie_condition & XtInputWriteMask) &&
|
|
!(condition & XtInputWriteMask))
|
|
FD_CLR(source, &app->fds.wmask);
|
|
if ((sptr->ie_condition & XtInputExceptMask) &&
|
|
!(condition & XtInputExceptMask))
|
|
FD_CLR(source, &app->fds.emask);
|
|
#endif
|
|
XtFree((char *) sptr);
|
|
found = True;
|
|
break;
|
|
}
|
|
lptr = sptr;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
app->input_count--;
|
|
#ifdef USE_POLL
|
|
if (app->input_list[source] == NULL)
|
|
app->fds.nfds--;
|
|
#endif
|
|
app->rebuild_fdlist = TRUE;
|
|
} else
|
|
XtAppWarningMsg(app, "invalidProcedure","inputHandler",
|
|
XtCXtToolkitError,
|
|
"XtRemoveInput: Input handler not found",
|
|
(String *)NULL, (Cardinal *)NULL);
|
|
UNLOCK_APP(app);
|
|
}
|
|
|
|
void _XtRemoveAllInputs(
|
|
XtAppContext app)
|
|
{
|
|
int i;
|
|
for (i = 0; i < app->input_max; i++) {
|
|
InputEvent* ep = app->input_list[i];
|
|
while (ep) {
|
|
InputEvent *next = ep->ie_next;
|
|
XtFree( (char*)ep );
|
|
ep = next;
|
|
}
|
|
}
|
|
XtFree((char *) app->input_list);
|
|
}
|
|
|
|
/* Do alternate input and timer callbacks if there are any */
|
|
|
|
static void DoOtherSources(
|
|
XtAppContext app)
|
|
{
|
|
TimerEventRec *te_ptr;
|
|
InputEvent *ie_ptr;
|
|
struct timeval cur_time;
|
|
|
|
#define DrainQueue() \
|
|
for (ie_ptr = app->outstandingQueue; ie_ptr != NULL;) { \
|
|
app->outstandingQueue = ie_ptr->ie_oq; \
|
|
ie_ptr ->ie_oq = NULL; \
|
|
IeCallProc(ie_ptr); \
|
|
ie_ptr = app->outstandingQueue; \
|
|
}
|
|
/*enddef*/
|
|
DrainQueue();
|
|
if (app->input_count > 0) {
|
|
/* Call _XtWaitForSomething to get input queued up */
|
|
(void) _XtWaitForSomething (app,
|
|
TRUE, TRUE, FALSE, TRUE,
|
|
FALSE,
|
|
#ifdef XTHREADS
|
|
TRUE,
|
|
#endif
|
|
(unsigned long *)NULL);
|
|
DrainQueue();
|
|
}
|
|
if (app->timerQueue != NULL) { /* check timeout queue */
|
|
X_GETTIMEOFDAY (&cur_time);
|
|
FIXUP_TIMEVAL(cur_time);
|
|
while(IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time)) {
|
|
te_ptr = app->timerQueue;
|
|
app->timerQueue = te_ptr->te_next;
|
|
te_ptr->te_next = NULL;
|
|
if (te_ptr->te_proc != NULL)
|
|
TeCallProc(te_ptr);
|
|
LOCK_PROCESS;
|
|
te_ptr->te_next = freeTimerRecs;
|
|
freeTimerRecs = te_ptr;
|
|
UNLOCK_PROCESS;
|
|
if (app->timerQueue == NULL) break;
|
|
}
|
|
}
|
|
if (app->signalQueue != NULL) {
|
|
SignalEventRec *se_ptr = app->signalQueue;
|
|
while (se_ptr != NULL) {
|
|
if (se_ptr->se_notice) {
|
|
se_ptr->se_notice = FALSE;
|
|
if (se_ptr->se_proc != NULL)
|
|
SeCallProc(se_ptr);
|
|
}
|
|
se_ptr = se_ptr->se_next;
|
|
}
|
|
}
|
|
#undef DrainQueue
|
|
}
|
|
|
|
/* If there are any work procs, call them. Return whether we did so */
|
|
|
|
static Boolean CallWorkProc(
|
|
XtAppContext app)
|
|
{
|
|
register WorkProcRec *w = app->workQueue;
|
|
Boolean delete;
|
|
|
|
if (w == NULL) return FALSE;
|
|
|
|
app->workQueue = w->next;
|
|
|
|
delete = (*(w->proc)) (w->closure);
|
|
|
|
if (delete) {
|
|
LOCK_PROCESS;
|
|
w->next = freeWorkRecs;
|
|
freeWorkRecs = w;
|
|
UNLOCK_PROCESS;
|
|
}
|
|
else {
|
|
w->next = app->workQueue;
|
|
app->workQueue = w;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* XtNextEvent()
|
|
* return next event;
|
|
*/
|
|
|
|
void XtNextEvent(
|
|
XEvent *event)
|
|
{
|
|
XtAppNextEvent(_XtDefaultAppContext(), event);
|
|
}
|
|
|
|
void _XtRefreshMapping(
|
|
XEvent* event,
|
|
_XtBoolean dispatch)
|
|
{
|
|
XtPerDisplay pd;
|
|
|
|
LOCK_PROCESS;
|
|
pd = _XtGetPerDisplay(event->xmapping.display);
|
|
if (event->xmapping.request != MappingPointer &&
|
|
pd && pd->keysyms && (event->xmapping.serial >= pd->keysyms_serial))
|
|
_XtBuildKeysymTables( event->xmapping.display, pd );
|
|
XRefreshKeyboardMapping(&event->xmapping);
|
|
if (dispatch && pd && pd->mapping_callbacks)
|
|
XtCallCallbackList((Widget) NULL,
|
|
(XtCallbackList)pd->mapping_callbacks,
|
|
(XtPointer)event );
|
|
UNLOCK_PROCESS;
|
|
}
|
|
|
|
void XtAppNextEvent(
|
|
XtAppContext app,
|
|
XEvent *event)
|
|
{
|
|
int i, d;
|
|
|
|
LOCK_APP(app);
|
|
for (;;) {
|
|
if (app->count == 0)
|
|
DoOtherSources(app);
|
|
else {
|
|
for (i = 1; i <= app->count; i++) {
|
|
d = (i + app->last) % app->count;
|
|
if (d == 0) DoOtherSources(app);
|
|
if (XEventsQueued(app->list[d], QueuedAfterReading))
|
|
goto GotEvent;
|
|
}
|
|
for (i = 1; i <= app->count; i++) {
|
|
d = (i + app->last) % app->count;
|
|
if (XEventsQueued(app->list[d], QueuedAfterFlush))
|
|
goto GotEvent;
|
|
}
|
|
}
|
|
|
|
/* We're ready to wait...if there is a work proc, call it */
|
|
if (CallWorkProc(app)) continue;
|
|
|
|
d = _XtWaitForSomething (app,
|
|
FALSE, FALSE, FALSE, FALSE,
|
|
TRUE,
|
|
#ifdef XTHREADS
|
|
TRUE,
|
|
#endif
|
|
(unsigned long *) NULL);
|
|
|
|
if (d != -1) {
|
|
GotEvent:
|
|
XNextEvent (app->list[d], event);
|
|
#ifdef XTHREADS
|
|
/* assert(app->list[d] == event->xany.display); */
|
|
#endif
|
|
app->last = d;
|
|
if (event->xany.type == MappingNotify)
|
|
_XtRefreshMapping(event, False);
|
|
UNLOCK_APP(app);
|
|
return;
|
|
}
|
|
|
|
} /* for */
|
|
}
|
|
|
|
void XtProcessEvent(
|
|
XtInputMask mask)
|
|
{
|
|
XtAppProcessEvent(_XtDefaultAppContext(), mask);
|
|
}
|
|
|
|
void XtAppProcessEvent(
|
|
XtAppContext app,
|
|
XtInputMask mask)
|
|
{
|
|
int i, d;
|
|
XEvent event;
|
|
struct timeval cur_time;
|
|
|
|
LOCK_APP(app);
|
|
if (mask == 0) {
|
|
UNLOCK_APP(app);
|
|
return;
|
|
}
|
|
|
|
for (;;) {
|
|
|
|
if (mask & XtIMSignal && app->signalQueue != NULL) {
|
|
SignalEventRec *se_ptr = app->signalQueue;
|
|
while (se_ptr != NULL) {
|
|
if (se_ptr->se_notice) {
|
|
se_ptr->se_notice = FALSE;
|
|
SeCallProc(se_ptr);
|
|
UNLOCK_APP(app);
|
|
return;
|
|
}
|
|
se_ptr = se_ptr->se_next;
|
|
}
|
|
}
|
|
|
|
if (mask & XtIMTimer && app->timerQueue != NULL) {
|
|
X_GETTIMEOFDAY (&cur_time);
|
|
FIXUP_TIMEVAL(cur_time);
|
|
if (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)){
|
|
TimerEventRec *te_ptr = app->timerQueue;
|
|
app->timerQueue = app->timerQueue->te_next;
|
|
te_ptr->te_next = NULL;
|
|
if (te_ptr->te_proc != NULL)
|
|
TeCallProc(te_ptr);
|
|
LOCK_PROCESS;
|
|
te_ptr->te_next = freeTimerRecs;
|
|
freeTimerRecs = te_ptr;
|
|
UNLOCK_PROCESS;
|
|
UNLOCK_APP(app);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (mask & XtIMAlternateInput) {
|
|
if (app->input_count > 0 && app->outstandingQueue == NULL) {
|
|
/* Call _XtWaitForSomething to get input queued up */
|
|
(void) _XtWaitForSomething (app,
|
|
TRUE, TRUE, FALSE, TRUE,
|
|
FALSE,
|
|
#ifdef XTHREADS
|
|
TRUE,
|
|
#endif
|
|
(unsigned long *)NULL);
|
|
}
|
|
if (app->outstandingQueue != NULL) {
|
|
InputEvent *ie_ptr = app->outstandingQueue;
|
|
app->outstandingQueue = ie_ptr->ie_oq;
|
|
ie_ptr->ie_oq = NULL;
|
|
IeCallProc(ie_ptr);
|
|
UNLOCK_APP(app);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (mask & XtIMXEvent) {
|
|
for (i = 1; i <= app->count; i++) {
|
|
d = (i + app->last) % app->count;
|
|
if (XEventsQueued(app->list[d], QueuedAfterReading))
|
|
goto GotEvent;
|
|
}
|
|
for (i = 1; i <= app->count; i++) {
|
|
d = (i + app->last) % app->count;
|
|
if (XEventsQueued(app->list[d], QueuedAfterFlush))
|
|
goto GotEvent;
|
|
}
|
|
}
|
|
|
|
/* Nothing to do...wait for something */
|
|
|
|
if (CallWorkProc(app)) continue;
|
|
|
|
d = _XtWaitForSomething (app,
|
|
(mask & XtIMXEvent ? FALSE : TRUE),
|
|
(mask & XtIMTimer ? FALSE : TRUE),
|
|
(mask & XtIMAlternateInput ? FALSE : TRUE),
|
|
(mask & XtIMSignal ? FALSE : TRUE),
|
|
TRUE,
|
|
#ifdef XTHREADS
|
|
TRUE,
|
|
#endif
|
|
(unsigned long *) NULL);
|
|
|
|
if (mask & XtIMXEvent && d != -1) {
|
|
GotEvent:
|
|
XNextEvent(app->list[d], &event);
|
|
#ifdef XTHREADS
|
|
/* assert(app->list[d] == event.xany.display); */
|
|
#endif
|
|
app->last = d;
|
|
if (event.xany.type == MappingNotify) {
|
|
_XtRefreshMapping(&event, False);
|
|
}
|
|
XtDispatchEvent(&event);
|
|
UNLOCK_APP(app);
|
|
return;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
Boolean XtPending(void)
|
|
{
|
|
return (XtAppPending(_XtDefaultAppContext()) != 0);
|
|
}
|
|
|
|
XtInputMask XtAppPending(
|
|
XtAppContext app)
|
|
{
|
|
struct timeval cur_time;
|
|
int d;
|
|
XtInputMask ret = 0;
|
|
|
|
/*
|
|
* Check for pending X events
|
|
*/
|
|
LOCK_APP(app);
|
|
for (d = 0; d < app->count; d++) {
|
|
if (XEventsQueued(app->list[d], QueuedAfterReading)) {
|
|
ret = XtIMXEvent;
|
|
break;
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
for (d = 0; d < app->count; d++) {
|
|
if (XEventsQueued(app->list[d], QueuedAfterFlush)) {
|
|
ret = XtIMXEvent;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (app->signalQueue != NULL) {
|
|
SignalEventRec *se_ptr = app->signalQueue;
|
|
while (se_ptr != NULL) {
|
|
if (se_ptr->se_notice) {
|
|
ret |= XtIMSignal;
|
|
break;
|
|
}
|
|
se_ptr = se_ptr->se_next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check for pending alternate input
|
|
*/
|
|
if (app->timerQueue != NULL) { /* check timeout queue */
|
|
X_GETTIMEOFDAY (&cur_time);
|
|
FIXUP_TIMEVAL(cur_time);
|
|
if ((IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) &&
|
|
(app->timerQueue->te_proc != 0)) {
|
|
ret |= XtIMTimer;
|
|
}
|
|
}
|
|
|
|
if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput;
|
|
else {
|
|
/* This won't cause a wait, but will enqueue any input */
|
|
|
|
if(_XtWaitForSomething (app,
|
|
FALSE, TRUE, FALSE, TRUE,
|
|
FALSE,
|
|
#ifdef XTHREADS
|
|
TRUE,
|
|
#endif
|
|
(unsigned long *) NULL) != -1)
|
|
ret |= XtIMXEvent;
|
|
if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput;
|
|
}
|
|
UNLOCK_APP(app);
|
|
return ret;
|
|
}
|
|
|
|
/* Peek at alternate input and timer callbacks if there are any */
|
|
|
|
static Boolean PeekOtherSources(
|
|
XtAppContext app)
|
|
{
|
|
struct timeval cur_time;
|
|
|
|
if (app->outstandingQueue != NULL) return TRUE;
|
|
|
|
if (app->signalQueue != NULL) {
|
|
SignalEventRec *se_ptr = app->signalQueue;
|
|
while (se_ptr != NULL) {
|
|
if (se_ptr->se_notice)
|
|
return TRUE;
|
|
se_ptr = se_ptr->se_next;
|
|
}
|
|
}
|
|
|
|
if (app->input_count > 0) {
|
|
/* Call _XtWaitForSomething to get input queued up */
|
|
(void) _XtWaitForSomething (app,
|
|
TRUE, TRUE, FALSE, TRUE,
|
|
FALSE,
|
|
#ifdef XTHREADS
|
|
TRUE,
|
|
#endif
|
|
(unsigned long *)NULL);
|
|
if (app->outstandingQueue != NULL) return TRUE;
|
|
}
|
|
|
|
if (app->timerQueue != NULL) { /* check timeout queue */
|
|
X_GETTIMEOFDAY (&cur_time);
|
|
FIXUP_TIMEVAL(cur_time);
|
|
if (IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Boolean XtPeekEvent(
|
|
XEvent *event)
|
|
{
|
|
return XtAppPeekEvent(_XtDefaultAppContext(), event);
|
|
}
|
|
|
|
Boolean XtAppPeekEvent_SkipTimer;
|
|
|
|
Boolean XtAppPeekEvent(
|
|
XtAppContext app,
|
|
XEvent *event)
|
|
{
|
|
int i, d;
|
|
Boolean foundCall = FALSE;
|
|
|
|
LOCK_APP(app);
|
|
for (i = 1; i <= app->count; i++) {
|
|
d = (i + app->last) % app->count;
|
|
if (d == 0) foundCall = PeekOtherSources(app);
|
|
if (XEventsQueued(app->list[d], QueuedAfterReading))
|
|
goto GotEvent;
|
|
}
|
|
for (i = 1; i <= app->count; i++) {
|
|
d = (i + app->last) % app->count;
|
|
if (XEventsQueued(app->list[d], QueuedAfterFlush))
|
|
goto GotEvent;
|
|
}
|
|
|
|
if (foundCall) {
|
|
event->xany.type = 0;
|
|
event->xany.display = NULL;
|
|
event->xany.window = 0;
|
|
UNLOCK_APP(app);
|
|
return FALSE;
|
|
}
|
|
|
|
while (1) {
|
|
d = _XtWaitForSomething (app,
|
|
FALSE, FALSE, FALSE, FALSE,
|
|
TRUE,
|
|
#ifdef XTHREADS
|
|
TRUE,
|
|
#endif
|
|
(unsigned long *) NULL);
|
|
|
|
if (d != -1) { /* event */
|
|
GotEvent:
|
|
XPeekEvent(app->list[d], event);
|
|
app->last = (d == 0 ? app->count : d) - 1;
|
|
UNLOCK_APP(app);
|
|
return TRUE;
|
|
}
|
|
else { /* input or timer or signal */
|
|
/*
|
|
* Check to see why a -1 was returned, if a timer expired,
|
|
* call it and block some more
|
|
*/
|
|
if ((app->timerQueue != NULL) && ! XtAppPeekEvent_SkipTimer) { /* timer */
|
|
struct timeval cur_time;
|
|
Bool did_timer = False;
|
|
|
|
X_GETTIMEOFDAY (&cur_time);
|
|
FIXUP_TIMEVAL(cur_time);
|
|
while (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) {
|
|
TimerEventRec *te_ptr = app->timerQueue;
|
|
app->timerQueue = app->timerQueue->te_next;
|
|
te_ptr->te_next = NULL;
|
|
if (te_ptr->te_proc != NULL) {
|
|
TeCallProc(te_ptr);
|
|
did_timer = True;
|
|
}
|
|
LOCK_PROCESS;
|
|
te_ptr->te_next = freeTimerRecs;
|
|
freeTimerRecs = te_ptr;
|
|
UNLOCK_PROCESS;
|
|
if (app->timerQueue == NULL) break;
|
|
}
|
|
if (did_timer)
|
|
{
|
|
for (d = 0; d < app->count; d++)
|
|
/* the timer's procedure may have caused an event */
|
|
if (XEventsQueued(app->list[d], QueuedAfterFlush)) {
|
|
goto GotEvent;
|
|
}
|
|
continue; /* keep blocking */
|
|
}
|
|
}
|
|
/*
|
|
* spec is vague here; we'll assume signals also return FALSE,
|
|
* of course to determine whether a signal is pending requires
|
|
* walking the signalQueue looking for se_notice flags which
|
|
* this code doesn't do.
|
|
*/
|
|
#if 0
|
|
if (app->signalQueue != NULL) { /* signal */
|
|
event->xany.type = 0;
|
|
event->xany.display = NULL;
|
|
event->xany.window = 0;
|
|
UNLOCK_APP(app);
|
|
return FALSE;
|
|
}
|
|
else
|
|
#endif
|
|
{ /* input */
|
|
event->xany.type = 0;
|
|
event->xany.display = NULL;
|
|
event->xany.window = 0;
|
|
UNLOCK_APP(app);
|
|
return FALSE;
|
|
}
|
|
}
|
|
} /* end while */
|
|
}
|