105b261ecSmrg/*
205b261ecSmrg *
305b261ecSmrgCopyright 1992, 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 * Author:  Keith Packard, MIT X Consortium
2605b261ecSmrg */
2705b261ecSmrg
2805b261ecSmrg/* dixsleep.c - implement millisecond timeouts for X clients */
2905b261ecSmrg
3005b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3105b261ecSmrg#include <dix-config.h>
3205b261ecSmrg#endif
3305b261ecSmrg
3405b261ecSmrg#include "sleepuntil.h"
3505b261ecSmrg#include <X11/X.h>
3605b261ecSmrg#include <X11/Xmd.h>
3705b261ecSmrg#include "misc.h"
3805b261ecSmrg#include "windowstr.h"
3905b261ecSmrg#include "dixstruct.h"
4005b261ecSmrg#include "pixmapstr.h"
4105b261ecSmrg#include "scrnintstr.h"
4205b261ecSmrg
4305b261ecSmrgtypedef struct _Sertafied {
4435c4bbdfSmrg    struct _Sertafied *next;
4535c4bbdfSmrg    TimeStamp revive;
4635c4bbdfSmrg    ClientPtr pClient;
4735c4bbdfSmrg    XID id;
4835c4bbdfSmrg    void (*notifyFunc) (ClientPtr /* client */ ,
4935c4bbdfSmrg                        void *    /* closure */
5035c4bbdfSmrg        );
5135c4bbdfSmrg
5235c4bbdfSmrg    void *closure;
5305b261ecSmrg} SertafiedRec, *SertafiedPtr;
5405b261ecSmrg
5505b261ecSmrgstatic SertafiedPtr pPending;
5635c4bbdfSmrgstatic RESTYPE SertafiedResType;
5735c4bbdfSmrgstatic Bool BlockHandlerRegistered;
5835c4bbdfSmrgstatic int SertafiedGeneration;
5935c4bbdfSmrg
6035c4bbdfSmrgstatic void ClientAwaken(ClientPtr /* client */ ,
6135c4bbdfSmrg                         void *    /* closure */
6235c4bbdfSmrg    );
6335c4bbdfSmrgstatic int SertafiedDelete(void *  /* value */ ,
6435c4bbdfSmrg                           XID     /* id */
6535c4bbdfSmrg    );
661b5d61b8Smrgstatic void SertafiedBlockHandler(void *data,
671b5d61b8Smrg                                  void *timeout);
681b5d61b8Smrg
691b5d61b8Smrgstatic void SertafiedWakeupHandler(void *data,
701b5d61b8Smrg                                   int i);
7105b261ecSmrg
726747b715Smrgint
7335c4bbdfSmrgClientSleepUntil(ClientPtr client,
7435c4bbdfSmrg                 TimeStamp *revive,
7535c4bbdfSmrg                 void (*notifyFunc) (ClientPtr, void *), void *closure)
7605b261ecSmrg{
7735c4bbdfSmrg    SertafiedPtr pRequest, pReq, pPrev;
7835c4bbdfSmrg
7935c4bbdfSmrg    if (SertafiedGeneration != serverGeneration) {
8035c4bbdfSmrg        SertafiedResType = CreateNewResourceType(SertafiedDelete,
8135c4bbdfSmrg                                                 "ClientSleep");
8235c4bbdfSmrg        if (!SertafiedResType)
8335c4bbdfSmrg            return FALSE;
8435c4bbdfSmrg        SertafiedGeneration = serverGeneration;
8535c4bbdfSmrg        BlockHandlerRegistered = FALSE;
8605b261ecSmrg    }
8735c4bbdfSmrg    pRequest = malloc(sizeof(SertafiedRec));
8805b261ecSmrg    if (!pRequest)
8935c4bbdfSmrg        return FALSE;
9005b261ecSmrg    pRequest->pClient = client;
9105b261ecSmrg    pRequest->revive = *revive;
9235c4bbdfSmrg    pRequest->id = FakeClientID(client->index);
9305b261ecSmrg    pRequest->closure = closure;
9435c4bbdfSmrg    if (!BlockHandlerRegistered) {
9535c4bbdfSmrg        if (!RegisterBlockAndWakeupHandlers(SertafiedBlockHandler,
9635c4bbdfSmrg                                            SertafiedWakeupHandler,
9735c4bbdfSmrg                                            (void *) 0)) {
9835c4bbdfSmrg            free(pRequest);
9935c4bbdfSmrg            return FALSE;
10035c4bbdfSmrg        }
10135c4bbdfSmrg        BlockHandlerRegistered = TRUE;
10205b261ecSmrg    }
10305b261ecSmrg    pRequest->notifyFunc = 0;
10435c4bbdfSmrg    if (!AddResource(pRequest->id, SertafiedResType, (void *) pRequest))
10535c4bbdfSmrg        return FALSE;
10605b261ecSmrg    if (!notifyFunc)
10735c4bbdfSmrg        notifyFunc = ClientAwaken;
10805b261ecSmrg    pRequest->notifyFunc = notifyFunc;
10905b261ecSmrg    /* Insert into time-ordered queue, with earliest activation time coming first. */
11005b261ecSmrg    pPrev = 0;
11135c4bbdfSmrg    for (pReq = pPending; pReq; pReq = pReq->next) {
11235c4bbdfSmrg        if (CompareTimeStamps(pReq->revive, *revive) == LATER)
11335c4bbdfSmrg            break;
11435c4bbdfSmrg        pPrev = pReq;
11505b261ecSmrg    }
11605b261ecSmrg    if (pPrev)
11735c4bbdfSmrg        pPrev->next = pRequest;
11805b261ecSmrg    else
11935c4bbdfSmrg        pPending = pRequest;
12005b261ecSmrg    pRequest->next = pReq;
12135c4bbdfSmrg    IgnoreClient(client);
12205b261ecSmrg    return TRUE;
12305b261ecSmrg}
12405b261ecSmrg
12505b261ecSmrgstatic void
12635c4bbdfSmrgClientAwaken(ClientPtr client, void *closure)
12705b261ecSmrg{
12825da500fSmrg    AttendClient(client);
12905b261ecSmrg}
13005b261ecSmrg
13105b261ecSmrgstatic int
13235c4bbdfSmrgSertafiedDelete(void *value, XID id)
13305b261ecSmrg{
13435c4bbdfSmrg    SertafiedPtr pRequest = (SertafiedPtr) value;
13535c4bbdfSmrg    SertafiedPtr pReq, pPrev;
13605b261ecSmrg
13705b261ecSmrg    pPrev = 0;
13805b261ecSmrg    for (pReq = pPending; pReq; pPrev = pReq, pReq = pReq->next)
13935c4bbdfSmrg        if (pReq == pRequest) {
14035c4bbdfSmrg            if (pPrev)
14135c4bbdfSmrg                pPrev->next = pReq->next;
14235c4bbdfSmrg            else
14335c4bbdfSmrg                pPending = pReq->next;
14435c4bbdfSmrg            break;
14535c4bbdfSmrg        }
14605b261ecSmrg    if (pRequest->notifyFunc)
14735c4bbdfSmrg        (*pRequest->notifyFunc) (pRequest->pClient, pRequest->closure);
1486747b715Smrg    free(pRequest);
14905b261ecSmrg    return TRUE;
15005b261ecSmrg}
15105b261ecSmrg
15205b261ecSmrgstatic void
1531b5d61b8SmrgSertafiedBlockHandler(void *data, void *wt)
15405b261ecSmrg{
15535c4bbdfSmrg    SertafiedPtr pReq, pNext;
15635c4bbdfSmrg    unsigned long delay;
15735c4bbdfSmrg    TimeStamp now;
15805b261ecSmrg
15905b261ecSmrg    if (!pPending)
16035c4bbdfSmrg        return;
16135c4bbdfSmrg    now.milliseconds = GetTimeInMillis();
16205b261ecSmrg    now.months = currentTime.months;
16305b261ecSmrg    if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
16435c4bbdfSmrg        now.months++;
16535c4bbdfSmrg    for (pReq = pPending; pReq; pReq = pNext) {
16635c4bbdfSmrg        pNext = pReq->next;
16735c4bbdfSmrg        if (CompareTimeStamps(pReq->revive, now) == LATER)
16835c4bbdfSmrg            break;
16935c4bbdfSmrg        FreeResource(pReq->id, RT_NONE);
17035c4bbdfSmrg
17135c4bbdfSmrg        /* AttendClient() may have been called via the resource delete
17235c4bbdfSmrg         * function so a client may have input to be processed and so
17335c4bbdfSmrg         *  set delay to 0 to prevent blocking in WaitForSomething().
17435c4bbdfSmrg         */
17535c4bbdfSmrg        AdjustWaitForDelay(wt, 0);
17605b261ecSmrg    }
17705b261ecSmrg    pReq = pPending;
17805b261ecSmrg    if (!pReq)
17935c4bbdfSmrg        return;
18005b261ecSmrg    delay = pReq->revive.milliseconds - now.milliseconds;
18135c4bbdfSmrg    AdjustWaitForDelay(wt, delay);
18205b261ecSmrg}
18305b261ecSmrg
18405b261ecSmrgstatic void
1851b5d61b8SmrgSertafiedWakeupHandler(void *data, int i)
18605b261ecSmrg{
18735c4bbdfSmrg    SertafiedPtr pReq, pNext;
18835c4bbdfSmrg    TimeStamp now;
18905b261ecSmrg
19035c4bbdfSmrg    now.milliseconds = GetTimeInMillis();
19105b261ecSmrg    now.months = currentTime.months;
19205b261ecSmrg    if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
19335c4bbdfSmrg        now.months++;
19435c4bbdfSmrg    for (pReq = pPending; pReq; pReq = pNext) {
19535c4bbdfSmrg        pNext = pReq->next;
19635c4bbdfSmrg        if (CompareTimeStamps(pReq->revive, now) == LATER)
19735c4bbdfSmrg            break;
19835c4bbdfSmrg        FreeResource(pReq->id, RT_NONE);
19905b261ecSmrg    }
20035c4bbdfSmrg    if (!pPending) {
20135c4bbdfSmrg        RemoveBlockAndWakeupHandlers(SertafiedBlockHandler,
20235c4bbdfSmrg                                     SertafiedWakeupHandler, (void *) 0);
20335c4bbdfSmrg        BlockHandlerRegistered = FALSE;
20405b261ecSmrg    }
20505b261ecSmrg}
206