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