Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * | |
3 | Copyright 1992, 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 | * Author: Keith Packard, MIT X Consortium | |
26 | */ | |
27 | ||
28 | /* dixsleep.c - implement millisecond timeouts for X clients */ | |
29 | ||
30 | #ifdef HAVE_DIX_CONFIG_H | |
31 | #include <dix-config.h> | |
32 | #endif | |
33 | ||
34 | #include "sleepuntil.h" | |
35 | #include <X11/X.h> | |
36 | #include <X11/Xmd.h> | |
37 | #include "misc.h" | |
38 | #include "windowstr.h" | |
39 | #include "dixstruct.h" | |
40 | #include "pixmapstr.h" | |
41 | #include "scrnintstr.h" | |
42 | ||
43 | typedef struct _Sertafied { | |
44 | struct _Sertafied *next; | |
45 | TimeStamp revive; | |
46 | ClientPtr pClient; | |
47 | XID id; | |
48 | void (*notifyFunc) (ClientPtr /* client */ , | |
49 | pointer /* closure */ | |
50 | ); | |
51 | ||
52 | pointer closure; | |
53 | } SertafiedRec, *SertafiedPtr; | |
54 | ||
55 | static SertafiedPtr pPending; | |
56 | static RESTYPE SertafiedResType; | |
57 | static Bool BlockHandlerRegistered; | |
58 | static int SertafiedGeneration; | |
59 | ||
60 | static void ClientAwaken(ClientPtr /* client */ , | |
61 | pointer /* closure */ | |
62 | ); | |
63 | static int SertafiedDelete(pointer /* value */ , | |
64 | XID /* id */ | |
65 | ); | |
66 | static void SertafiedBlockHandler(pointer /* data */ , | |
67 | OSTimePtr /* wt */ , | |
68 | pointer /* LastSelectMask */ | |
69 | ); | |
70 | static void SertafiedWakeupHandler(pointer /* data */ , | |
71 | int /* i */ , | |
72 | pointer /* LastSelectMask */ | |
73 | ); | |
74 | ||
75 | int | |
76 | ClientSleepUntil(ClientPtr client, | |
77 | TimeStamp *revive, | |
78 | void (*notifyFunc) (ClientPtr, pointer), pointer closure) | |
79 | { | |
80 | SertafiedPtr pRequest, pReq, pPrev; | |
81 | ||
82 | if (SertafiedGeneration != serverGeneration) { | |
83 | SertafiedResType = CreateNewResourceType(SertafiedDelete, | |
84 | "ClientSleep"); | |
85 | if (!SertafiedResType) | |
86 | return FALSE; | |
87 | SertafiedGeneration = serverGeneration; | |
88 | BlockHandlerRegistered = FALSE; | |
89 | } | |
90 | pRequest = malloc(sizeof(SertafiedRec)); | |
91 | if (!pRequest) | |
92 | return FALSE; | |
93 | pRequest->pClient = client; | |
94 | pRequest->revive = *revive; | |
95 | pRequest->id = FakeClientID(client->index); | |
96 | pRequest->closure = closure; | |
97 | if (!BlockHandlerRegistered) { | |
98 | if (!RegisterBlockAndWakeupHandlers(SertafiedBlockHandler, | |
99 | SertafiedWakeupHandler, | |
100 | (pointer) 0)) { | |
101 | free(pRequest); | |
102 | return FALSE; | |
103 | } | |
104 | BlockHandlerRegistered = TRUE; | |
105 | } | |
106 | pRequest->notifyFunc = 0; | |
107 | if (!AddResource(pRequest->id, SertafiedResType, (pointer) pRequest)) | |
108 | return FALSE; | |
109 | if (!notifyFunc) | |
110 | notifyFunc = ClientAwaken; | |
111 | pRequest->notifyFunc = notifyFunc; | |
112 | /* Insert into time-ordered queue, with earliest activation time coming first. */ | |
113 | pPrev = 0; | |
114 | for (pReq = pPending; pReq; pReq = pReq->next) { | |
115 | if (CompareTimeStamps(pReq->revive, *revive) == LATER) | |
116 | break; | |
117 | pPrev = pReq; | |
118 | } | |
119 | if (pPrev) | |
120 | pPrev->next = pRequest; | |
121 | else | |
122 | pPending = pRequest; | |
123 | pRequest->next = pReq; | |
124 | IgnoreClient(client); | |
125 | return TRUE; | |
126 | } | |
127 | ||
128 | static void | |
129 | ClientAwaken(ClientPtr client, pointer closure) | |
130 | { | |
131 | if (!client->clientGone) | |
132 | AttendClient(client); | |
133 | } | |
134 | ||
135 | static int | |
136 | SertafiedDelete(pointer value, XID id) | |
137 | { | |
138 | SertafiedPtr pRequest = (SertafiedPtr) value; | |
139 | SertafiedPtr pReq, pPrev; | |
140 | ||
141 | pPrev = 0; | |
142 | for (pReq = pPending; pReq; pPrev = pReq, pReq = pReq->next) | |
143 | if (pReq == pRequest) { | |
144 | if (pPrev) | |
145 | pPrev->next = pReq->next; | |
146 | else | |
147 | pPending = pReq->next; | |
148 | break; | |
149 | } | |
150 | if (pRequest->notifyFunc) | |
151 | (*pRequest->notifyFunc) (pRequest->pClient, pRequest->closure); | |
152 | free(pRequest); | |
153 | return TRUE; | |
154 | } | |
155 | ||
156 | static void | |
157 | SertafiedBlockHandler(pointer data, OSTimePtr wt, pointer LastSelectMask) | |
158 | { | |
159 | SertafiedPtr pReq, pNext; | |
160 | unsigned long delay; | |
161 | TimeStamp now; | |
162 | ||
163 | if (!pPending) | |
164 | return; | |
165 | now.milliseconds = GetTimeInMillis(); | |
166 | now.months = currentTime.months; | |
167 | if ((int) (now.milliseconds - currentTime.milliseconds) < 0) | |
168 | now.months++; | |
169 | for (pReq = pPending; pReq; pReq = pNext) { | |
170 | pNext = pReq->next; | |
171 | if (CompareTimeStamps(pReq->revive, now) == LATER) | |
172 | break; | |
173 | FreeResource(pReq->id, RT_NONE); | |
174 | ||
175 | /* AttendClient() may have been called via the resource delete | |
176 | * function so a client may have input to be processed and so | |
177 | * set delay to 0 to prevent blocking in WaitForSomething(). | |
178 | */ | |
179 | AdjustWaitForDelay(wt, 0); | |
180 | } | |
181 | pReq = pPending; | |
182 | if (!pReq) | |
183 | return; | |
184 | delay = pReq->revive.milliseconds - now.milliseconds; | |
185 | AdjustWaitForDelay(wt, delay); | |
186 | } | |
187 | ||
188 | static void | |
189 | SertafiedWakeupHandler(pointer data, int i, pointer LastSelectMask) | |
190 | { | |
191 | SertafiedPtr pReq, pNext; | |
192 | TimeStamp now; | |
193 | ||
194 | now.milliseconds = GetTimeInMillis(); | |
195 | now.months = currentTime.months; | |
196 | if ((int) (now.milliseconds - currentTime.milliseconds) < 0) | |
197 | now.months++; | |
198 | for (pReq = pPending; pReq; pReq = pNext) { | |
199 | pNext = pReq->next; | |
200 | if (CompareTimeStamps(pReq->revive, now) == LATER) | |
201 | break; | |
202 | FreeResource(pReq->id, RT_NONE); | |
203 | } | |
204 | if (!pPending) { | |
205 | RemoveBlockAndWakeupHandlers(SertafiedBlockHandler, | |
206 | SertafiedWakeupHandler, (pointer) 0); | |
207 | BlockHandlerRegistered = FALSE; | |
208 | } | |
209 | } |