1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun Copyright 1992, 1998 The Open Group
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun Permission to use, copy, modify, distribute, and sell this software and its
6*4882a593Smuzhiyun documentation for any purpose is hereby granted without fee, provided that
7*4882a593Smuzhiyun the above copyright notice appear in all copies and that both that
8*4882a593Smuzhiyun copyright notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation.
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun all copies or substantial portions of the Software.
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17*4882a593Smuzhiyun OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18*4882a593Smuzhiyun AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19*4882a593Smuzhiyun CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun Except as contained in this notice, the name of The Open Group shall not be
22*4882a593Smuzhiyun used in advertising or otherwise to promote the sale, use or other dealings
23*4882a593Smuzhiyun in this Software without prior written authorization from The Open Group.
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * Author: Keith Packard, MIT X Consortium
26*4882a593Smuzhiyun */
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /* dixsleep.c - implement millisecond timeouts for X clients */
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
31*4882a593Smuzhiyun #include <dix-config.h>
32*4882a593Smuzhiyun #endif
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #include "sleepuntil.h"
35*4882a593Smuzhiyun #include <X11/X.h>
36*4882a593Smuzhiyun #include <X11/Xmd.h>
37*4882a593Smuzhiyun #include "misc.h"
38*4882a593Smuzhiyun #include "windowstr.h"
39*4882a593Smuzhiyun #include "dixstruct.h"
40*4882a593Smuzhiyun #include "pixmapstr.h"
41*4882a593Smuzhiyun #include "scrnintstr.h"
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun typedef struct _Sertafied {
44*4882a593Smuzhiyun struct _Sertafied *next;
45*4882a593Smuzhiyun TimeStamp revive;
46*4882a593Smuzhiyun ClientPtr pClient;
47*4882a593Smuzhiyun XID id;
48*4882a593Smuzhiyun void (*notifyFunc) (ClientPtr /* client */ ,
49*4882a593Smuzhiyun void * /* closure */
50*4882a593Smuzhiyun );
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun void *closure;
53*4882a593Smuzhiyun } SertafiedRec, *SertafiedPtr;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun static SertafiedPtr pPending;
56*4882a593Smuzhiyun static RESTYPE SertafiedResType;
57*4882a593Smuzhiyun static Bool BlockHandlerRegistered;
58*4882a593Smuzhiyun static int SertafiedGeneration;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun static void ClientAwaken(ClientPtr /* client */ ,
61*4882a593Smuzhiyun void * /* closure */
62*4882a593Smuzhiyun );
63*4882a593Smuzhiyun static int SertafiedDelete(void * /* value */ ,
64*4882a593Smuzhiyun XID /* id */
65*4882a593Smuzhiyun );
66*4882a593Smuzhiyun static void SertafiedBlockHandler(void *data,
67*4882a593Smuzhiyun void *timeout);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun static void SertafiedWakeupHandler(void *data,
70*4882a593Smuzhiyun int i);
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun int
ClientSleepUntil(ClientPtr client,TimeStamp * revive,void (* notifyFunc)(ClientPtr,void *),void * closure)73*4882a593Smuzhiyun ClientSleepUntil(ClientPtr client,
74*4882a593Smuzhiyun TimeStamp *revive,
75*4882a593Smuzhiyun void (*notifyFunc) (ClientPtr, void *), void *closure)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun SertafiedPtr pRequest, pReq, pPrev;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun if (SertafiedGeneration != serverGeneration) {
80*4882a593Smuzhiyun SertafiedResType = CreateNewResourceType(SertafiedDelete,
81*4882a593Smuzhiyun "ClientSleep");
82*4882a593Smuzhiyun if (!SertafiedResType)
83*4882a593Smuzhiyun return FALSE;
84*4882a593Smuzhiyun SertafiedGeneration = serverGeneration;
85*4882a593Smuzhiyun BlockHandlerRegistered = FALSE;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun pRequest = malloc(sizeof(SertafiedRec));
88*4882a593Smuzhiyun if (!pRequest)
89*4882a593Smuzhiyun return FALSE;
90*4882a593Smuzhiyun pRequest->pClient = client;
91*4882a593Smuzhiyun pRequest->revive = *revive;
92*4882a593Smuzhiyun pRequest->id = FakeClientID(client->index);
93*4882a593Smuzhiyun pRequest->closure = closure;
94*4882a593Smuzhiyun if (!BlockHandlerRegistered) {
95*4882a593Smuzhiyun if (!RegisterBlockAndWakeupHandlers(SertafiedBlockHandler,
96*4882a593Smuzhiyun SertafiedWakeupHandler,
97*4882a593Smuzhiyun (void *) 0)) {
98*4882a593Smuzhiyun free(pRequest);
99*4882a593Smuzhiyun return FALSE;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun BlockHandlerRegistered = TRUE;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun pRequest->notifyFunc = 0;
104*4882a593Smuzhiyun if (!AddResource(pRequest->id, SertafiedResType, (void *) pRequest))
105*4882a593Smuzhiyun return FALSE;
106*4882a593Smuzhiyun if (!notifyFunc)
107*4882a593Smuzhiyun notifyFunc = ClientAwaken;
108*4882a593Smuzhiyun pRequest->notifyFunc = notifyFunc;
109*4882a593Smuzhiyun /* Insert into time-ordered queue, with earliest activation time coming first. */
110*4882a593Smuzhiyun pPrev = 0;
111*4882a593Smuzhiyun for (pReq = pPending; pReq; pReq = pReq->next) {
112*4882a593Smuzhiyun if (CompareTimeStamps(pReq->revive, *revive) == LATER)
113*4882a593Smuzhiyun break;
114*4882a593Smuzhiyun pPrev = pReq;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun if (pPrev)
117*4882a593Smuzhiyun pPrev->next = pRequest;
118*4882a593Smuzhiyun else
119*4882a593Smuzhiyun pPending = pRequest;
120*4882a593Smuzhiyun pRequest->next = pReq;
121*4882a593Smuzhiyun IgnoreClient(client);
122*4882a593Smuzhiyun return TRUE;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun static void
ClientAwaken(ClientPtr client,void * closure)126*4882a593Smuzhiyun ClientAwaken(ClientPtr client, void *closure)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun AttendClient(client);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun static int
SertafiedDelete(void * value,XID id)132*4882a593Smuzhiyun SertafiedDelete(void *value, XID id)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun SertafiedPtr pRequest = (SertafiedPtr) value;
135*4882a593Smuzhiyun SertafiedPtr pReq, pPrev;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun pPrev = 0;
138*4882a593Smuzhiyun for (pReq = pPending; pReq; pPrev = pReq, pReq = pReq->next)
139*4882a593Smuzhiyun if (pReq == pRequest) {
140*4882a593Smuzhiyun if (pPrev)
141*4882a593Smuzhiyun pPrev->next = pReq->next;
142*4882a593Smuzhiyun else
143*4882a593Smuzhiyun pPending = pReq->next;
144*4882a593Smuzhiyun break;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun if (pRequest->notifyFunc)
147*4882a593Smuzhiyun (*pRequest->notifyFunc) (pRequest->pClient, pRequest->closure);
148*4882a593Smuzhiyun free(pRequest);
149*4882a593Smuzhiyun return TRUE;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun static void
SertafiedBlockHandler(void * data,void * wt)153*4882a593Smuzhiyun SertafiedBlockHandler(void *data, void *wt)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun SertafiedPtr pReq, pNext;
156*4882a593Smuzhiyun unsigned long delay;
157*4882a593Smuzhiyun TimeStamp now;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun if (!pPending)
160*4882a593Smuzhiyun return;
161*4882a593Smuzhiyun now.milliseconds = GetTimeInMillis();
162*4882a593Smuzhiyun now.months = currentTime.months;
163*4882a593Smuzhiyun if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
164*4882a593Smuzhiyun now.months++;
165*4882a593Smuzhiyun for (pReq = pPending; pReq; pReq = pNext) {
166*4882a593Smuzhiyun pNext = pReq->next;
167*4882a593Smuzhiyun if (CompareTimeStamps(pReq->revive, now) == LATER)
168*4882a593Smuzhiyun break;
169*4882a593Smuzhiyun FreeResource(pReq->id, RT_NONE);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* AttendClient() may have been called via the resource delete
172*4882a593Smuzhiyun * function so a client may have input to be processed and so
173*4882a593Smuzhiyun * set delay to 0 to prevent blocking in WaitForSomething().
174*4882a593Smuzhiyun */
175*4882a593Smuzhiyun AdjustWaitForDelay(wt, 0);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun pReq = pPending;
178*4882a593Smuzhiyun if (!pReq)
179*4882a593Smuzhiyun return;
180*4882a593Smuzhiyun delay = pReq->revive.milliseconds - now.milliseconds;
181*4882a593Smuzhiyun AdjustWaitForDelay(wt, delay);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun static void
SertafiedWakeupHandler(void * data,int i)185*4882a593Smuzhiyun SertafiedWakeupHandler(void *data, int i)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun SertafiedPtr pReq, pNext;
188*4882a593Smuzhiyun TimeStamp now;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun now.milliseconds = GetTimeInMillis();
191*4882a593Smuzhiyun now.months = currentTime.months;
192*4882a593Smuzhiyun if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
193*4882a593Smuzhiyun now.months++;
194*4882a593Smuzhiyun for (pReq = pPending; pReq; pReq = pNext) {
195*4882a593Smuzhiyun pNext = pReq->next;
196*4882a593Smuzhiyun if (CompareTimeStamps(pReq->revive, now) == LATER)
197*4882a593Smuzhiyun break;
198*4882a593Smuzhiyun FreeResource(pReq->id, RT_NONE);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun if (!pPending) {
201*4882a593Smuzhiyun RemoveBlockAndWakeupHandlers(SertafiedBlockHandler,
202*4882a593Smuzhiyun SertafiedWakeupHandler, (void *) 0);
203*4882a593Smuzhiyun BlockHandlerRegistered = FALSE;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun }
206