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