1706f2543Smrg/*********************************************************** 2706f2543Smrg 3706f2543SmrgCopyright 1987, 1998 The Open Group 4706f2543Smrg 5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that 7706f2543Smrgthe above copyright notice appear in all copies and that both that 8706f2543Smrgcopyright notice and this permission notice appear in supporting 9706f2543Smrgdocumentation. 10706f2543Smrg 11706f2543SmrgThe above copyright notice and this permission notice shall be included in 12706f2543Smrgall copies or substantial portions of the Software. 13706f2543Smrg 14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20706f2543Smrg 21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be 22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings 23706f2543Smrgin this Software without prior written authorization from The Open Group. 24706f2543Smrg 25706f2543Smrg 26706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 27706f2543Smrg 28706f2543Smrg All Rights Reserved 29706f2543Smrg 30706f2543SmrgPermission to use, copy, modify, and distribute this software and its 31706f2543Smrgdocumentation for any purpose and without fee is hereby granted, 32706f2543Smrgprovided that the above copyright notice appear in all copies and that 33706f2543Smrgboth that copyright notice and this permission notice appear in 34706f2543Smrgsupporting documentation, and that the name of Digital not be 35706f2543Smrgused in advertising or publicity pertaining to distribution of the 36706f2543Smrgsoftware without specific, written prior permission. 37706f2543Smrg 38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44706f2543SmrgSOFTWARE. 45706f2543Smrg 46706f2543Smrg******************************************************************/ 47706f2543Smrg 48706f2543Smrg 49706f2543Smrg/***************************************************************** 50706f2543Smrg * OS Dependent input routines: 51706f2543Smrg * 52706f2543Smrg * WaitForSomething 53706f2543Smrg * TimerForce, TimerSet, TimerCheck, TimerFree 54706f2543Smrg * 55706f2543Smrg *****************************************************************/ 56706f2543Smrg 57706f2543Smrg#include <X11/Xpoll.h> 58706f2543Smrg 59706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 60706f2543Smrg#include <dix-config.h> 61706f2543Smrg#endif 62706f2543Smrg 63706f2543Smrg#ifdef WIN32 64706f2543Smrg#include <X11/Xwinsock.h> 65706f2543Smrg#endif 66706f2543Smrg#include <X11/Xos.h> /* for strings, fcntl, time */ 67706f2543Smrg#include <errno.h> 68706f2543Smrg#include <stdio.h> 69706f2543Smrg#include <X11/X.h> 70706f2543Smrg#include "misc.h" 71706f2543Smrg 72706f2543Smrg#include "osdep.h" 73706f2543Smrg#include "dixstruct.h" 74706f2543Smrg#include "opaque.h" 75706f2543Smrg#ifdef DPMSExtension 76706f2543Smrg#include "dpmsproc.h" 77706f2543Smrg#endif 78706f2543Smrg 79706f2543Smrg#ifdef WIN32 80706f2543Smrg/* Error codes from windows sockets differ from fileio error codes */ 81706f2543Smrg#undef EINTR 82706f2543Smrg#define EINTR WSAEINTR 83706f2543Smrg#undef EINVAL 84706f2543Smrg#define EINVAL WSAEINVAL 85706f2543Smrg#undef EBADF 86706f2543Smrg#define EBADF WSAENOTSOCK 87706f2543Smrg/* Windows select does not set errno. Use GetErrno as wrapper for 88706f2543Smrg WSAGetLastError */ 89706f2543Smrg#define GetErrno WSAGetLastError 90706f2543Smrg#else 91706f2543Smrg/* This is just a fallback to errno to hide the differences between unix and 92706f2543Smrg Windows in the code */ 93706f2543Smrg#define GetErrno() errno 94706f2543Smrg#endif 95706f2543Smrg 96706f2543Smrg/* like ffs, but uses fd_mask instead of int as argument, so it works 97706f2543Smrg when fd_mask is longer than an int, such as common 64-bit platforms */ 98706f2543Smrg/* modifications by raphael */ 99706f2543Smrgint 100706f2543Smrgmffs(fd_mask mask) 101706f2543Smrg{ 102706f2543Smrg int i; 103706f2543Smrg 104706f2543Smrg if (!mask) return 0; 105706f2543Smrg i = 1; 106706f2543Smrg while (!(mask & 1)) 107706f2543Smrg { 108706f2543Smrg i++; 109706f2543Smrg mask >>= 1; 110706f2543Smrg } 111706f2543Smrg return i; 112706f2543Smrg} 113706f2543Smrg 114706f2543Smrg#ifdef DPMSExtension 115706f2543Smrg#include <X11/extensions/dpmsconst.h> 116706f2543Smrg#endif 117706f2543Smrg 118706f2543Smrgstruct _OsTimerRec { 119706f2543Smrg OsTimerPtr next; 120706f2543Smrg CARD32 expires; 121706f2543Smrg CARD32 delta; 122706f2543Smrg OsTimerCallback callback; 123706f2543Smrg pointer arg; 124706f2543Smrg}; 125706f2543Smrg 126706f2543Smrgstatic void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev); 127706f2543Smrgstatic void CheckAllTimers(void); 128706f2543Smrgstatic OsTimerPtr timers = NULL; 129706f2543Smrg 130706f2543Smrg/***************** 131706f2543Smrg * WaitForSomething: 132706f2543Smrg * Make the server suspend until there is 133706f2543Smrg * 1. data from clients or 134706f2543Smrg * 2. input events available or 135706f2543Smrg * 3. ddx notices something of interest (graphics 136706f2543Smrg * queue ready, etc.) or 137706f2543Smrg * 4. clients that have buffered replies/events are ready 138706f2543Smrg * 139706f2543Smrg * If the time between INPUT events is 140706f2543Smrg * greater than ScreenSaverTime, the display is turned off (or 141706f2543Smrg * saved, depending on the hardware). So, WaitForSomething() 142706f2543Smrg * has to handle this also (that's why the select() has a timeout. 143706f2543Smrg * For more info on ClientsWithInput, see ReadRequestFromClient(). 144706f2543Smrg * pClientsReady is an array to store ready client->index values into. 145706f2543Smrg *****************/ 146706f2543Smrg 147706f2543Smrgint 148706f2543SmrgWaitForSomething(int *pClientsReady) 149706f2543Smrg{ 150706f2543Smrg int i; 151706f2543Smrg struct timeval waittime, *wt; 152706f2543Smrg INT32 timeout = 0; 153706f2543Smrg fd_set clientsReadable; 154706f2543Smrg fd_set clientsWritable; 155706f2543Smrg int curclient; 156706f2543Smrg int selecterr; 157706f2543Smrg static int nready; 158706f2543Smrg fd_set devicesReadable; 159706f2543Smrg CARD32 now = 0; 160706f2543Smrg Bool someReady = FALSE; 161706f2543Smrg 162706f2543Smrg FD_ZERO(&clientsReadable); 163706f2543Smrg 164706f2543Smrg if (nready) 165706f2543Smrg SmartScheduleStopTimer(); 166706f2543Smrg nready = 0; 167706f2543Smrg 168706f2543Smrg /* We need a while loop here to handle 169706f2543Smrg crashed connections and the screen saver timeout */ 170706f2543Smrg while (1) 171706f2543Smrg { 172706f2543Smrg /* deal with any blocked jobs */ 173706f2543Smrg if (workQueue) 174706f2543Smrg ProcessWorkQueue(); 175706f2543Smrg if (XFD_ANYSET (&ClientsWithInput)) 176706f2543Smrg { 177706f2543Smrg if (!SmartScheduleDisable) 178706f2543Smrg { 179706f2543Smrg someReady = TRUE; 180706f2543Smrg waittime.tv_sec = 0; 181706f2543Smrg waittime.tv_usec = 0; 182706f2543Smrg wt = &waittime; 183706f2543Smrg } 184706f2543Smrg else 185706f2543Smrg { 186706f2543Smrg XFD_COPYSET (&ClientsWithInput, &clientsReadable); 187706f2543Smrg break; 188706f2543Smrg } 189706f2543Smrg } 190706f2543Smrg if (someReady) 191706f2543Smrg { 192706f2543Smrg XFD_COPYSET(&AllSockets, &LastSelectMask); 193706f2543Smrg XFD_UNSET(&LastSelectMask, &ClientsWithInput); 194706f2543Smrg } 195706f2543Smrg else 196706f2543Smrg { 197706f2543Smrg wt = NULL; 198706f2543Smrg if (timers) 199706f2543Smrg { 200706f2543Smrg now = GetTimeInMillis(); 201706f2543Smrg timeout = timers->expires - now; 202706f2543Smrg if (timeout > 0 && timeout > timers->delta + 250) { 203706f2543Smrg /* time has rewound. reset the timers. */ 204706f2543Smrg CheckAllTimers(); 205706f2543Smrg } 206706f2543Smrg 207706f2543Smrg if (timers) { 208706f2543Smrg timeout = timers->expires - now; 209706f2543Smrg if (timeout < 0) 210706f2543Smrg timeout = 0; 211706f2543Smrg waittime.tv_sec = timeout / MILLI_PER_SECOND; 212706f2543Smrg waittime.tv_usec = (timeout % MILLI_PER_SECOND) * 213706f2543Smrg (1000000 / MILLI_PER_SECOND); 214706f2543Smrg wt = &waittime; 215706f2543Smrg } 216706f2543Smrg } 217706f2543Smrg XFD_COPYSET(&AllSockets, &LastSelectMask); 218706f2543Smrg } 219706f2543Smrg 220706f2543Smrg BlockHandler((pointer)&wt, (pointer)&LastSelectMask); 221706f2543Smrg if (NewOutputPending) 222706f2543Smrg FlushAllOutput(); 223706f2543Smrg /* keep this check close to select() call to minimize race */ 224706f2543Smrg if (dispatchException) 225706f2543Smrg i = -1; 226706f2543Smrg else if (AnyClientsWriteBlocked) 227706f2543Smrg { 228706f2543Smrg XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable); 229706f2543Smrg i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); 230706f2543Smrg } 231706f2543Smrg else 232706f2543Smrg { 233706f2543Smrg i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt); 234706f2543Smrg } 235706f2543Smrg selecterr = GetErrno(); 236706f2543Smrg WakeupHandler(i, (pointer)&LastSelectMask); 237706f2543Smrg if (i <= 0) /* An error or timeout occurred */ 238706f2543Smrg { 239706f2543Smrg if (dispatchException) 240706f2543Smrg return 0; 241706f2543Smrg if (i < 0) 242706f2543Smrg { 243706f2543Smrg if (selecterr == EBADF) /* Some client disconnected */ 244706f2543Smrg { 245706f2543Smrg CheckConnections (); 246706f2543Smrg if (! XFD_ANYSET (&AllClients)) 247706f2543Smrg return 0; 248706f2543Smrg } 249706f2543Smrg else if (selecterr == EINVAL) 250706f2543Smrg { 251706f2543Smrg FatalError("WaitForSomething(): select: %s\n", 252706f2543Smrg strerror(selecterr)); 253706f2543Smrg } 254706f2543Smrg else if (selecterr != EINTR && selecterr != EAGAIN) 255706f2543Smrg { 256706f2543Smrg ErrorF("WaitForSomething(): select: %s\n", 257706f2543Smrg strerror(selecterr)); 258706f2543Smrg } 259706f2543Smrg } 260706f2543Smrg else if (someReady) 261706f2543Smrg { 262706f2543Smrg /* 263706f2543Smrg * If no-one else is home, bail quickly 264706f2543Smrg */ 265706f2543Smrg XFD_COPYSET(&ClientsWithInput, &LastSelectMask); 266706f2543Smrg XFD_COPYSET(&ClientsWithInput, &clientsReadable); 267706f2543Smrg break; 268706f2543Smrg } 269706f2543Smrg if (*checkForInput[0] != *checkForInput[1]) 270706f2543Smrg return 0; 271706f2543Smrg 272706f2543Smrg if (timers) 273706f2543Smrg { 274706f2543Smrg int expired = 0; 275706f2543Smrg now = GetTimeInMillis(); 276706f2543Smrg if ((int) (timers->expires - now) <= 0) 277706f2543Smrg expired = 1; 278706f2543Smrg 279706f2543Smrg while (timers && (int) (timers->expires - now) <= 0) 280706f2543Smrg DoTimer(timers, now, &timers); 281706f2543Smrg 282706f2543Smrg if (expired) 283706f2543Smrg return 0; 284706f2543Smrg } 285706f2543Smrg } 286706f2543Smrg else 287706f2543Smrg { 288706f2543Smrg fd_set tmp_set; 289706f2543Smrg 290706f2543Smrg if (*checkForInput[0] == *checkForInput[1]) { 291706f2543Smrg if (timers) 292706f2543Smrg { 293706f2543Smrg int expired = 0; 294706f2543Smrg now = GetTimeInMillis(); 295706f2543Smrg if ((int) (timers->expires - now) <= 0) 296706f2543Smrg expired = 1; 297706f2543Smrg 298706f2543Smrg while (timers && (int) (timers->expires - now) <= 0) 299706f2543Smrg DoTimer(timers, now, &timers); 300706f2543Smrg 301706f2543Smrg if (expired) 302706f2543Smrg return 0; 303706f2543Smrg } 304706f2543Smrg } 305706f2543Smrg if (someReady) 306706f2543Smrg XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); 307706f2543Smrg if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable)) 308706f2543Smrg { 309706f2543Smrg NewOutputPending = TRUE; 310706f2543Smrg XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); 311706f2543Smrg XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); 312706f2543Smrg if (! XFD_ANYSET(&ClientsWriteBlocked)) 313706f2543Smrg AnyClientsWriteBlocked = FALSE; 314706f2543Smrg } 315706f2543Smrg 316706f2543Smrg XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices); 317706f2543Smrg XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); 318706f2543Smrg XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); 319706f2543Smrg if (XFD_ANYSET(&tmp_set)) 320706f2543Smrg QueueWorkProc(EstablishNewConnections, NULL, 321706f2543Smrg (pointer)&LastSelectMask); 322706f2543Smrg 323706f2543Smrg if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable)) 324706f2543Smrg break; 325706f2543Smrg /* check here for DDXes that queue events during Block/Wakeup */ 326706f2543Smrg if (*checkForInput[0] != *checkForInput[1]) 327706f2543Smrg return 0; 328706f2543Smrg } 329706f2543Smrg } 330706f2543Smrg 331706f2543Smrg nready = 0; 332706f2543Smrg if (XFD_ANYSET (&clientsReadable)) 333706f2543Smrg { 334706f2543Smrg#ifndef WIN32 335706f2543Smrg for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) 336706f2543Smrg { 337706f2543Smrg int highest_priority = 0; 338706f2543Smrg 339706f2543Smrg while (clientsReadable.fds_bits[i]) 340706f2543Smrg { 341706f2543Smrg int client_priority, client_index; 342706f2543Smrg 343706f2543Smrg curclient = mffs (clientsReadable.fds_bits[i]) - 1; 344706f2543Smrg client_index = /* raphael: modified */ 345706f2543Smrg ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))]; 346706f2543Smrg#else 347706f2543Smrg int highest_priority = 0; 348706f2543Smrg fd_set savedClientsReadable; 349706f2543Smrg XFD_COPYSET(&clientsReadable, &savedClientsReadable); 350706f2543Smrg for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++) 351706f2543Smrg { 352706f2543Smrg int client_priority, client_index; 353706f2543Smrg 354706f2543Smrg curclient = XFD_FD(&savedClientsReadable, i); 355706f2543Smrg client_index = GetConnectionTranslation(curclient); 356706f2543Smrg#endif 357706f2543Smrg /* We implement "strict" priorities. 358706f2543Smrg * Only the highest priority client is returned to 359706f2543Smrg * dix. If multiple clients at the same priority are 360706f2543Smrg * ready, they are all returned. This means that an 361706f2543Smrg * aggressive client could take over the server. 362706f2543Smrg * This was not considered a big problem because 363706f2543Smrg * aggressive clients can hose the server in so many 364706f2543Smrg * other ways :) 365706f2543Smrg */ 366706f2543Smrg client_priority = clients[client_index]->priority; 367706f2543Smrg if (nready == 0 || client_priority > highest_priority) 368706f2543Smrg { 369706f2543Smrg /* Either we found the first client, or we found 370706f2543Smrg * a client whose priority is greater than all others 371706f2543Smrg * that have been found so far. Either way, we want 372706f2543Smrg * to initialize the list of clients to contain just 373706f2543Smrg * this client. 374706f2543Smrg */ 375706f2543Smrg pClientsReady[0] = client_index; 376706f2543Smrg highest_priority = client_priority; 377706f2543Smrg nready = 1; 378706f2543Smrg } 379706f2543Smrg /* the following if makes sure that multiple same-priority 380706f2543Smrg * clients get batched together 381706f2543Smrg */ 382706f2543Smrg else if (client_priority == highest_priority) 383706f2543Smrg { 384706f2543Smrg pClientsReady[nready++] = client_index; 385706f2543Smrg } 386706f2543Smrg#ifndef WIN32 387706f2543Smrg clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); 388706f2543Smrg } 389706f2543Smrg#else 390706f2543Smrg FD_CLR(curclient, &clientsReadable); 391706f2543Smrg#endif 392706f2543Smrg } 393706f2543Smrg } 394706f2543Smrg 395706f2543Smrg if (nready) 396706f2543Smrg SmartScheduleStartTimer(); 397706f2543Smrg 398706f2543Smrg return nready; 399706f2543Smrg} 400706f2543Smrg 401706f2543Smrg/* If time has rewound, re-run every affected timer. 402706f2543Smrg * Timers might drop out of the list, so we have to restart every time. */ 403706f2543Smrgstatic void 404706f2543SmrgCheckAllTimers(void) 405706f2543Smrg{ 406706f2543Smrg OsTimerPtr timer; 407706f2543Smrg CARD32 now; 408706f2543Smrg 409706f2543Smrgstart: 410706f2543Smrg now = GetTimeInMillis(); 411706f2543Smrg 412706f2543Smrg for (timer = timers; timer; timer = timer->next) { 413706f2543Smrg if (timer->expires - now > timer->delta + 250) { 414706f2543Smrg TimerForce(timer); 415706f2543Smrg goto start; 416706f2543Smrg } 417706f2543Smrg } 418706f2543Smrg} 419706f2543Smrg 420706f2543Smrgstatic void 421706f2543SmrgDoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev) 422706f2543Smrg{ 423706f2543Smrg CARD32 newTime; 424706f2543Smrg 425706f2543Smrg *prev = timer->next; 426706f2543Smrg timer->next = NULL; 427706f2543Smrg newTime = (*timer->callback)(timer, now, timer->arg); 428706f2543Smrg if (newTime) 429706f2543Smrg TimerSet(timer, 0, newTime, timer->callback, timer->arg); 430706f2543Smrg} 431706f2543Smrg 432706f2543SmrgOsTimerPtr 433706f2543SmrgTimerSet(OsTimerPtr timer, int flags, CARD32 millis, 434706f2543Smrg OsTimerCallback func, pointer arg) 435706f2543Smrg{ 436706f2543Smrg register OsTimerPtr *prev; 437706f2543Smrg CARD32 now = GetTimeInMillis(); 438706f2543Smrg 439706f2543Smrg if (!timer) 440706f2543Smrg { 441706f2543Smrg timer = malloc(sizeof(struct _OsTimerRec)); 442706f2543Smrg if (!timer) 443706f2543Smrg return NULL; 444706f2543Smrg } 445706f2543Smrg else 446706f2543Smrg { 447706f2543Smrg for (prev = &timers; *prev; prev = &(*prev)->next) 448706f2543Smrg { 449706f2543Smrg if (*prev == timer) 450706f2543Smrg { 451706f2543Smrg *prev = timer->next; 452706f2543Smrg if (flags & TimerForceOld) 453706f2543Smrg (void)(*timer->callback)(timer, now, timer->arg); 454706f2543Smrg break; 455706f2543Smrg } 456706f2543Smrg } 457706f2543Smrg } 458706f2543Smrg if (!millis) 459706f2543Smrg return timer; 460706f2543Smrg if (flags & TimerAbsolute) { 461706f2543Smrg timer->delta = millis - now; 462706f2543Smrg } 463706f2543Smrg else { 464706f2543Smrg timer->delta = millis; 465706f2543Smrg millis += now; 466706f2543Smrg } 467706f2543Smrg timer->expires = millis; 468706f2543Smrg timer->callback = func; 469706f2543Smrg timer->arg = arg; 470706f2543Smrg if ((int) (millis - now) <= 0) 471706f2543Smrg { 472706f2543Smrg timer->next = NULL; 473706f2543Smrg millis = (*timer->callback)(timer, now, timer->arg); 474706f2543Smrg if (!millis) 475706f2543Smrg return timer; 476706f2543Smrg } 477706f2543Smrg for (prev = &timers; 478706f2543Smrg *prev && (int) ((*prev)->expires - millis) <= 0; 479706f2543Smrg prev = &(*prev)->next) 480706f2543Smrg ; 481706f2543Smrg timer->next = *prev; 482706f2543Smrg *prev = timer; 483706f2543Smrg return timer; 484706f2543Smrg} 485706f2543Smrg 486706f2543SmrgBool 487706f2543SmrgTimerForce(OsTimerPtr timer) 488706f2543Smrg{ 489706f2543Smrg OsTimerPtr *prev; 490706f2543Smrg 491706f2543Smrg for (prev = &timers; *prev; prev = &(*prev)->next) 492706f2543Smrg { 493706f2543Smrg if (*prev == timer) 494706f2543Smrg { 495706f2543Smrg DoTimer(timer, GetTimeInMillis(), prev); 496706f2543Smrg return TRUE; 497706f2543Smrg } 498706f2543Smrg } 499706f2543Smrg return FALSE; 500706f2543Smrg} 501706f2543Smrg 502706f2543Smrg 503706f2543Smrgvoid 504706f2543SmrgTimerCancel(OsTimerPtr timer) 505706f2543Smrg{ 506706f2543Smrg OsTimerPtr *prev; 507706f2543Smrg 508706f2543Smrg if (!timer) 509706f2543Smrg return; 510706f2543Smrg for (prev = &timers; *prev; prev = &(*prev)->next) 511706f2543Smrg { 512706f2543Smrg if (*prev == timer) 513706f2543Smrg { 514706f2543Smrg *prev = timer->next; 515706f2543Smrg break; 516706f2543Smrg } 517706f2543Smrg } 518706f2543Smrg} 519706f2543Smrg 520706f2543Smrgvoid 521706f2543SmrgTimerFree(OsTimerPtr timer) 522706f2543Smrg{ 523706f2543Smrg if (!timer) 524706f2543Smrg return; 525706f2543Smrg TimerCancel(timer); 526706f2543Smrg free(timer); 527706f2543Smrg} 528706f2543Smrg 529706f2543Smrgvoid 530706f2543SmrgTimerCheck(void) 531706f2543Smrg{ 532706f2543Smrg CARD32 now = GetTimeInMillis(); 533706f2543Smrg 534706f2543Smrg while (timers && (int) (timers->expires - now) <= 0) 535706f2543Smrg DoTimer(timers, now, &timers); 536706f2543Smrg} 537706f2543Smrg 538706f2543Smrgvoid 539706f2543SmrgTimerInit(void) 540706f2543Smrg{ 541706f2543Smrg OsTimerPtr timer; 542706f2543Smrg 543706f2543Smrg while ((timer = timers)) 544706f2543Smrg { 545706f2543Smrg timers = timer->next; 546706f2543Smrg free(timer); 547706f2543Smrg } 548706f2543Smrg} 549706f2543Smrg 550706f2543Smrg#ifdef DPMSExtension 551706f2543Smrg 552706f2543Smrg#define DPMS_CHECK_MODE(mode,time)\ 553706f2543Smrg if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\ 554706f2543Smrg DPMSSet(serverClient, mode); 555706f2543Smrg 556706f2543Smrg#define DPMS_CHECK_TIMEOUT(time)\ 557706f2543Smrg if (time > 0 && (time - timeout) > 0)\ 558706f2543Smrg return time - timeout; 559706f2543Smrg 560706f2543Smrgstatic CARD32 561706f2543SmrgNextDPMSTimeout(INT32 timeout) 562706f2543Smrg{ 563706f2543Smrg /* 564706f2543Smrg * Return the amount of time remaining until we should set 565706f2543Smrg * the next power level. Fallthroughs are intentional. 566706f2543Smrg */ 567706f2543Smrg switch (DPMSPowerLevel) 568706f2543Smrg { 569706f2543Smrg case DPMSModeOn: 570706f2543Smrg DPMS_CHECK_TIMEOUT(DPMSStandbyTime) 571706f2543Smrg 572706f2543Smrg case DPMSModeStandby: 573706f2543Smrg DPMS_CHECK_TIMEOUT(DPMSSuspendTime) 574706f2543Smrg 575706f2543Smrg case DPMSModeSuspend: 576706f2543Smrg DPMS_CHECK_TIMEOUT(DPMSOffTime) 577706f2543Smrg 578706f2543Smrg default: /* DPMSModeOff */ 579706f2543Smrg return 0; 580706f2543Smrg } 581706f2543Smrg} 582706f2543Smrg#endif /* DPMSExtension */ 583706f2543Smrg 584706f2543Smrgstatic CARD32 585706f2543SmrgScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg) 586706f2543Smrg{ 587706f2543Smrg INT32 timeout = now - lastDeviceEventTime.milliseconds; 588706f2543Smrg CARD32 nextTimeout = 0; 589706f2543Smrg 590706f2543Smrg#ifdef DPMSExtension 591706f2543Smrg /* 592706f2543Smrg * Check each mode lowest to highest, since a lower mode can 593706f2543Smrg * have the same timeout as a higher one. 594706f2543Smrg */ 595706f2543Smrg if (DPMSEnabled) 596706f2543Smrg { 597706f2543Smrg DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime) 598706f2543Smrg DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime) 599706f2543Smrg DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime) 600706f2543Smrg 601706f2543Smrg nextTimeout = NextDPMSTimeout(timeout); 602706f2543Smrg } 603706f2543Smrg 604706f2543Smrg /* 605706f2543Smrg * Only do the screensaver checks if we're not in a DPMS 606706f2543Smrg * power saving mode 607706f2543Smrg */ 608706f2543Smrg if (DPMSPowerLevel != DPMSModeOn) 609706f2543Smrg return nextTimeout; 610706f2543Smrg#endif /* DPMSExtension */ 611706f2543Smrg 612706f2543Smrg if (!ScreenSaverTime) 613706f2543Smrg return nextTimeout; 614706f2543Smrg 615706f2543Smrg if (timeout < ScreenSaverTime) 616706f2543Smrg { 617706f2543Smrg return nextTimeout > 0 ? 618706f2543Smrg min(ScreenSaverTime - timeout, nextTimeout) : 619706f2543Smrg ScreenSaverTime - timeout; 620706f2543Smrg } 621706f2543Smrg 622706f2543Smrg ResetOsBuffers(); /* not ideal, but better than nothing */ 623706f2543Smrg dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive); 624706f2543Smrg 625706f2543Smrg if (ScreenSaverInterval > 0) 626706f2543Smrg { 627706f2543Smrg nextTimeout = nextTimeout > 0 ? 628706f2543Smrg min(ScreenSaverInterval, nextTimeout) : 629706f2543Smrg ScreenSaverInterval; 630706f2543Smrg } 631706f2543Smrg 632706f2543Smrg return nextTimeout; 633706f2543Smrg} 634706f2543Smrg 635706f2543Smrgstatic OsTimerPtr ScreenSaverTimer = NULL; 636706f2543Smrg 637706f2543Smrgvoid 638706f2543SmrgFreeScreenSaverTimer(void) 639706f2543Smrg{ 640706f2543Smrg if (ScreenSaverTimer) { 641706f2543Smrg TimerFree(ScreenSaverTimer); 642706f2543Smrg ScreenSaverTimer = NULL; 643706f2543Smrg } 644706f2543Smrg} 645706f2543Smrg 646706f2543Smrgvoid 647706f2543SmrgSetScreenSaverTimer(void) 648706f2543Smrg{ 649706f2543Smrg CARD32 timeout = 0; 650706f2543Smrg 651706f2543Smrg#ifdef DPMSExtension 652706f2543Smrg if (DPMSEnabled) 653706f2543Smrg { 654706f2543Smrg /* 655706f2543Smrg * A higher DPMS level has a timeout that's either less 656706f2543Smrg * than or equal to that of a lower DPMS level. 657706f2543Smrg */ 658706f2543Smrg if (DPMSStandbyTime > 0) 659706f2543Smrg timeout = DPMSStandbyTime; 660706f2543Smrg 661706f2543Smrg else if (DPMSSuspendTime > 0) 662706f2543Smrg timeout = DPMSSuspendTime; 663706f2543Smrg 664706f2543Smrg else if (DPMSOffTime > 0) 665706f2543Smrg timeout = DPMSOffTime; 666706f2543Smrg } 667706f2543Smrg#endif 668706f2543Smrg 669706f2543Smrg if (ScreenSaverTime > 0) 670706f2543Smrg { 671706f2543Smrg timeout = timeout > 0 ? 672706f2543Smrg min(ScreenSaverTime, timeout) : 673706f2543Smrg ScreenSaverTime; 674706f2543Smrg } 675706f2543Smrg 676706f2543Smrg#ifdef SCREENSAVER 677706f2543Smrg if (timeout && !screenSaverSuspended) { 678706f2543Smrg#else 679706f2543Smrg if (timeout) { 680706f2543Smrg#endif 681706f2543Smrg ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout, 682706f2543Smrg ScreenSaverTimeoutExpire, NULL); 683706f2543Smrg } 684706f2543Smrg else if (ScreenSaverTimer) { 685706f2543Smrg FreeScreenSaverTimer(); 686706f2543Smrg } 687706f2543Smrg} 688706f2543Smrg 689