1706f2543Smrg/*
2706f2543Smrg *
3706f2543SmrgCopyright 1992, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included in
12706f2543Smrgall copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20706f2543Smrg
21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be
22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings
23706f2543Smrgin this Software without prior written authorization from The Open Group.
24706f2543Smrg *
25706f2543Smrg * Author:  Keith Packard, MIT X Consortium
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg/* dixsleep.c - implement millisecond timeouts for X clients */
29706f2543Smrg
30706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
31706f2543Smrg#include <dix-config.h>
32706f2543Smrg#endif
33706f2543Smrg
34706f2543Smrg#include "sleepuntil.h"
35706f2543Smrg#include <X11/X.h>
36706f2543Smrg#include <X11/Xmd.h>
37706f2543Smrg#include "misc.h"
38706f2543Smrg#include "windowstr.h"
39706f2543Smrg#include "dixstruct.h"
40706f2543Smrg#include "pixmapstr.h"
41706f2543Smrg#include "scrnintstr.h"
42706f2543Smrg
43706f2543Smrgtypedef struct _Sertafied {
44706f2543Smrg    struct _Sertafied	*next;
45706f2543Smrg    TimeStamp		revive;
46706f2543Smrg    ClientPtr		pClient;
47706f2543Smrg    XID			id;
48706f2543Smrg    void		(*notifyFunc)(
49706f2543Smrg			ClientPtr /* client */,
50706f2543Smrg			pointer /* closure */
51706f2543Smrg			);
52706f2543Smrg
53706f2543Smrg    pointer		closure;
54706f2543Smrg} SertafiedRec, *SertafiedPtr;
55706f2543Smrg
56706f2543Smrgstatic SertafiedPtr pPending;
57706f2543Smrgstatic RESTYPE	    SertafiedResType;
58706f2543Smrgstatic Bool	    BlockHandlerRegistered;
59706f2543Smrgstatic int	    SertafiedGeneration;
60706f2543Smrg
61706f2543Smrgstatic void	    ClientAwaken(
62706f2543Smrg    ClientPtr /* client */,
63706f2543Smrg    pointer /* closure */
64706f2543Smrg);
65706f2543Smrgstatic int	    SertafiedDelete(
66706f2543Smrg    pointer /* value */,
67706f2543Smrg    XID /* id */
68706f2543Smrg);
69706f2543Smrgstatic void	    SertafiedBlockHandler(
70706f2543Smrg    pointer /* data */,
71706f2543Smrg    OSTimePtr /* wt */,
72706f2543Smrg    pointer /* LastSelectMask */
73706f2543Smrg);
74706f2543Smrgstatic void	    SertafiedWakeupHandler(
75706f2543Smrg    pointer /* data */,
76706f2543Smrg    int /* i */,
77706f2543Smrg    pointer /* LastSelectMask */
78706f2543Smrg);
79706f2543Smrg
80706f2543Smrgint
81706f2543SmrgClientSleepUntil (ClientPtr client,
82706f2543Smrg                  TimeStamp *revive,
83706f2543Smrg                  void (*notifyFunc)(ClientPtr, pointer),
84706f2543Smrg                  pointer closure)
85706f2543Smrg{
86706f2543Smrg    SertafiedPtr	pRequest, pReq, pPrev;
87706f2543Smrg
88706f2543Smrg    if (SertafiedGeneration != serverGeneration)
89706f2543Smrg    {
90706f2543Smrg	SertafiedResType = CreateNewResourceType (SertafiedDelete,
91706f2543Smrg						  "ClientSleep");
92706f2543Smrg	if (!SertafiedResType)
93706f2543Smrg	    return FALSE;
94706f2543Smrg	SertafiedGeneration = serverGeneration;
95706f2543Smrg	BlockHandlerRegistered = FALSE;
96706f2543Smrg    }
97706f2543Smrg    pRequest = malloc(sizeof (SertafiedRec));
98706f2543Smrg    if (!pRequest)
99706f2543Smrg	return FALSE;
100706f2543Smrg    pRequest->pClient = client;
101706f2543Smrg    pRequest->revive = *revive;
102706f2543Smrg    pRequest->id = FakeClientID (client->index);
103706f2543Smrg    pRequest->closure = closure;
104706f2543Smrg    if (!BlockHandlerRegistered)
105706f2543Smrg    {
106706f2543Smrg	if (!RegisterBlockAndWakeupHandlers (SertafiedBlockHandler,
107706f2543Smrg					     SertafiedWakeupHandler,
108706f2543Smrg					     (pointer) 0))
109706f2543Smrg	{
110706f2543Smrg	    free(pRequest);
111706f2543Smrg	    return FALSE;
112706f2543Smrg	}
113706f2543Smrg	BlockHandlerRegistered = TRUE;
114706f2543Smrg    }
115706f2543Smrg    pRequest->notifyFunc = 0;
116706f2543Smrg    if (!AddResource (pRequest->id, SertafiedResType, (pointer) pRequest))
117706f2543Smrg	return FALSE;
118706f2543Smrg    if (!notifyFunc)
119706f2543Smrg	notifyFunc = ClientAwaken;
120706f2543Smrg    pRequest->notifyFunc = notifyFunc;
121706f2543Smrg    /* Insert into time-ordered queue, with earliest activation time coming first. */
122706f2543Smrg    pPrev = 0;
123706f2543Smrg    for (pReq = pPending; pReq; pReq = pReq->next)
124706f2543Smrg    {
125706f2543Smrg	if (CompareTimeStamps (pReq->revive, *revive) == LATER)
126706f2543Smrg	    break;
127706f2543Smrg	pPrev = pReq;
128706f2543Smrg    }
129706f2543Smrg    if (pPrev)
130706f2543Smrg	pPrev->next = pRequest;
131706f2543Smrg    else
132706f2543Smrg	pPending = pRequest;
133706f2543Smrg    pRequest->next = pReq;
134706f2543Smrg    IgnoreClient (client);
135706f2543Smrg    return TRUE;
136706f2543Smrg}
137706f2543Smrg
138706f2543Smrgstatic void
139706f2543SmrgClientAwaken (ClientPtr client, pointer closure)
140706f2543Smrg{
141706f2543Smrg    if (!client->clientGone)
142706f2543Smrg	AttendClient (client);
143706f2543Smrg}
144706f2543Smrg
145706f2543Smrg
146706f2543Smrgstatic int
147706f2543SmrgSertafiedDelete (pointer value, XID id)
148706f2543Smrg{
149706f2543Smrg    SertafiedPtr	pRequest = (SertafiedPtr)value;
150706f2543Smrg    SertafiedPtr	pReq, pPrev;
151706f2543Smrg
152706f2543Smrg    pPrev = 0;
153706f2543Smrg    for (pReq = pPending; pReq; pPrev = pReq, pReq = pReq->next)
154706f2543Smrg	if (pReq == pRequest)
155706f2543Smrg	{
156706f2543Smrg	    if (pPrev)
157706f2543Smrg		pPrev->next = pReq->next;
158706f2543Smrg	    else
159706f2543Smrg		pPending = pReq->next;
160706f2543Smrg	    break;
161706f2543Smrg	}
162706f2543Smrg    if (pRequest->notifyFunc)
163706f2543Smrg	(*pRequest->notifyFunc) (pRequest->pClient, pRequest->closure);
164706f2543Smrg    free(pRequest);
165706f2543Smrg    return TRUE;
166706f2543Smrg}
167706f2543Smrg
168706f2543Smrgstatic void
169706f2543SmrgSertafiedBlockHandler (pointer data, OSTimePtr wt, pointer LastSelectMask)
170706f2543Smrg{
171706f2543Smrg    SertafiedPtr	    pReq, pNext;
172706f2543Smrg    unsigned long	    delay;
173706f2543Smrg    TimeStamp		    now;
174706f2543Smrg
175706f2543Smrg    if (!pPending)
176706f2543Smrg	return;
177706f2543Smrg    now.milliseconds = GetTimeInMillis ();
178706f2543Smrg    now.months = currentTime.months;
179706f2543Smrg    if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
180706f2543Smrg	now.months++;
181706f2543Smrg    for (pReq = pPending; pReq; pReq = pNext)
182706f2543Smrg    {
183706f2543Smrg	pNext = pReq->next;
184706f2543Smrg	if (CompareTimeStamps (pReq->revive, now) == LATER)
185706f2543Smrg	    break;
186706f2543Smrg	FreeResource (pReq->id, RT_NONE);
187706f2543Smrg
188706f2543Smrg 	/* AttendClient() may have been called via the resource delete
189706f2543Smrg 	 * function so a client may have input to be processed and so
190706f2543Smrg 	 *  set delay to 0 to prevent blocking in WaitForSomething().
191706f2543Smrg 	 */
192706f2543Smrg 	AdjustWaitForDelay (wt, 0);
193706f2543Smrg    }
194706f2543Smrg    pReq = pPending;
195706f2543Smrg    if (!pReq)
196706f2543Smrg	return;
197706f2543Smrg    delay = pReq->revive.milliseconds - now.milliseconds;
198706f2543Smrg    AdjustWaitForDelay (wt, delay);
199706f2543Smrg}
200706f2543Smrg
201706f2543Smrgstatic void
202706f2543SmrgSertafiedWakeupHandler (pointer data, int i, pointer LastSelectMask)
203706f2543Smrg{
204706f2543Smrg    SertafiedPtr	pReq, pNext;
205706f2543Smrg    TimeStamp		now;
206706f2543Smrg
207706f2543Smrg    now.milliseconds = GetTimeInMillis ();
208706f2543Smrg    now.months = currentTime.months;
209706f2543Smrg    if ((int) (now.milliseconds - currentTime.milliseconds) < 0)
210706f2543Smrg	now.months++;
211706f2543Smrg    for (pReq = pPending; pReq; pReq = pNext)
212706f2543Smrg    {
213706f2543Smrg	pNext = pReq->next;
214706f2543Smrg	if (CompareTimeStamps (pReq->revive, now) == LATER)
215706f2543Smrg	    break;
216706f2543Smrg	FreeResource (pReq->id, RT_NONE);
217706f2543Smrg    }
218706f2543Smrg    if (!pPending)
219706f2543Smrg    {
220706f2543Smrg	RemoveBlockAndWakeupHandlers (SertafiedBlockHandler,
221706f2543Smrg				      SertafiedWakeupHandler,
222706f2543Smrg				      (pointer) 0);
223706f2543Smrg	BlockHandlerRegistered = FALSE;
224706f2543Smrg    }
225706f2543Smrg}
226