1*4882a593Smuzhiyun /***********************************************************
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun Copyright 1987, 1998 The Open Group
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun Permission to use, copy, modify, distribute, and sell this software and its
6*4882a593Smuzhiyun documentation for any purpose is hereby granted without fee, provided that
7*4882a593Smuzhiyun the above copyright notice appear in all copies and that both that
8*4882a593Smuzhiyun copyright notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation.
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun all copies or substantial portions of the Software.
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17*4882a593Smuzhiyun OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18*4882a593Smuzhiyun AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19*4882a593Smuzhiyun CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun Except as contained in this notice, the name of The Open Group shall not be
22*4882a593Smuzhiyun used in advertising or otherwise to promote the sale, use or other dealings
23*4882a593Smuzhiyun in this Software without prior written authorization from The Open Group.
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun All Rights Reserved
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun Permission to use, copy, modify, and distribute this software and its
30*4882a593Smuzhiyun documentation for any purpose and without fee is hereby granted,
31*4882a593Smuzhiyun provided that the above copyright notice appear in all copies and that
32*4882a593Smuzhiyun both that copyright notice and this permission notice appear in
33*4882a593Smuzhiyun supporting documentation, and that the name of Digital not be
34*4882a593Smuzhiyun used in advertising or publicity pertaining to distribution of the
35*4882a593Smuzhiyun software without specific, written prior permission.
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38*4882a593Smuzhiyun ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39*4882a593Smuzhiyun DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40*4882a593Smuzhiyun ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41*4882a593Smuzhiyun WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42*4882a593Smuzhiyun ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43*4882a593Smuzhiyun SOFTWARE.
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun ******************************************************************/
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /*****************************************************************
48*4882a593Smuzhiyun * OS Dependent input routines:
49*4882a593Smuzhiyun *
50*4882a593Smuzhiyun * WaitForSomething
51*4882a593Smuzhiyun * TimerForce, TimerSet, TimerCheck, TimerFree
52*4882a593Smuzhiyun *
53*4882a593Smuzhiyun *****************************************************************/
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
56*4882a593Smuzhiyun #include <dix-config.h>
57*4882a593Smuzhiyun #endif
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun #ifdef WIN32
60*4882a593Smuzhiyun #include <X11/Xwinsock.h>
61*4882a593Smuzhiyun #endif
62*4882a593Smuzhiyun #include <X11/Xos.h> /* for strings, fcntl, time */
63*4882a593Smuzhiyun #include <errno.h>
64*4882a593Smuzhiyun #include <stdio.h>
65*4882a593Smuzhiyun #include <X11/X.h>
66*4882a593Smuzhiyun #include "misc.h"
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun #include "osdep.h"
69*4882a593Smuzhiyun #include "dixstruct.h"
70*4882a593Smuzhiyun #include "opaque.h"
71*4882a593Smuzhiyun #ifdef DPMSExtension
72*4882a593Smuzhiyun #include "dpmsproc.h"
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun #include "busfault.h"
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun #ifdef WIN32
77*4882a593Smuzhiyun /* Error codes from windows sockets differ from fileio error codes */
78*4882a593Smuzhiyun #undef EINTR
79*4882a593Smuzhiyun #define EINTR WSAEINTR
80*4882a593Smuzhiyun #undef EINVAL
81*4882a593Smuzhiyun #define EINVAL WSAEINVAL
82*4882a593Smuzhiyun #undef EBADF
83*4882a593Smuzhiyun #define EBADF WSAENOTSOCK
84*4882a593Smuzhiyun /* Windows select does not set errno. Use GetErrno as wrapper for
85*4882a593Smuzhiyun WSAGetLastError */
86*4882a593Smuzhiyun #define GetErrno WSAGetLastError
87*4882a593Smuzhiyun #else
88*4882a593Smuzhiyun /* This is just a fallback to errno to hide the differences between unix and
89*4882a593Smuzhiyun Windows in the code */
90*4882a593Smuzhiyun #define GetErrno() errno
91*4882a593Smuzhiyun #endif
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #ifdef DPMSExtension
94*4882a593Smuzhiyun #include <X11/extensions/dpmsconst.h>
95*4882a593Smuzhiyun #endif
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun struct _OsTimerRec {
98*4882a593Smuzhiyun struct xorg_list list;
99*4882a593Smuzhiyun CARD32 expires;
100*4882a593Smuzhiyun CARD32 delta;
101*4882a593Smuzhiyun OsTimerCallback callback;
102*4882a593Smuzhiyun void *arg;
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun static void DoTimer(OsTimerPtr timer, CARD32 now);
106*4882a593Smuzhiyun static void DoTimers(CARD32 now);
107*4882a593Smuzhiyun static void CheckAllTimers(void);
108*4882a593Smuzhiyun static volatile struct xorg_list timers;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun static inline OsTimerPtr
first_timer(void)111*4882a593Smuzhiyun first_timer(void)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun /* inline xorg_list_is_empty which can't handle volatile */
114*4882a593Smuzhiyun if (timers.next == &timers)
115*4882a593Smuzhiyun return NULL;
116*4882a593Smuzhiyun return xorg_list_first_entry(&timers, struct _OsTimerRec, list);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun * Compute timeout until next timer, running
121*4882a593Smuzhiyun * any expired timers
122*4882a593Smuzhiyun */
123*4882a593Smuzhiyun static int
check_timers(void)124*4882a593Smuzhiyun check_timers(void)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun OsTimerPtr timer;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if ((timer = first_timer()) != NULL) {
129*4882a593Smuzhiyun CARD32 now = GetTimeInMillis();
130*4882a593Smuzhiyun int timeout = timer->expires - now;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (timeout <= 0) {
133*4882a593Smuzhiyun DoTimers(now);
134*4882a593Smuzhiyun } else {
135*4882a593Smuzhiyun /* Make sure the timeout is sane */
136*4882a593Smuzhiyun if (timeout < timer->delta + 250)
137*4882a593Smuzhiyun return timeout;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* time has rewound. reset the timers. */
140*4882a593Smuzhiyun CheckAllTimers();
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun return 0;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun return -1;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun /*****************
149*4882a593Smuzhiyun * WaitForSomething:
150*4882a593Smuzhiyun * Make the server suspend until there is
151*4882a593Smuzhiyun * 1. data from clients or
152*4882a593Smuzhiyun * 2. input events available or
153*4882a593Smuzhiyun * 3. ddx notices something of interest (graphics
154*4882a593Smuzhiyun * queue ready, etc.) or
155*4882a593Smuzhiyun * 4. clients that have buffered replies/events are ready
156*4882a593Smuzhiyun *
157*4882a593Smuzhiyun * If the time between INPUT events is
158*4882a593Smuzhiyun * greater than ScreenSaverTime, the display is turned off (or
159*4882a593Smuzhiyun * saved, depending on the hardware). So, WaitForSomething()
160*4882a593Smuzhiyun * has to handle this also (that's why the select() has a timeout.
161*4882a593Smuzhiyun * For more info on ClientsWithInput, see ReadRequestFromClient().
162*4882a593Smuzhiyun * pClientsReady is an array to store ready client->index values into.
163*4882a593Smuzhiyun *****************/
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun Bool
WaitForSomething(Bool are_ready)166*4882a593Smuzhiyun WaitForSomething(Bool are_ready)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun int i;
169*4882a593Smuzhiyun int timeout;
170*4882a593Smuzhiyun int pollerr;
171*4882a593Smuzhiyun static Bool were_ready;
172*4882a593Smuzhiyun Bool timer_is_running;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun timer_is_running = were_ready;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun if (were_ready && !are_ready) {
177*4882a593Smuzhiyun timer_is_running = FALSE;
178*4882a593Smuzhiyun SmartScheduleStopTimer();
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun were_ready = FALSE;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun #ifdef BUSFAULT
184*4882a593Smuzhiyun busfault_check();
185*4882a593Smuzhiyun #endif
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /* We need a while loop here to handle
188*4882a593Smuzhiyun crashed connections and the screen saver timeout */
189*4882a593Smuzhiyun while (1) {
190*4882a593Smuzhiyun /* deal with any blocked jobs */
191*4882a593Smuzhiyun if (workQueue) {
192*4882a593Smuzhiyun ProcessWorkQueue();
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun timeout = check_timers();
196*4882a593Smuzhiyun are_ready = clients_are_ready();
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if (are_ready)
199*4882a593Smuzhiyun timeout = 0;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun BlockHandler(&timeout);
202*4882a593Smuzhiyun if (NewOutputPending)
203*4882a593Smuzhiyun FlushAllOutput();
204*4882a593Smuzhiyun /* keep this check close to select() call to minimize race */
205*4882a593Smuzhiyun if (dispatchException)
206*4882a593Smuzhiyun i = -1;
207*4882a593Smuzhiyun else
208*4882a593Smuzhiyun i = ospoll_wait(server_poll, timeout);
209*4882a593Smuzhiyun pollerr = GetErrno();
210*4882a593Smuzhiyun WakeupHandler(i);
211*4882a593Smuzhiyun if (i <= 0) { /* An error or timeout occurred */
212*4882a593Smuzhiyun if (dispatchException)
213*4882a593Smuzhiyun return FALSE;
214*4882a593Smuzhiyun if (i < 0) {
215*4882a593Smuzhiyun if (pollerr != EINTR && !ETEST(pollerr)) {
216*4882a593Smuzhiyun ErrorF("WaitForSomething(): poll: %s\n",
217*4882a593Smuzhiyun strerror(pollerr));
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun } else
221*4882a593Smuzhiyun are_ready = clients_are_ready();
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (InputCheckPending())
224*4882a593Smuzhiyun return FALSE;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun if (are_ready) {
227*4882a593Smuzhiyun were_ready = TRUE;
228*4882a593Smuzhiyun if (!timer_is_running)
229*4882a593Smuzhiyun SmartScheduleStartTimer();
230*4882a593Smuzhiyun return TRUE;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun void
AdjustWaitForDelay(void * waitTime,int newdelay)236*4882a593Smuzhiyun AdjustWaitForDelay(void *waitTime, int newdelay)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun int *timeoutp = waitTime;
239*4882a593Smuzhiyun int timeout = *timeoutp;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (timeout < 0 || newdelay < timeout)
242*4882a593Smuzhiyun *timeoutp = newdelay;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
timer_pending(OsTimerPtr timer)245*4882a593Smuzhiyun static inline Bool timer_pending(OsTimerPtr timer) {
246*4882a593Smuzhiyun return !xorg_list_is_empty(&timer->list);
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /* If time has rewound, re-run every affected timer.
250*4882a593Smuzhiyun * Timers might drop out of the list, so we have to restart every time. */
251*4882a593Smuzhiyun static void
CheckAllTimers(void)252*4882a593Smuzhiyun CheckAllTimers(void)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun OsTimerPtr timer;
255*4882a593Smuzhiyun CARD32 now;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun input_lock();
258*4882a593Smuzhiyun start:
259*4882a593Smuzhiyun now = GetTimeInMillis();
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun xorg_list_for_each_entry(timer, &timers, list) {
262*4882a593Smuzhiyun if (timer->expires - now > timer->delta + 250) {
263*4882a593Smuzhiyun DoTimer(timer, now);
264*4882a593Smuzhiyun goto start;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun input_unlock();
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun static void
DoTimer(OsTimerPtr timer,CARD32 now)271*4882a593Smuzhiyun DoTimer(OsTimerPtr timer, CARD32 now)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun CARD32 newTime;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun xorg_list_del(&timer->list);
276*4882a593Smuzhiyun newTime = (*timer->callback) (timer, now, timer->arg);
277*4882a593Smuzhiyun if (newTime)
278*4882a593Smuzhiyun TimerSet(timer, 0, newTime, timer->callback, timer->arg);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun static void
DoTimers(CARD32 now)282*4882a593Smuzhiyun DoTimers(CARD32 now)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun OsTimerPtr timer;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun input_lock();
287*4882a593Smuzhiyun while ((timer = first_timer())) {
288*4882a593Smuzhiyun if ((int) (timer->expires - now) > 0)
289*4882a593Smuzhiyun break;
290*4882a593Smuzhiyun DoTimer(timer, now);
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun input_unlock();
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun OsTimerPtr
TimerSet(OsTimerPtr timer,int flags,CARD32 millis,OsTimerCallback func,void * arg)296*4882a593Smuzhiyun TimerSet(OsTimerPtr timer, int flags, CARD32 millis,
297*4882a593Smuzhiyun OsTimerCallback func, void *arg)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun OsTimerPtr existing, tmp;
300*4882a593Smuzhiyun CARD32 now = GetTimeInMillis();
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (!timer) {
303*4882a593Smuzhiyun timer = calloc(1, sizeof(struct _OsTimerRec));
304*4882a593Smuzhiyun if (!timer)
305*4882a593Smuzhiyun return NULL;
306*4882a593Smuzhiyun xorg_list_init(&timer->list);
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun else {
309*4882a593Smuzhiyun input_lock();
310*4882a593Smuzhiyun if (timer_pending(timer)) {
311*4882a593Smuzhiyun xorg_list_del(&timer->list);
312*4882a593Smuzhiyun if (flags & TimerForceOld)
313*4882a593Smuzhiyun (void) (*timer->callback) (timer, now, timer->arg);
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun input_unlock();
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun if (!millis)
318*4882a593Smuzhiyun return timer;
319*4882a593Smuzhiyun if (flags & TimerAbsolute) {
320*4882a593Smuzhiyun timer->delta = millis - now;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun else {
323*4882a593Smuzhiyun timer->delta = millis;
324*4882a593Smuzhiyun millis += now;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun timer->expires = millis;
327*4882a593Smuzhiyun timer->callback = func;
328*4882a593Smuzhiyun timer->arg = arg;
329*4882a593Smuzhiyun input_lock();
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun /* Sort into list */
332*4882a593Smuzhiyun xorg_list_for_each_entry_safe(existing, tmp, &timers, list)
333*4882a593Smuzhiyun if ((int) (existing->expires - millis) > 0)
334*4882a593Smuzhiyun break;
335*4882a593Smuzhiyun /* This even works at the end of the list -- existing->list will be timers */
336*4882a593Smuzhiyun xorg_list_add(&timer->list, existing->list.prev);
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun /* Check to see if the timer is ready to run now */
339*4882a593Smuzhiyun if ((int) (millis - now) <= 0)
340*4882a593Smuzhiyun DoTimer(timer, now);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun input_unlock();
343*4882a593Smuzhiyun return timer;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun Bool
TimerForce(OsTimerPtr timer)347*4882a593Smuzhiyun TimerForce(OsTimerPtr timer)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun int pending;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun input_lock();
352*4882a593Smuzhiyun pending = timer_pending(timer);
353*4882a593Smuzhiyun if (pending)
354*4882a593Smuzhiyun DoTimer(timer, GetTimeInMillis());
355*4882a593Smuzhiyun input_unlock();
356*4882a593Smuzhiyun return pending;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun void
TimerCancel(OsTimerPtr timer)360*4882a593Smuzhiyun TimerCancel(OsTimerPtr timer)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun if (!timer)
363*4882a593Smuzhiyun return;
364*4882a593Smuzhiyun input_lock();
365*4882a593Smuzhiyun xorg_list_del(&timer->list);
366*4882a593Smuzhiyun input_unlock();
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun void
TimerFree(OsTimerPtr timer)370*4882a593Smuzhiyun TimerFree(OsTimerPtr timer)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun if (!timer)
373*4882a593Smuzhiyun return;
374*4882a593Smuzhiyun TimerCancel(timer);
375*4882a593Smuzhiyun free(timer);
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun void
TimerCheck(void)379*4882a593Smuzhiyun TimerCheck(void)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun DoTimers(GetTimeInMillis());
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun void
TimerInit(void)385*4882a593Smuzhiyun TimerInit(void)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun static Bool been_here;
388*4882a593Smuzhiyun OsTimerPtr timer, tmp;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if (!been_here) {
391*4882a593Smuzhiyun been_here = TRUE;
392*4882a593Smuzhiyun xorg_list_init((struct xorg_list*) &timers);
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun xorg_list_for_each_entry_safe(timer, tmp, &timers, list) {
396*4882a593Smuzhiyun xorg_list_del(&timer->list);
397*4882a593Smuzhiyun free(timer);
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun #ifdef DPMSExtension
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun #define DPMS_CHECK_MODE(mode,time)\
404*4882a593Smuzhiyun if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\
405*4882a593Smuzhiyun DPMSSet(serverClient, mode);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun #define DPMS_CHECK_TIMEOUT(time)\
408*4882a593Smuzhiyun if (time > 0 && (time - timeout) > 0)\
409*4882a593Smuzhiyun return time - timeout;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun static CARD32
NextDPMSTimeout(INT32 timeout)412*4882a593Smuzhiyun NextDPMSTimeout(INT32 timeout)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun /*
415*4882a593Smuzhiyun * Return the amount of time remaining until we should set
416*4882a593Smuzhiyun * the next power level. Fallthroughs are intentional.
417*4882a593Smuzhiyun */
418*4882a593Smuzhiyun switch (DPMSPowerLevel) {
419*4882a593Smuzhiyun case DPMSModeOn:
420*4882a593Smuzhiyun DPMS_CHECK_TIMEOUT(DPMSStandbyTime)
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun case DPMSModeStandby:
423*4882a593Smuzhiyun DPMS_CHECK_TIMEOUT(DPMSSuspendTime)
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun case DPMSModeSuspend:
426*4882a593Smuzhiyun DPMS_CHECK_TIMEOUT(DPMSOffTime)
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun default: /* DPMSModeOff */
429*4882a593Smuzhiyun return 0;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun #endif /* DPMSExtension */
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun static CARD32
ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,void * arg)435*4882a593Smuzhiyun ScreenSaverTimeoutExpire(OsTimerPtr timer, CARD32 now, void *arg)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun INT32 timeout = now - LastEventTime(XIAllDevices).milliseconds;
438*4882a593Smuzhiyun CARD32 nextTimeout = 0;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun #ifdef DPMSExtension
441*4882a593Smuzhiyun /*
442*4882a593Smuzhiyun * Check each mode lowest to highest, since a lower mode can
443*4882a593Smuzhiyun * have the same timeout as a higher one.
444*4882a593Smuzhiyun */
445*4882a593Smuzhiyun if (DPMSEnabled) {
446*4882a593Smuzhiyun DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime)
447*4882a593Smuzhiyun DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime)
448*4882a593Smuzhiyun DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime)
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun nextTimeout = NextDPMSTimeout(timeout);
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun /*
454*4882a593Smuzhiyun * Only do the screensaver checks if we're not in a DPMS
455*4882a593Smuzhiyun * power saving mode
456*4882a593Smuzhiyun */
457*4882a593Smuzhiyun if (DPMSPowerLevel != DPMSModeOn)
458*4882a593Smuzhiyun return nextTimeout;
459*4882a593Smuzhiyun #endif /* DPMSExtension */
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun if (!ScreenSaverTime)
462*4882a593Smuzhiyun return nextTimeout;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (timeout < ScreenSaverTime) {
465*4882a593Smuzhiyun return nextTimeout > 0 ?
466*4882a593Smuzhiyun min(ScreenSaverTime - timeout, nextTimeout) :
467*4882a593Smuzhiyun ScreenSaverTime - timeout;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun ResetOsBuffers(); /* not ideal, but better than nothing */
471*4882a593Smuzhiyun dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun if (ScreenSaverInterval > 0) {
474*4882a593Smuzhiyun nextTimeout = nextTimeout > 0 ?
475*4882a593Smuzhiyun min(ScreenSaverInterval, nextTimeout) : ScreenSaverInterval;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun return nextTimeout;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun static OsTimerPtr ScreenSaverTimer = NULL;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun void
FreeScreenSaverTimer(void)484*4882a593Smuzhiyun FreeScreenSaverTimer(void)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun if (ScreenSaverTimer) {
487*4882a593Smuzhiyun TimerFree(ScreenSaverTimer);
488*4882a593Smuzhiyun ScreenSaverTimer = NULL;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun void
SetScreenSaverTimer(void)493*4882a593Smuzhiyun SetScreenSaverTimer(void)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun CARD32 timeout = 0;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun #ifdef DPMSExtension
498*4882a593Smuzhiyun if (DPMSEnabled) {
499*4882a593Smuzhiyun /*
500*4882a593Smuzhiyun * A higher DPMS level has a timeout that's either less
501*4882a593Smuzhiyun * than or equal to that of a lower DPMS level.
502*4882a593Smuzhiyun */
503*4882a593Smuzhiyun if (DPMSStandbyTime > 0)
504*4882a593Smuzhiyun timeout = DPMSStandbyTime;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun else if (DPMSSuspendTime > 0)
507*4882a593Smuzhiyun timeout = DPMSSuspendTime;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun else if (DPMSOffTime > 0)
510*4882a593Smuzhiyun timeout = DPMSOffTime;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun #endif
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun if (ScreenSaverTime > 0) {
515*4882a593Smuzhiyun timeout = timeout > 0 ? min(ScreenSaverTime, timeout) : ScreenSaverTime;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun #ifdef SCREENSAVER
519*4882a593Smuzhiyun if (timeout && !screenSaverSuspended) {
520*4882a593Smuzhiyun #else
521*4882a593Smuzhiyun if (timeout) {
522*4882a593Smuzhiyun #endif
523*4882a593Smuzhiyun ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout,
524*4882a593Smuzhiyun ScreenSaverTimeoutExpire, NULL);
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun else if (ScreenSaverTimer) {
527*4882a593Smuzhiyun FreeScreenSaverTimer();
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun }
530