WaitFor.c revision 05b261ec
105b261ecSmrg/***********************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrg
2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2705b261ecSmrg
2805b261ecSmrg                        All Rights Reserved
2905b261ecSmrg
3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3205b261ecSmrgprovided that the above copyright notice appear in all copies and that
3305b261ecSmrgboth that copyright notice and this permission notice appear in
3405b261ecSmrgsupporting documentation, and that the name of Digital not be
3505b261ecSmrgused in advertising or publicity pertaining to distribution of the
3605b261ecSmrgsoftware without specific, written prior permission.
3705b261ecSmrg
3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4405b261ecSmrgSOFTWARE.
4505b261ecSmrg
4605b261ecSmrg******************************************************************/
4705b261ecSmrg
4805b261ecSmrg
4905b261ecSmrg/*****************************************************************
5005b261ecSmrg * OS Dependent input routines:
5105b261ecSmrg *
5205b261ecSmrg *  WaitForSomething
5305b261ecSmrg *  TimerForce, TimerSet, TimerCheck, TimerFree
5405b261ecSmrg *
5505b261ecSmrg *****************************************************************/
5605b261ecSmrg
5705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5805b261ecSmrg#include <dix-config.h>
5905b261ecSmrg#endif
6005b261ecSmrg
6105b261ecSmrg#ifdef WIN32
6205b261ecSmrg#include <X11/Xwinsock.h>
6305b261ecSmrg#endif
6405b261ecSmrg#include <X11/Xos.h>			/* for strings, fcntl, time */
6505b261ecSmrg#include <errno.h>
6605b261ecSmrg#include <stdio.h>
6705b261ecSmrg#include <X11/X.h>
6805b261ecSmrg#include "misc.h"
6905b261ecSmrg
7005b261ecSmrg#include "osdep.h"
7105b261ecSmrg#include <X11/Xpoll.h>
7205b261ecSmrg#include "dixstruct.h"
7305b261ecSmrg#include "opaque.h"
7405b261ecSmrg#ifdef DPMSExtension
7505b261ecSmrg#include "dpmsproc.h"
7605b261ecSmrg#endif
7705b261ecSmrg
7805b261ecSmrg#ifdef WIN32
7905b261ecSmrg/* Error codes from windows sockets differ from fileio error codes  */
8005b261ecSmrg#undef EINTR
8105b261ecSmrg#define EINTR WSAEINTR
8205b261ecSmrg#undef EINVAL
8305b261ecSmrg#define EINVAL WSAEINVAL
8405b261ecSmrg#undef EBADF
8505b261ecSmrg#define EBADF WSAENOTSOCK
8605b261ecSmrg/* Windows select does not set errno. Use GetErrno as wrapper for
8705b261ecSmrg   WSAGetLastError */
8805b261ecSmrg#define GetErrno WSAGetLastError
8905b261ecSmrg#else
9005b261ecSmrg/* This is just a fallback to errno to hide the differences between unix and
9105b261ecSmrg   Windows in the code */
9205b261ecSmrg#define GetErrno() errno
9305b261ecSmrg#endif
9405b261ecSmrg
9505b261ecSmrg/* modifications by raphael */
9605b261ecSmrgint
9705b261ecSmrgmffs(fd_mask mask)
9805b261ecSmrg{
9905b261ecSmrg    int i;
10005b261ecSmrg
10105b261ecSmrg    if (!mask) return 0;
10205b261ecSmrg    i = 1;
10305b261ecSmrg    while (!(mask & 1))
10405b261ecSmrg    {
10505b261ecSmrg	i++;
10605b261ecSmrg	mask >>= 1;
10705b261ecSmrg    }
10805b261ecSmrg    return i;
10905b261ecSmrg}
11005b261ecSmrg
11105b261ecSmrg#ifdef DPMSExtension
11205b261ecSmrg#define DPMS_SERVER
11305b261ecSmrg#include <X11/extensions/dpms.h>
11405b261ecSmrg#endif
11505b261ecSmrg
11605b261ecSmrgstruct _OsTimerRec {
11705b261ecSmrg    OsTimerPtr		next;
11805b261ecSmrg    CARD32		expires;
11905b261ecSmrg    CARD32              delta;
12005b261ecSmrg    OsTimerCallback	callback;
12105b261ecSmrg    pointer		arg;
12205b261ecSmrg};
12305b261ecSmrg
12405b261ecSmrgstatic void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev);
12505b261ecSmrgstatic void CheckAllTimers(void);
12605b261ecSmrgstatic OsTimerPtr timers = NULL;
12705b261ecSmrg
12805b261ecSmrg/*****************
12905b261ecSmrg * WaitForSomething:
13005b261ecSmrg *     Make the server suspend until there is
13105b261ecSmrg *	1. data from clients or
13205b261ecSmrg *	2. input events available or
13305b261ecSmrg *	3. ddx notices something of interest (graphics
13405b261ecSmrg *	   queue ready, etc.) or
13505b261ecSmrg *	4. clients that have buffered replies/events are ready
13605b261ecSmrg *
13705b261ecSmrg *     If the time between INPUT events is
13805b261ecSmrg *     greater than ScreenSaverTime, the display is turned off (or
13905b261ecSmrg *     saved, depending on the hardware).  So, WaitForSomething()
14005b261ecSmrg *     has to handle this also (that's why the select() has a timeout.
14105b261ecSmrg *     For more info on ClientsWithInput, see ReadRequestFromClient().
14205b261ecSmrg *     pClientsReady is an array to store ready client->index values into.
14305b261ecSmrg *****************/
14405b261ecSmrg
14505b261ecSmrgint
14605b261ecSmrgWaitForSomething(int *pClientsReady)
14705b261ecSmrg{
14805b261ecSmrg    int i;
14905b261ecSmrg    struct timeval waittime, *wt;
15005b261ecSmrg    INT32 timeout = 0;
15105b261ecSmrg    fd_set clientsReadable;
15205b261ecSmrg    fd_set clientsWritable;
15305b261ecSmrg    int curclient;
15405b261ecSmrg    int selecterr;
15505b261ecSmrg    int nready;
15605b261ecSmrg    fd_set devicesReadable;
15705b261ecSmrg    CARD32 now = 0;
15805b261ecSmrg#ifdef SMART_SCHEDULE
15905b261ecSmrg    Bool    someReady = FALSE;
16005b261ecSmrg#endif
16105b261ecSmrg
16205b261ecSmrg    FD_ZERO(&clientsReadable);
16305b261ecSmrg
16405b261ecSmrg    /* We need a while loop here to handle
16505b261ecSmrg       crashed connections and the screen saver timeout */
16605b261ecSmrg    while (1)
16705b261ecSmrg    {
16805b261ecSmrg	/* deal with any blocked jobs */
16905b261ecSmrg	if (workQueue)
17005b261ecSmrg	    ProcessWorkQueue();
17105b261ecSmrg	if (XFD_ANYSET (&ClientsWithInput))
17205b261ecSmrg	{
17305b261ecSmrg#ifdef SMART_SCHEDULE
17405b261ecSmrg	    if (!SmartScheduleDisable)
17505b261ecSmrg	    {
17605b261ecSmrg		someReady = TRUE;
17705b261ecSmrg		waittime.tv_sec = 0;
17805b261ecSmrg		waittime.tv_usec = 0;
17905b261ecSmrg		wt = &waittime;
18005b261ecSmrg	    }
18105b261ecSmrg	    else
18205b261ecSmrg#endif
18305b261ecSmrg	    {
18405b261ecSmrg		XFD_COPYSET (&ClientsWithInput, &clientsReadable);
18505b261ecSmrg		break;
18605b261ecSmrg	    }
18705b261ecSmrg	}
18805b261ecSmrg#ifdef SMART_SCHEDULE
18905b261ecSmrg	if (someReady)
19005b261ecSmrg	{
19105b261ecSmrg	    XFD_COPYSET(&AllSockets, &LastSelectMask);
19205b261ecSmrg	    XFD_UNSET(&LastSelectMask, &ClientsWithInput);
19305b261ecSmrg	}
19405b261ecSmrg	else
19505b261ecSmrg	{
19605b261ecSmrg#endif
19705b261ecSmrg        wt = NULL;
19805b261ecSmrg	if (timers)
19905b261ecSmrg        {
20005b261ecSmrg            now = GetTimeInMillis();
20105b261ecSmrg	    timeout = timers->expires - now;
20205b261ecSmrg            if (timeout > 0 && timeout > timers->delta + 250) {
20305b261ecSmrg                /* time has rewound.  reset the timers. */
20405b261ecSmrg                CheckAllTimers();
20505b261ecSmrg            }
20605b261ecSmrg
20705b261ecSmrg	    if (timers) {
20805b261ecSmrg		timeout = timers->expires - now;
20905b261ecSmrg		if (timeout < 0)
21005b261ecSmrg		    timeout = 0;
21105b261ecSmrg		waittime.tv_sec = timeout / MILLI_PER_SECOND;
21205b261ecSmrg		waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
21305b261ecSmrg				   (1000000 / MILLI_PER_SECOND);
21405b261ecSmrg		wt = &waittime;
21505b261ecSmrg	    }
21605b261ecSmrg	}
21705b261ecSmrg	XFD_COPYSET(&AllSockets, &LastSelectMask);
21805b261ecSmrg#ifdef SMART_SCHEDULE
21905b261ecSmrg	}
22005b261ecSmrg	SmartScheduleIdle = TRUE;
22105b261ecSmrg#endif
22205b261ecSmrg	BlockHandler((pointer)&wt, (pointer)&LastSelectMask);
22305b261ecSmrg	if (NewOutputPending)
22405b261ecSmrg	    FlushAllOutput();
22505b261ecSmrg	/* keep this check close to select() call to minimize race */
22605b261ecSmrg	if (dispatchException)
22705b261ecSmrg	    i = -1;
22805b261ecSmrg	else if (AnyClientsWriteBlocked)
22905b261ecSmrg	{
23005b261ecSmrg	    XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
23105b261ecSmrg	    i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt);
23205b261ecSmrg	}
23305b261ecSmrg	else
23405b261ecSmrg	{
23505b261ecSmrg	    i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt);
23605b261ecSmrg	}
23705b261ecSmrg	selecterr = GetErrno();
23805b261ecSmrg	WakeupHandler(i, (pointer)&LastSelectMask);
23905b261ecSmrg#ifdef SMART_SCHEDULE
24005b261ecSmrg	if (i >= 0)
24105b261ecSmrg	{
24205b261ecSmrg	    SmartScheduleIdle = FALSE;
24305b261ecSmrg	    SmartScheduleIdleCount = 0;
24405b261ecSmrg	    if (SmartScheduleTimerStopped)
24505b261ecSmrg		(void) SmartScheduleStartTimer ();
24605b261ecSmrg	}
24705b261ecSmrg#endif
24805b261ecSmrg	if (i <= 0) /* An error or timeout occurred */
24905b261ecSmrg	{
25005b261ecSmrg	    if (dispatchException)
25105b261ecSmrg		return 0;
25205b261ecSmrg	    if (i < 0)
25305b261ecSmrg	    {
25405b261ecSmrg		if (selecterr == EBADF)    /* Some client disconnected */
25505b261ecSmrg		{
25605b261ecSmrg		    CheckConnections ();
25705b261ecSmrg		    if (! XFD_ANYSET (&AllClients))
25805b261ecSmrg			return 0;
25905b261ecSmrg		}
26005b261ecSmrg		else if (selecterr == EINVAL)
26105b261ecSmrg		{
26205b261ecSmrg		    FatalError("WaitForSomething(): select: errno=%d\n",
26305b261ecSmrg			selecterr);
26405b261ecSmrg            }
26505b261ecSmrg		else if (selecterr != EINTR && selecterr != EAGAIN)
26605b261ecSmrg		{
26705b261ecSmrg		    ErrorF("WaitForSomething(): select: errno=%d\n",
26805b261ecSmrg			selecterr);
26905b261ecSmrg		}
27005b261ecSmrg	    }
27105b261ecSmrg#ifdef SMART_SCHEDULE
27205b261ecSmrg	    else if (someReady)
27305b261ecSmrg	    {
27405b261ecSmrg		/*
27505b261ecSmrg		 * If no-one else is home, bail quickly
27605b261ecSmrg		 */
27705b261ecSmrg		XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
27805b261ecSmrg		XFD_COPYSET(&ClientsWithInput, &clientsReadable);
27905b261ecSmrg		break;
28005b261ecSmrg	    }
28105b261ecSmrg#endif
28205b261ecSmrg	    if (*checkForInput[0] != *checkForInput[1])
28305b261ecSmrg		return 0;
28405b261ecSmrg
28505b261ecSmrg	    if (timers)
28605b261ecSmrg	    {
28705b261ecSmrg                int expired = 0;
28805b261ecSmrg		now = GetTimeInMillis();
28905b261ecSmrg		if ((int) (timers->expires - now) <= 0)
29005b261ecSmrg		    expired = 1;
29105b261ecSmrg
29205b261ecSmrg		while (timers && (int) (timers->expires - now) <= 0)
29305b261ecSmrg		    DoTimer(timers, now, &timers);
29405b261ecSmrg
29505b261ecSmrg                if (expired)
29605b261ecSmrg                    return 0;
29705b261ecSmrg	    }
29805b261ecSmrg	}
29905b261ecSmrg	else
30005b261ecSmrg	{
30105b261ecSmrg	    fd_set tmp_set;
30205b261ecSmrg
30305b261ecSmrg	    if (*checkForInput[0] == *checkForInput[1]) {
30405b261ecSmrg	        if (timers)
30505b261ecSmrg	        {
30605b261ecSmrg                    int expired = 0;
30705b261ecSmrg		    now = GetTimeInMillis();
30805b261ecSmrg		    if ((int) (timers->expires - now) <= 0)
30905b261ecSmrg		        expired = 1;
31005b261ecSmrg
31105b261ecSmrg		    while (timers && (int) (timers->expires - now) <= 0)
31205b261ecSmrg		        DoTimer(timers, now, &timers);
31305b261ecSmrg
31405b261ecSmrg                    if (expired)
31505b261ecSmrg                        return 0;
31605b261ecSmrg	        }
31705b261ecSmrg	    }
31805b261ecSmrg#ifdef SMART_SCHEDULE
31905b261ecSmrg	    if (someReady)
32005b261ecSmrg		XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask);
32105b261ecSmrg#endif
32205b261ecSmrg	    if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable))
32305b261ecSmrg	    {
32405b261ecSmrg		NewOutputPending = TRUE;
32505b261ecSmrg		XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
32605b261ecSmrg		XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
32705b261ecSmrg		if (! XFD_ANYSET(&ClientsWriteBlocked))
32805b261ecSmrg		    AnyClientsWriteBlocked = FALSE;
32905b261ecSmrg	    }
33005b261ecSmrg
33105b261ecSmrg	    XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
33205b261ecSmrg	    XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
33305b261ecSmrg	    XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
33405b261ecSmrg	    if (XFD_ANYSET(&tmp_set))
33505b261ecSmrg		QueueWorkProc(EstablishNewConnections, NULL,
33605b261ecSmrg			      (pointer)&LastSelectMask);
33705b261ecSmrg
33805b261ecSmrg	    if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable))
33905b261ecSmrg		break;
34005b261ecSmrg#ifdef WIN32
34105b261ecSmrg	    /* Windows keyboard and mouse events are added to the input queue
34205b261ecSmrg	       in Block- and WakupHandlers. There is no device to check if
34305b261ecSmrg	       data is ready. So check here if new input is available */
34405b261ecSmrg	    if (*checkForInput[0] != *checkForInput[1])
34505b261ecSmrg		return 0;
34605b261ecSmrg#endif
34705b261ecSmrg	}
34805b261ecSmrg    }
34905b261ecSmrg
35005b261ecSmrg    nready = 0;
35105b261ecSmrg    if (XFD_ANYSET (&clientsReadable))
35205b261ecSmrg    {
35305b261ecSmrg#ifndef WIN32
35405b261ecSmrg	for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
35505b261ecSmrg	{
35605b261ecSmrg	    int highest_priority = 0;
35705b261ecSmrg
35805b261ecSmrg	    while (clientsReadable.fds_bits[i])
35905b261ecSmrg	    {
36005b261ecSmrg	        int client_priority, client_index;
36105b261ecSmrg
36205b261ecSmrg		curclient = ffs (clientsReadable.fds_bits[i]) - 1;
36305b261ecSmrg		client_index = /* raphael: modified */
36405b261ecSmrg			ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))];
36505b261ecSmrg#else
36605b261ecSmrg	int highest_priority = 0;
36705b261ecSmrg	fd_set savedClientsReadable;
36805b261ecSmrg	XFD_COPYSET(&clientsReadable, &savedClientsReadable);
36905b261ecSmrg	for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++)
37005b261ecSmrg	{
37105b261ecSmrg	    int client_priority, client_index;
37205b261ecSmrg
37305b261ecSmrg	    curclient = XFD_FD(&savedClientsReadable, i);
37405b261ecSmrg	    client_index = GetConnectionTranslation(curclient);
37505b261ecSmrg#endif
37605b261ecSmrg#ifdef XSYNC
37705b261ecSmrg		/*  We implement "strict" priorities.
37805b261ecSmrg		 *  Only the highest priority client is returned to
37905b261ecSmrg		 *  dix.  If multiple clients at the same priority are
38005b261ecSmrg		 *  ready, they are all returned.  This means that an
38105b261ecSmrg		 *  aggressive client could take over the server.
38205b261ecSmrg		 *  This was not considered a big problem because
38305b261ecSmrg		 *  aggressive clients can hose the server in so many
38405b261ecSmrg		 *  other ways :)
38505b261ecSmrg		 */
38605b261ecSmrg		client_priority = clients[client_index]->priority;
38705b261ecSmrg		if (nready == 0 || client_priority > highest_priority)
38805b261ecSmrg		{
38905b261ecSmrg		    /*  Either we found the first client, or we found
39005b261ecSmrg		     *  a client whose priority is greater than all others
39105b261ecSmrg		     *  that have been found so far.  Either way, we want
39205b261ecSmrg		     *  to initialize the list of clients to contain just
39305b261ecSmrg		     *  this client.
39405b261ecSmrg		     */
39505b261ecSmrg		    pClientsReady[0] = client_index;
39605b261ecSmrg		    highest_priority = client_priority;
39705b261ecSmrg		    nready = 1;
39805b261ecSmrg		}
39905b261ecSmrg		/*  the following if makes sure that multiple same-priority
40005b261ecSmrg		 *  clients get batched together
40105b261ecSmrg		 */
40205b261ecSmrg		else if (client_priority == highest_priority)
40305b261ecSmrg#endif
40405b261ecSmrg		{
40505b261ecSmrg		    pClientsReady[nready++] = client_index;
40605b261ecSmrg		}
40705b261ecSmrg#ifndef WIN32
40805b261ecSmrg		clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient);
40905b261ecSmrg	    }
41005b261ecSmrg#else
41105b261ecSmrg	    FD_CLR(curclient, &clientsReadable);
41205b261ecSmrg#endif
41305b261ecSmrg	}
41405b261ecSmrg    }
41505b261ecSmrg    return nready;
41605b261ecSmrg}
41705b261ecSmrg
41805b261ecSmrg#if 0
41905b261ecSmrg/*
42005b261ecSmrg * This is not always a macro.
42105b261ecSmrg */
42205b261ecSmrgANYSET(FdMask *src)
42305b261ecSmrg{
42405b261ecSmrg    int i;
42505b261ecSmrg
42605b261ecSmrg    for (i=0; i<mskcnt; i++)
42705b261ecSmrg	if (src[ i ])
42805b261ecSmrg	    return (TRUE);
42905b261ecSmrg    return (FALSE);
43005b261ecSmrg}
43105b261ecSmrg#endif
43205b261ecSmrg
43305b261ecSmrg/* If time has rewound, re-run every affected timer.
43405b261ecSmrg * Timers might drop out of the list, so we have to restart every time. */
43505b261ecSmrgstatic void
43605b261ecSmrgCheckAllTimers(void)
43705b261ecSmrg{
43805b261ecSmrg    OsTimerPtr timer;
43905b261ecSmrg    CARD32 now;
44005b261ecSmrg
44105b261ecSmrgstart:
44205b261ecSmrg    now = GetTimeInMillis();
44305b261ecSmrg
44405b261ecSmrg    for (timer = timers; timer; timer = timer->next) {
44505b261ecSmrg        if (timer->expires - now > timer->delta + 250) {
44605b261ecSmrg            TimerForce(timer);
44705b261ecSmrg            goto start;
44805b261ecSmrg        }
44905b261ecSmrg    }
45005b261ecSmrg}
45105b261ecSmrg
45205b261ecSmrgstatic void
45305b261ecSmrgDoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev)
45405b261ecSmrg{
45505b261ecSmrg    CARD32 newTime;
45605b261ecSmrg
45705b261ecSmrg    *prev = timer->next;
45805b261ecSmrg    timer->next = NULL;
45905b261ecSmrg    newTime = (*timer->callback)(timer, now, timer->arg);
46005b261ecSmrg    if (newTime)
46105b261ecSmrg	TimerSet(timer, 0, newTime, timer->callback, timer->arg);
46205b261ecSmrg}
46305b261ecSmrg
46405b261ecSmrg_X_EXPORT OsTimerPtr
46505b261ecSmrgTimerSet(OsTimerPtr timer, int flags, CARD32 millis,
46605b261ecSmrg    OsTimerCallback func, pointer arg)
46705b261ecSmrg{
46805b261ecSmrg    register OsTimerPtr *prev;
46905b261ecSmrg    CARD32 now = GetTimeInMillis();
47005b261ecSmrg
47105b261ecSmrg    if (!timer)
47205b261ecSmrg    {
47305b261ecSmrg	timer = (OsTimerPtr)xalloc(sizeof(struct _OsTimerRec));
47405b261ecSmrg	if (!timer)
47505b261ecSmrg	    return NULL;
47605b261ecSmrg    }
47705b261ecSmrg    else
47805b261ecSmrg    {
47905b261ecSmrg	for (prev = &timers; *prev; prev = &(*prev)->next)
48005b261ecSmrg	{
48105b261ecSmrg	    if (*prev == timer)
48205b261ecSmrg	    {
48305b261ecSmrg		*prev = timer->next;
48405b261ecSmrg		if (flags & TimerForceOld)
48505b261ecSmrg		    (void)(*timer->callback)(timer, now, timer->arg);
48605b261ecSmrg		break;
48705b261ecSmrg	    }
48805b261ecSmrg	}
48905b261ecSmrg    }
49005b261ecSmrg    if (!millis)
49105b261ecSmrg	return timer;
49205b261ecSmrg    if (flags & TimerAbsolute) {
49305b261ecSmrg        timer->delta = millis - now;
49405b261ecSmrg    }
49505b261ecSmrg    else {
49605b261ecSmrg        timer->delta = millis;
49705b261ecSmrg	millis += now;
49805b261ecSmrg    }
49905b261ecSmrg    timer->expires = millis;
50005b261ecSmrg    timer->callback = func;
50105b261ecSmrg    timer->arg = arg;
50205b261ecSmrg    if ((int) (millis - now) <= 0)
50305b261ecSmrg    {
50405b261ecSmrg	timer->next = NULL;
50505b261ecSmrg	millis = (*timer->callback)(timer, now, timer->arg);
50605b261ecSmrg	if (!millis)
50705b261ecSmrg	    return timer;
50805b261ecSmrg    }
50905b261ecSmrg    for (prev = &timers;
51005b261ecSmrg	 *prev && (int) ((*prev)->expires - millis) <= 0;
51105b261ecSmrg	 prev = &(*prev)->next)
51205b261ecSmrg        ;
51305b261ecSmrg    timer->next = *prev;
51405b261ecSmrg    *prev = timer;
51505b261ecSmrg    return timer;
51605b261ecSmrg}
51705b261ecSmrg
51805b261ecSmrgBool
51905b261ecSmrgTimerForce(OsTimerPtr timer)
52005b261ecSmrg{
52105b261ecSmrg    OsTimerPtr *prev;
52205b261ecSmrg
52305b261ecSmrg    for (prev = &timers; *prev; prev = &(*prev)->next)
52405b261ecSmrg    {
52505b261ecSmrg	if (*prev == timer)
52605b261ecSmrg	{
52705b261ecSmrg	    DoTimer(timer, GetTimeInMillis(), prev);
52805b261ecSmrg	    return TRUE;
52905b261ecSmrg	}
53005b261ecSmrg    }
53105b261ecSmrg    return FALSE;
53205b261ecSmrg}
53305b261ecSmrg
53405b261ecSmrg
53505b261ecSmrg_X_EXPORT void
53605b261ecSmrgTimerCancel(OsTimerPtr timer)
53705b261ecSmrg{
53805b261ecSmrg    OsTimerPtr *prev;
53905b261ecSmrg
54005b261ecSmrg    if (!timer)
54105b261ecSmrg	return;
54205b261ecSmrg    for (prev = &timers; *prev; prev = &(*prev)->next)
54305b261ecSmrg    {
54405b261ecSmrg	if (*prev == timer)
54505b261ecSmrg	{
54605b261ecSmrg	    *prev = timer->next;
54705b261ecSmrg	    break;
54805b261ecSmrg	}
54905b261ecSmrg    }
55005b261ecSmrg}
55105b261ecSmrg
55205b261ecSmrg_X_EXPORT void
55305b261ecSmrgTimerFree(OsTimerPtr timer)
55405b261ecSmrg{
55505b261ecSmrg    if (!timer)
55605b261ecSmrg	return;
55705b261ecSmrg    TimerCancel(timer);
55805b261ecSmrg    xfree(timer);
55905b261ecSmrg}
56005b261ecSmrg
56105b261ecSmrgvoid
56205b261ecSmrgTimerCheck(void)
56305b261ecSmrg{
56405b261ecSmrg    CARD32 now = GetTimeInMillis();
56505b261ecSmrg
56605b261ecSmrg    while (timers && (int) (timers->expires - now) <= 0)
56705b261ecSmrg	DoTimer(timers, now, &timers);
56805b261ecSmrg}
56905b261ecSmrg
57005b261ecSmrgvoid
57105b261ecSmrgTimerInit(void)
57205b261ecSmrg{
57305b261ecSmrg    OsTimerPtr timer;
57405b261ecSmrg
57505b261ecSmrg    while ((timer = timers))
57605b261ecSmrg    {
57705b261ecSmrg	timers = timer->next;
57805b261ecSmrg	xfree(timer);
57905b261ecSmrg    }
58005b261ecSmrg}
58105b261ecSmrg
58205b261ecSmrg#ifdef DPMSExtension
58305b261ecSmrg
58405b261ecSmrg#define DPMS_CHECK_MODE(mode,time)\
58505b261ecSmrg    if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
58605b261ecSmrg	DPMSSet(mode);
58705b261ecSmrg
58805b261ecSmrg#define DPMS_CHECK_TIMEOUT(time)\
58905b261ecSmrg    if (time > 0 && (time - timeout) > 0)\
59005b261ecSmrg	return time - timeout;
59105b261ecSmrg
59205b261ecSmrgstatic CARD32
59305b261ecSmrgNextDPMSTimeout(INT32 timeout)
59405b261ecSmrg{
59505b261ecSmrg    /*
59605b261ecSmrg     * Return the amount of time remaining until we should set
59705b261ecSmrg     * the next power level. Fallthroughs are intentional.
59805b261ecSmrg     */
59905b261ecSmrg    switch (DPMSPowerLevel)
60005b261ecSmrg    {
60105b261ecSmrg	case DPMSModeOn:
60205b261ecSmrg	    DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
60305b261ecSmrg
60405b261ecSmrg	case DPMSModeStandby:
60505b261ecSmrg	    DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
60605b261ecSmrg
60705b261ecSmrg	case DPMSModeSuspend:
60805b261ecSmrg	    DPMS_CHECK_TIMEOUT(DPMSOffTime)
60905b261ecSmrg
61005b261ecSmrg	default: /* DPMSModeOff */
61105b261ecSmrg	    return 0;
61205b261ecSmrg    }
61305b261ecSmrg}
61405b261ecSmrg#endif /* DPMSExtension */
61505b261ecSmrg
61605b261ecSmrgstatic CARD32
61705b261ecSmrgScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg)
61805b261ecSmrg{
61905b261ecSmrg    INT32 timeout      = now - lastDeviceEventTime.milliseconds;
62005b261ecSmrg    CARD32 nextTimeout = 0;
62105b261ecSmrg
62205b261ecSmrg#ifdef DPMSExtension
62305b261ecSmrg    /*
62405b261ecSmrg     * Check each mode lowest to highest, since a lower mode can
62505b261ecSmrg     * have the same timeout as a higher one.
62605b261ecSmrg     */
62705b261ecSmrg    if (DPMSEnabled)
62805b261ecSmrg    {
62905b261ecSmrg	DPMS_CHECK_MODE(DPMSModeOff,     DPMSOffTime)
63005b261ecSmrg	DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
63105b261ecSmrg	DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
63205b261ecSmrg
63305b261ecSmrg	nextTimeout = NextDPMSTimeout(timeout);
63405b261ecSmrg    }
63505b261ecSmrg
63605b261ecSmrg    /*
63705b261ecSmrg     * Only do the screensaver checks if we're not in a DPMS
63805b261ecSmrg     * power saving mode
63905b261ecSmrg     */
64005b261ecSmrg    if (DPMSPowerLevel != DPMSModeOn)
64105b261ecSmrg	return nextTimeout;
64205b261ecSmrg#endif /* DPMSExtension */
64305b261ecSmrg
64405b261ecSmrg    if (!ScreenSaverTime)
64505b261ecSmrg	return nextTimeout;
64605b261ecSmrg
64705b261ecSmrg    if (timeout < ScreenSaverTime)
64805b261ecSmrg    {
64905b261ecSmrg	return nextTimeout > 0 ?
65005b261ecSmrg		min(ScreenSaverTime - timeout, nextTimeout) :
65105b261ecSmrg		ScreenSaverTime - timeout;
65205b261ecSmrg    }
65305b261ecSmrg
65405b261ecSmrg    ResetOsBuffers(); /* not ideal, but better than nothing */
65505b261ecSmrg    SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive);
65605b261ecSmrg
65705b261ecSmrg    if (ScreenSaverInterval > 0)
65805b261ecSmrg    {
65905b261ecSmrg	nextTimeout = nextTimeout > 0 ?
66005b261ecSmrg		min(ScreenSaverInterval, nextTimeout) :
66105b261ecSmrg		ScreenSaverInterval;
66205b261ecSmrg    }
66305b261ecSmrg
66405b261ecSmrg    return nextTimeout;
66505b261ecSmrg}
66605b261ecSmrg
66705b261ecSmrgstatic OsTimerPtr ScreenSaverTimer = NULL;
66805b261ecSmrg
66905b261ecSmrgvoid
67005b261ecSmrgFreeScreenSaverTimer(void)
67105b261ecSmrg{
67205b261ecSmrg    if (ScreenSaverTimer) {
67305b261ecSmrg	TimerFree(ScreenSaverTimer);
67405b261ecSmrg	ScreenSaverTimer = NULL;
67505b261ecSmrg    }
67605b261ecSmrg}
67705b261ecSmrg
67805b261ecSmrgvoid
67905b261ecSmrgSetScreenSaverTimer(void)
68005b261ecSmrg{
68105b261ecSmrg    CARD32 timeout = 0;
68205b261ecSmrg
68305b261ecSmrg#ifdef DPMSExtension
68405b261ecSmrg    if (DPMSEnabled)
68505b261ecSmrg    {
68605b261ecSmrg	/*
68705b261ecSmrg	 * A higher DPMS level has a timeout that's either less
68805b261ecSmrg	 * than or equal to that of a lower DPMS level.
68905b261ecSmrg	 */
69005b261ecSmrg	if (DPMSStandbyTime > 0)
69105b261ecSmrg	    timeout = DPMSStandbyTime;
69205b261ecSmrg
69305b261ecSmrg	else if (DPMSSuspendTime > 0)
69405b261ecSmrg	    timeout = DPMSSuspendTime;
69505b261ecSmrg
69605b261ecSmrg	else if (DPMSOffTime > 0)
69705b261ecSmrg	    timeout = DPMSOffTime;
69805b261ecSmrg    }
69905b261ecSmrg#endif
70005b261ecSmrg
70105b261ecSmrg    if (ScreenSaverTime > 0)
70205b261ecSmrg    {
70305b261ecSmrg	timeout = timeout > 0 ?
70405b261ecSmrg		min(ScreenSaverTime, timeout) :
70505b261ecSmrg		ScreenSaverTime;
70605b261ecSmrg    }
70705b261ecSmrg
70805b261ecSmrg#ifdef SCREENSAVER
70905b261ecSmrg    if (timeout && !screenSaverSuspended) {
71005b261ecSmrg#else
71105b261ecSmrg    if (timeout) {
71205b261ecSmrg#endif
71305b261ecSmrg	ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
71405b261ecSmrg	                            ScreenSaverTimeoutExpire, NULL);
71505b261ecSmrg    }
71605b261ecSmrg    else if (ScreenSaverTimer) {
71705b261ecSmrg	FreeScreenSaverTimer();
71805b261ecSmrg    }
71905b261ecSmrg}
72005b261ecSmrg
721