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