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
2505b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrg                        All Rights Reserved
2805b261ecSmrg
29f7df2e56SmrgPermission to use, copy, modify, and distribute this software and its
30f7df2e56Smrgdocumentation for any purpose and without fee is hereby granted,
3105b261ecSmrgprovided that the above copyright notice appear in all copies and that
32f7df2e56Smrgboth that copyright notice and this permission notice appear in
3305b261ecSmrgsupporting documentation, and that the name of Digital not be
3405b261ecSmrgused in advertising or publicity pertaining to distribution of the
35f7df2e56Smrgsoftware without specific, written prior permission.
3605b261ecSmrg
3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4305b261ecSmrgSOFTWARE.
4405b261ecSmrg
4505b261ecSmrg******************************************************************/
4605b261ecSmrg
4705b261ecSmrg/*****************************************************************
4805b261ecSmrg * OS Dependent input routines:
4905b261ecSmrg *
5005b261ecSmrg *  WaitForSomething
5105b261ecSmrg *  TimerForce, TimerSet, TimerCheck, TimerFree
5205b261ecSmrg *
5305b261ecSmrg *****************************************************************/
5405b261ecSmrg
555bd42952Smrg#include <X11/Xpoll.h>
565bd42952Smrg
5705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5805b261ecSmrg#include <dix-config.h>
5905b261ecSmrg#endif
6005b261ecSmrg
6105b261ecSmrg#ifdef WIN32
6205b261ecSmrg#include <X11/Xwinsock.h>
6305b261ecSmrg#endif
64f7df2e56Smrg#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 "dixstruct.h"
7205b261ecSmrg#include "opaque.h"
7305b261ecSmrg#ifdef DPMSExtension
7405b261ecSmrg#include "dpmsproc.h"
7505b261ecSmrg#endif
76f7df2e56Smrg#include "busfault.h"
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
86f7df2e56Smrg/* 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#ifdef DPMSExtension
966747b715Smrg#include <X11/extensions/dpmsconst.h>
9705b261ecSmrg#endif
9805b261ecSmrg
9905b261ecSmrgstruct _OsTimerRec {
1007e31ba66Smrg    struct xorg_list list;
101f7df2e56Smrg    CARD32 expires;
102f7df2e56Smrg    CARD32 delta;
103f7df2e56Smrg    OsTimerCallback callback;
104f7df2e56Smrg    void *arg;
10505b261ecSmrg};
10605b261ecSmrg
1077e31ba66Smrgstatic void DoTimer(OsTimerPtr timer, CARD32 now);
1087e31ba66Smrgstatic void DoTimers(CARD32 now);
10905b261ecSmrgstatic void CheckAllTimers(void);
1107e31ba66Smrgstatic volatile struct xorg_list timers;
1117e31ba66Smrg
1127e31ba66Smrgstatic inline OsTimerPtr
1137e31ba66Smrgfirst_timer(void)
1147e31ba66Smrg{
1157e31ba66Smrg    /* inline xorg_list_is_empty which can't handle volatile */
1167e31ba66Smrg    if (timers.next == &timers)
1177e31ba66Smrg        return NULL;
1187e31ba66Smrg    return xorg_list_first_entry(&timers, struct _OsTimerRec, list);
1197e31ba66Smrg}
1207e31ba66Smrg
1217e31ba66Smrg/*
1227e31ba66Smrg * Compute timeout until next timer, running
1237e31ba66Smrg * any expired timers
1247e31ba66Smrg */
1257e31ba66Smrgstatic int
1267e31ba66Smrgcheck_timers(void)
1277e31ba66Smrg{
1287e31ba66Smrg    OsTimerPtr timer;
1297e31ba66Smrg
1307e31ba66Smrg    if ((timer = first_timer()) != NULL) {
1317e31ba66Smrg        CARD32 now = GetTimeInMillis();
1327e31ba66Smrg        int timeout = timer->expires - now;
1337e31ba66Smrg
1347e31ba66Smrg        if (timeout <= 0) {
1357e31ba66Smrg            DoTimers(now);
1367e31ba66Smrg        } else {
1377e31ba66Smrg            /* Make sure the timeout is sane */
1387e31ba66Smrg            if (timeout < timer->delta + 250)
1397e31ba66Smrg                return timeout;
1407e31ba66Smrg
1417e31ba66Smrg            /* time has rewound.  reset the timers. */
1427e31ba66Smrg            CheckAllTimers();
1437e31ba66Smrg        }
1447e31ba66Smrg
1457e31ba66Smrg        return 0;
1467e31ba66Smrg    }
1477e31ba66Smrg    return -1;
1487e31ba66Smrg}
14905b261ecSmrg
15005b261ecSmrg/*****************
15105b261ecSmrg * WaitForSomething:
15205b261ecSmrg *     Make the server suspend until there is
15305b261ecSmrg *	1. data from clients or
15405b261ecSmrg *	2. input events available or
15505b261ecSmrg *	3. ddx notices something of interest (graphics
15605b261ecSmrg *	   queue ready, etc.) or
15705b261ecSmrg *	4. clients that have buffered replies/events are ready
15805b261ecSmrg *
15905b261ecSmrg *     If the time between INPUT events is
16005b261ecSmrg *     greater than ScreenSaverTime, the display is turned off (or
16105b261ecSmrg *     saved, depending on the hardware).  So, WaitForSomething()
16205b261ecSmrg *     has to handle this also (that's why the select() has a timeout.
16305b261ecSmrg *     For more info on ClientsWithInput, see ReadRequestFromClient().
16405b261ecSmrg *     pClientsReady is an array to store ready client->index values into.
16505b261ecSmrg *****************/
16605b261ecSmrg
1677e31ba66SmrgBool
1687e31ba66SmrgWaitForSomething(Bool are_ready)
16905b261ecSmrg{
17005b261ecSmrg    int i;
1717e31ba66Smrg    int timeout;
1727e31ba66Smrg    int pollerr;
1737e31ba66Smrg    static Bool were_ready;
1747e31ba66Smrg    Bool timer_is_running;
1757e31ba66Smrg
1767e31ba66Smrg    timer_is_running = were_ready;
1777e31ba66Smrg
1787e31ba66Smrg    if (were_ready && !are_ready) {
1797e31ba66Smrg        timer_is_running = FALSE;
1809ace9065Smrg        SmartScheduleStopTimer();
1817e31ba66Smrg    }
1827e31ba66Smrg
1837e31ba66Smrg    were_ready = FALSE;
1849ace9065Smrg
185f7df2e56Smrg#ifdef BUSFAULT
186f7df2e56Smrg    busfault_check();
187f7df2e56Smrg#endif
188f7df2e56Smrg
189f7df2e56Smrg    /* We need a while loop here to handle
19005b261ecSmrg       crashed connections and the screen saver timeout */
191f7df2e56Smrg    while (1) {
192f7df2e56Smrg        /* deal with any blocked jobs */
1937e31ba66Smrg        if (workQueue) {
194f7df2e56Smrg            ProcessWorkQueue();
195f7df2e56Smrg        }
196f7df2e56Smrg
1977e31ba66Smrg        timeout = check_timers();
1987e31ba66Smrg        are_ready = clients_are_ready();
19905b261ecSmrg
2007e31ba66Smrg        if (are_ready)
2017e31ba66Smrg            timeout = 0;
2027e31ba66Smrg
2037e31ba66Smrg        BlockHandler(&timeout);
204f7df2e56Smrg        if (NewOutputPending)
205f7df2e56Smrg            FlushAllOutput();
206f7df2e56Smrg        /* keep this check close to select() call to minimize race */
207f7df2e56Smrg        if (dispatchException)
208f7df2e56Smrg            i = -1;
2097e31ba66Smrg        else
2107e31ba66Smrg            i = ospoll_wait(server_poll, timeout);
2117e31ba66Smrg        pollerr = GetErrno();
2127e31ba66Smrg        WakeupHandler(i);
213f7df2e56Smrg        if (i <= 0) {           /* An error or timeout occurred */
214f7df2e56Smrg            if (dispatchException)
2157e31ba66Smrg                return FALSE;
216f7df2e56Smrg            if (i < 0) {
2177e31ba66Smrg                if (pollerr != EINTR && !ETEST(pollerr)) {
2187e31ba66Smrg                    ErrorF("WaitForSomething(): poll: %s\n",
2197e31ba66Smrg                           strerror(pollerr));
220f7df2e56Smrg                }
221f7df2e56Smrg            }
2227e31ba66Smrg        } else
2237e31ba66Smrg            are_ready = clients_are_ready();
224f7df2e56Smrg
2257e31ba66Smrg        if (InputCheckPending())
2267e31ba66Smrg            return FALSE;
22705b261ecSmrg
2287e31ba66Smrg        if (are_ready) {
2297e31ba66Smrg            were_ready = TRUE;
2307e31ba66Smrg            if (!timer_is_running)
2317e31ba66Smrg                SmartScheduleStartTimer();
2327e31ba66Smrg            return TRUE;
233f7df2e56Smrg        }
23405b261ecSmrg    }
2357e31ba66Smrg}
23605b261ecSmrg
2377e31ba66Smrgvoid
2387e31ba66SmrgAdjustWaitForDelay(void *waitTime, int newdelay)
2397e31ba66Smrg{
2407e31ba66Smrg    int *timeoutp = waitTime;
2417e31ba66Smrg    int timeout = *timeoutp;
2429ace9065Smrg
2437e31ba66Smrg    if (timeout < 0 || newdelay < timeout)
2447e31ba66Smrg        *timeoutp = newdelay;
2457e31ba66Smrg}
2469ace9065Smrg
2477e31ba66Smrgstatic inline Bool timer_pending(OsTimerPtr timer) {
2487e31ba66Smrg    return !xorg_list_is_empty(&timer->list);
24905b261ecSmrg}
25005b261ecSmrg
25105b261ecSmrg/* If time has rewound, re-run every affected timer.
25205b261ecSmrg * Timers might drop out of the list, so we have to restart every time. */
25305b261ecSmrgstatic void
25405b261ecSmrgCheckAllTimers(void)
25505b261ecSmrg{
25605b261ecSmrg    OsTimerPtr timer;
25705b261ecSmrg    CARD32 now;
25805b261ecSmrg
2597e31ba66Smrg    input_lock();
260f7df2e56Smrg start:
26105b261ecSmrg    now = GetTimeInMillis();
26205b261ecSmrg
2637e31ba66Smrg    xorg_list_for_each_entry(timer, &timers, list) {
26405b261ecSmrg        if (timer->expires - now > timer->delta + 250) {
2657e31ba66Smrg            DoTimer(timer, now);
26605b261ecSmrg            goto start;
26705b261ecSmrg        }
26805b261ecSmrg    }
2697e31ba66Smrg    input_unlock();
27005b261ecSmrg}
27105b261ecSmrg
27205b261ecSmrgstatic void
2737e31ba66SmrgDoTimer(OsTimerPtr timer, CARD32 now)
27405b261ecSmrg{
27505b261ecSmrg    CARD32 newTime;
27605b261ecSmrg
2777e31ba66Smrg    xorg_list_del(&timer->list);
278f7df2e56Smrg    newTime = (*timer->callback) (timer, now, timer->arg);
27905b261ecSmrg    if (newTime)
280f7df2e56Smrg        TimerSet(timer, 0, newTime, timer->callback, timer->arg);
28105b261ecSmrg}
28205b261ecSmrg
2837e31ba66Smrgstatic void
2847e31ba66SmrgDoTimers(CARD32 now)
2857e31ba66Smrg{
2867e31ba66Smrg    OsTimerPtr  timer;
2877e31ba66Smrg
2887e31ba66Smrg    input_lock();
2897e31ba66Smrg    while ((timer = first_timer())) {
2907e31ba66Smrg        if ((int) (timer->expires - now) > 0)
2917e31ba66Smrg            break;
2927e31ba66Smrg        DoTimer(timer, now);
2937e31ba66Smrg    }
2947e31ba66Smrg    input_unlock();
2957e31ba66Smrg}
2967e31ba66Smrg
2976747b715SmrgOsTimerPtr
298f7df2e56SmrgTimerSet(OsTimerPtr timer, int flags, CARD32 millis,
299f7df2e56Smrg         OsTimerCallback func, void *arg)
30005b261ecSmrg{
3015a112b11Smrg    OsTimerPtr existing;
30205b261ecSmrg    CARD32 now = GetTimeInMillis();
30305b261ecSmrg
304f7df2e56Smrg    if (!timer) {
3057e31ba66Smrg        timer = calloc(1, sizeof(struct _OsTimerRec));
306f7df2e56Smrg        if (!timer)
307f7df2e56Smrg            return NULL;
3087e31ba66Smrg        xorg_list_init(&timer->list);
30905b261ecSmrg    }
310f7df2e56Smrg    else {
3117e31ba66Smrg        input_lock();
3127e31ba66Smrg        if (timer_pending(timer)) {
3137e31ba66Smrg            xorg_list_del(&timer->list);
3147e31ba66Smrg            if (flags & TimerForceOld)
3157e31ba66Smrg                (void) (*timer->callback) (timer, now, timer->arg);
316f7df2e56Smrg        }
3177e31ba66Smrg        input_unlock();
31805b261ecSmrg    }
31905b261ecSmrg    if (!millis)
320f7df2e56Smrg        return timer;
32105b261ecSmrg    if (flags & TimerAbsolute) {
32205b261ecSmrg        timer->delta = millis - now;
32305b261ecSmrg    }
32405b261ecSmrg    else {
32505b261ecSmrg        timer->delta = millis;
326f7df2e56Smrg        millis += now;
32705b261ecSmrg    }
32805b261ecSmrg    timer->expires = millis;
32905b261ecSmrg    timer->callback = func;
33005b261ecSmrg    timer->arg = arg;
3317e31ba66Smrg    input_lock();
3327e31ba66Smrg
3337e31ba66Smrg    /* Sort into list */
3345a112b11Smrg    xorg_list_for_each_entry(existing, &timers, list)
3357e31ba66Smrg        if ((int) (existing->expires - millis) > 0)
3367e31ba66Smrg            break;
3377e31ba66Smrg    /* This even works at the end of the list -- existing->list will be timers */
3385a112b11Smrg    xorg_list_append(&timer->list, &existing->list);
3397e31ba66Smrg
3407e31ba66Smrg    /* Check to see if the timer is ready to run now */
3417e31ba66Smrg    if ((int) (millis - now) <= 0)
3427e31ba66Smrg        DoTimer(timer, now);
3437e31ba66Smrg
3447e31ba66Smrg    input_unlock();
34505b261ecSmrg    return timer;
34605b261ecSmrg}
34705b261ecSmrg
34805b261ecSmrgBool
34905b261ecSmrgTimerForce(OsTimerPtr timer)
35005b261ecSmrg{
3517e31ba66Smrg    int pending;
3527e31ba66Smrg
3537e31ba66Smrg    input_lock();
3547e31ba66Smrg    pending = timer_pending(timer);
3557e31ba66Smrg    if (pending)
3567e31ba66Smrg        DoTimer(timer, GetTimeInMillis());
3577e31ba66Smrg    input_unlock();
3587e31ba66Smrg    return pending;
35905b261ecSmrg}
36005b261ecSmrg
3616747b715Smrgvoid
36205b261ecSmrgTimerCancel(OsTimerPtr timer)
36305b261ecSmrg{
36405b261ecSmrg    if (!timer)
365f7df2e56Smrg        return;
3667e31ba66Smrg    input_lock();
3677e31ba66Smrg    xorg_list_del(&timer->list);
3687e31ba66Smrg    input_unlock();
36905b261ecSmrg}
37005b261ecSmrg
3716747b715Smrgvoid
37205b261ecSmrgTimerFree(OsTimerPtr timer)
37305b261ecSmrg{
37405b261ecSmrg    if (!timer)
375f7df2e56Smrg        return;
37605b261ecSmrg    TimerCancel(timer);
3776747b715Smrg    free(timer);
37805b261ecSmrg}
37905b261ecSmrg
38005b261ecSmrgvoid
38105b261ecSmrgTimerCheck(void)
38205b261ecSmrg{
3837e31ba66Smrg    DoTimers(GetTimeInMillis());
38405b261ecSmrg}
38505b261ecSmrg
38605b261ecSmrgvoid
38705b261ecSmrgTimerInit(void)
38805b261ecSmrg{
3897e31ba66Smrg    static Bool been_here;
3907e31ba66Smrg    OsTimerPtr timer, tmp;
3917e31ba66Smrg
3927e31ba66Smrg    if (!been_here) {
3937e31ba66Smrg        been_here = TRUE;
3947e31ba66Smrg        xorg_list_init((struct xorg_list*) &timers);
3957e31ba66Smrg    }
39605b261ecSmrg
3977e31ba66Smrg    xorg_list_for_each_entry_safe(timer, tmp, &timers, list) {
3987e31ba66Smrg        xorg_list_del(&timer->list);
399f7df2e56Smrg        free(timer);
40005b261ecSmrg    }
40105b261ecSmrg}
40205b261ecSmrg
40305b261ecSmrg#ifdef DPMSExtension
40405b261ecSmrg
40505b261ecSmrg#define DPMS_CHECK_MODE(mode,time)\
40605b261ecSmrg    if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
4074642e01fSmrg	DPMSSet(serverClient, mode);
40805b261ecSmrg
40905b261ecSmrg#define DPMS_CHECK_TIMEOUT(time)\
41005b261ecSmrg    if (time > 0 && (time - timeout) > 0)\
41105b261ecSmrg	return time - timeout;
41205b261ecSmrg
41305b261ecSmrgstatic CARD32
41405b261ecSmrgNextDPMSTimeout(INT32 timeout)
41505b261ecSmrg{
41605b261ecSmrg    /*
41705b261ecSmrg     * Return the amount of time remaining until we should set
41805b261ecSmrg     * the next power level. Fallthroughs are intentional.
41905b261ecSmrg     */
420f7df2e56Smrg    switch (DPMSPowerLevel) {
421f7df2e56Smrg    case DPMSModeOn:
422f7df2e56Smrg        DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
423d566a54bSmrg        /* fallthrough */
424f7df2e56Smrg    case DPMSModeStandby:
425f7df2e56Smrg        DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
426d566a54bSmrg        /* fallthrough */
427f7df2e56Smrg    case DPMSModeSuspend:
428f7df2e56Smrg        DPMS_CHECK_TIMEOUT(DPMSOffTime)
429d566a54bSmrg        /* fallthrough */
430f7df2e56Smrg    default:                   /* DPMSModeOff */
431f7df2e56Smrg        return 0;
43205b261ecSmrg    }
43305b261ecSmrg}
434f7df2e56Smrg#endif                          /* DPMSExtension */
43505b261ecSmrg
43605b261ecSmrgstatic CARD32
437f7df2e56SmrgScreenSaverTimeoutExpire(OsTimerPtr timer, CARD32 now, void *arg)
43805b261ecSmrg{
439f7df2e56Smrg    INT32 timeout = now - LastEventTime(XIAllDevices).milliseconds;
44005b261ecSmrg    CARD32 nextTimeout = 0;
44105b261ecSmrg
44205b261ecSmrg#ifdef DPMSExtension
44305b261ecSmrg    /*
44405b261ecSmrg     * Check each mode lowest to highest, since a lower mode can
44505b261ecSmrg     * have the same timeout as a higher one.
44605b261ecSmrg     */
447f7df2e56Smrg    if (DPMSEnabled) {
448f7df2e56Smrg        DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime)
449f7df2e56Smrg            DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
450f7df2e56Smrg            DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
45105b261ecSmrg
452f7df2e56Smrg            nextTimeout = NextDPMSTimeout(timeout);
45305b261ecSmrg    }
45405b261ecSmrg
45505b261ecSmrg    /*
45605b261ecSmrg     * Only do the screensaver checks if we're not in a DPMS
45705b261ecSmrg     * power saving mode
45805b261ecSmrg     */
45905b261ecSmrg    if (DPMSPowerLevel != DPMSModeOn)
460f7df2e56Smrg        return nextTimeout;
461f7df2e56Smrg#endif                          /* DPMSExtension */
46205b261ecSmrg
46305b261ecSmrg    if (!ScreenSaverTime)
464f7df2e56Smrg        return nextTimeout;
46505b261ecSmrg
466f7df2e56Smrg    if (timeout < ScreenSaverTime) {
467f7df2e56Smrg        return nextTimeout > 0 ?
468f7df2e56Smrg            min(ScreenSaverTime - timeout, nextTimeout) :
469f7df2e56Smrg            ScreenSaverTime - timeout;
47005b261ecSmrg    }
47105b261ecSmrg
472f7df2e56Smrg    ResetOsBuffers();           /* not ideal, but better than nothing */
4734642e01fSmrg    dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive);
47405b261ecSmrg
475f7df2e56Smrg    if (ScreenSaverInterval > 0) {
476f7df2e56Smrg        nextTimeout = nextTimeout > 0 ?
477f7df2e56Smrg            min(ScreenSaverInterval, nextTimeout) : ScreenSaverInterval;
47805b261ecSmrg    }
47905b261ecSmrg
48005b261ecSmrg    return nextTimeout;
48105b261ecSmrg}
48205b261ecSmrg
48305b261ecSmrgstatic OsTimerPtr ScreenSaverTimer = NULL;
48405b261ecSmrg
48505b261ecSmrgvoid
48605b261ecSmrgFreeScreenSaverTimer(void)
48705b261ecSmrg{
48805b261ecSmrg    if (ScreenSaverTimer) {
489f7df2e56Smrg        TimerFree(ScreenSaverTimer);
490f7df2e56Smrg        ScreenSaverTimer = NULL;
49105b261ecSmrg    }
49205b261ecSmrg}
49305b261ecSmrg
49405b261ecSmrgvoid
49505b261ecSmrgSetScreenSaverTimer(void)
49605b261ecSmrg{
49705b261ecSmrg    CARD32 timeout = 0;
49805b261ecSmrg
49905b261ecSmrg#ifdef DPMSExtension
500f7df2e56Smrg    if (DPMSEnabled) {
501f7df2e56Smrg        /*
502f7df2e56Smrg         * A higher DPMS level has a timeout that's either less
503f7df2e56Smrg         * than or equal to that of a lower DPMS level.
504f7df2e56Smrg         */
505f7df2e56Smrg        if (DPMSStandbyTime > 0)
506f7df2e56Smrg            timeout = DPMSStandbyTime;
507f7df2e56Smrg
508f7df2e56Smrg        else if (DPMSSuspendTime > 0)
509f7df2e56Smrg            timeout = DPMSSuspendTime;
510f7df2e56Smrg
511f7df2e56Smrg        else if (DPMSOffTime > 0)
512f7df2e56Smrg            timeout = DPMSOffTime;
51305b261ecSmrg    }
51405b261ecSmrg#endif
51505b261ecSmrg
516f7df2e56Smrg    if (ScreenSaverTime > 0) {
517f7df2e56Smrg        timeout = timeout > 0 ? min(ScreenSaverTime, timeout) : ScreenSaverTime;
51805b261ecSmrg    }
51905b261ecSmrg
52005b261ecSmrg#ifdef SCREENSAVER
52105b261ecSmrg    if (timeout && !screenSaverSuspended) {
52205b261ecSmrg#else
52305b261ecSmrg    if (timeout) {
52405b261ecSmrg#endif
525f7df2e56Smrg        ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
526f7df2e56Smrg                                    ScreenSaverTimeoutExpire, NULL);
52705b261ecSmrg    }
52805b261ecSmrg    else if (ScreenSaverTimer) {
529f7df2e56Smrg        FreeScreenSaverTimer();
53005b261ecSmrg    }
53105b261ecSmrg}
532