xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

WaitFor.c (13604B)


      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
    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
    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
    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
    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 
    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
    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
    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
    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
    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
    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
    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
    370 TimerFree(OsTimerPtr timer)
    371 {
    372     if (!timer)
    373         return;
    374     TimerCancel(timer);
    375     free(timer);
    376 }
    377 
    378 void
    379 TimerCheck(void)
    380 {
    381     DoTimers(GetTimeInMillis());
    382 }
    383 
    384 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
    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
    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
    484 FreeScreenSaverTimer(void)
    485 {
    486     if (ScreenSaverTimer) {
    487         TimerFree(ScreenSaverTimer);
    488         ScreenSaverTimer = NULL;
    489     }
    490 }
    491 
    492 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 }