dixutils.c revision b86d567b
105b261ecSmrg/*********************************************************** 205b261ecSmrg 305b261ecSmrgCopyright 1987, 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 2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 2705b261ecSmrg 2805b261ecSmrg All Rights Reserved 2905b261ecSmrg 3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its 3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted, 3205b261ecSmrgprovided that the above copyright notice appear in all copies and that 3305b261ecSmrgboth that copyright notice and this permission notice appear in 3405b261ecSmrgsupporting documentation, and that the name of Digital not be 3505b261ecSmrgused in advertising or publicity pertaining to distribution of the 3605b261ecSmrgsoftware without specific, written prior permission. 3705b261ecSmrg 3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 4405b261ecSmrgSOFTWARE. 4505b261ecSmrg 4605b261ecSmrg******************************************************************/ 4705b261ecSmrg 4805b261ecSmrg/* 4905b261ecSmrg 5005b261ecSmrg(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved. 5105b261ecSmrg 5205b261ecSmrgPermission to use, copy, modify, distribute, and sublicense this software and its 5305b261ecSmrgdocumentation for any purpose and without fee is hereby granted, provided that 5405b261ecSmrgthe above copyright notices appear in all copies and that both those copyright 5505b261ecSmrgnotices and this permission notice appear in supporting documentation and that 5605b261ecSmrgthe name of Adobe Systems Incorporated not be used in advertising or publicity 5705b261ecSmrgpertaining to distribution of the software without specific, written prior 5805b261ecSmrgpermission. No trademark license to use the Adobe trademarks is hereby 5905b261ecSmrggranted. If the Adobe trademark "Display PostScript"(tm) is used to describe 6005b261ecSmrgthis software, its functionality or for any other purpose, such use shall be 6105b261ecSmrglimited to a statement that this software works in conjunction with the Display 6205b261ecSmrgPostScript system. Proper trademark attribution to reflect Adobe's ownership 6305b261ecSmrgof the trademark shall be given whenever any such reference to the Display 6405b261ecSmrgPostScript system is made. 6505b261ecSmrg 6605b261ecSmrgADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY 6705b261ecSmrgPURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE 6805b261ecSmrgDISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED 6905b261ecSmrgWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- 7005b261ecSmrgINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU 7105b261ecSmrgOR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY 7205b261ecSmrgDAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT 7305b261ecSmrgLIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR 7405b261ecSmrgPERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER 7505b261ecSmrgSUPPORT FOR THE SOFTWARE. 7605b261ecSmrg 7705b261ecSmrgAdobe, PostScript, and Display PostScript are trademarks of Adobe Systems 7805b261ecSmrgIncorporated which may be registered in certain jurisdictions. 7905b261ecSmrg 8005b261ecSmrgAuthor: Adobe Systems Incorporated 8105b261ecSmrg 8205b261ecSmrg*/ 8305b261ecSmrg 8405b261ecSmrg 8505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 8605b261ecSmrg#include <dix-config.h> 8705b261ecSmrg#endif 8805b261ecSmrg 8905b261ecSmrg#include <X11/X.h> 9005b261ecSmrg#include <X11/Xmd.h> 9105b261ecSmrg#include "misc.h" 9205b261ecSmrg#include "windowstr.h" 9305b261ecSmrg#include "dixstruct.h" 9405b261ecSmrg#include "pixmapstr.h" 9505b261ecSmrg#include "scrnintstr.h" 9605b261ecSmrg#define XK_LATIN1 9705b261ecSmrg#include <X11/keysymdef.h> 9805b261ecSmrg#include "xace.h" 9905b261ecSmrg 10005b261ecSmrg/* 10105b261ecSmrg * CompareTimeStamps returns -1, 0, or +1 depending on if the first 10205b261ecSmrg * argument is less than, equal to or greater than the second argument. 10305b261ecSmrg */ 10405b261ecSmrg 10505b261ecSmrg_X_EXPORT int 10605b261ecSmrgCompareTimeStamps(TimeStamp a, TimeStamp b) 10705b261ecSmrg{ 10805b261ecSmrg if (a.months < b.months) 10905b261ecSmrg return EARLIER; 11005b261ecSmrg if (a.months > b.months) 11105b261ecSmrg return LATER; 11205b261ecSmrg if (a.milliseconds < b.milliseconds) 11305b261ecSmrg return EARLIER; 11405b261ecSmrg if (a.milliseconds > b.milliseconds) 11505b261ecSmrg return LATER; 11605b261ecSmrg return SAMETIME; 11705b261ecSmrg} 11805b261ecSmrg 11905b261ecSmrg/* 12005b261ecSmrg * convert client times to server TimeStamps 12105b261ecSmrg */ 12205b261ecSmrg 12305b261ecSmrg#define HALFMONTH ((unsigned long) 1<<31) 12405b261ecSmrg_X_EXPORT TimeStamp 12505b261ecSmrgClientTimeToServerTime(CARD32 c) 12605b261ecSmrg{ 12705b261ecSmrg TimeStamp ts; 12805b261ecSmrg if (c == CurrentTime) 12905b261ecSmrg return currentTime; 13005b261ecSmrg ts.months = currentTime.months; 13105b261ecSmrg ts.milliseconds = c; 13205b261ecSmrg if (c > currentTime.milliseconds) 13305b261ecSmrg { 13405b261ecSmrg if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH) 13505b261ecSmrg ts.months -= 1; 13605b261ecSmrg } 13705b261ecSmrg else if (c < currentTime.milliseconds) 13805b261ecSmrg { 13905b261ecSmrg if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH) 14005b261ecSmrg ts.months += 1; 14105b261ecSmrg } 14205b261ecSmrg return ts; 14305b261ecSmrg} 14405b261ecSmrg 14505b261ecSmrg/* 14605b261ecSmrg * ISO Latin-1 case conversion routine 14705b261ecSmrg * 14805b261ecSmrg * this routine always null-terminates the result, so 14905b261ecSmrg * beware of too-small buffers 15005b261ecSmrg */ 15105b261ecSmrg 15205b261ecSmrgstatic unsigned char 15305b261ecSmrgISOLatin1ToLower (unsigned char source) 15405b261ecSmrg{ 15505b261ecSmrg unsigned char dest; 15605b261ecSmrg if ((source >= XK_A) && (source <= XK_Z)) 15705b261ecSmrg dest = source + (XK_a - XK_A); 15805b261ecSmrg else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis)) 15905b261ecSmrg dest = source + (XK_agrave - XK_Agrave); 16005b261ecSmrg else if ((source >= XK_Ooblique) && (source <= XK_Thorn)) 16105b261ecSmrg dest = source + (XK_oslash - XK_Ooblique); 16205b261ecSmrg else 16305b261ecSmrg dest = source; 16405b261ecSmrg return dest; 16505b261ecSmrg} 16605b261ecSmrg 16705b261ecSmrg 16805b261ecSmrg_X_EXPORT void 16905b261ecSmrgCopyISOLatin1Lowered(unsigned char *dest, unsigned char *source, int length) 17005b261ecSmrg{ 17105b261ecSmrg int i; 17205b261ecSmrg 17305b261ecSmrg for (i = 0; i < length; i++, source++, dest++) 17405b261ecSmrg *dest = ISOLatin1ToLower (*source); 17505b261ecSmrg *dest = '\0'; 17605b261ecSmrg} 17705b261ecSmrg 17805b261ecSmrgint 17905b261ecSmrgCompareISOLatin1Lowered(unsigned char *s1, int s1len, 18005b261ecSmrg unsigned char *s2, int s2len) 18105b261ecSmrg{ 18205b261ecSmrg unsigned char c1, c2; 18305b261ecSmrg 18405b261ecSmrg for (;;) 18505b261ecSmrg { 18605b261ecSmrg /* note -- compare against zero so that -1 ignores len */ 18705b261ecSmrg c1 = s1len-- ? *s1++ : '\0'; 18805b261ecSmrg c2 = s2len-- ? *s2++ : '\0'; 18905b261ecSmrg if (!c1 || 19005b261ecSmrg (c1 != c2 && 19105b261ecSmrg (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2)))) 19205b261ecSmrg break; 19305b261ecSmrg } 19405b261ecSmrg return (int) c1 - (int) c2; 19505b261ecSmrg} 19605b261ecSmrg 19705b261ecSmrg/* 19805b261ecSmrg * dixLookupWindow and dixLookupDrawable: 19905b261ecSmrg * Look up the window/drawable taking into account the client doing the 20005b261ecSmrg * lookup, the type of drawable desired, and the type of access desired. 20105b261ecSmrg * Return Success with *pDraw set if the window/drawable exists and the client 20205b261ecSmrg * is allowed access, else return an error code with *pDraw set to NULL. The 20305b261ecSmrg * access mask values are defined in resource.h. The type mask values are 20405b261ecSmrg * defined in pixmap.h, with zero equivalent to M_DRAWABLE. 20505b261ecSmrg */ 20605b261ecSmrg_X_EXPORT int 20705b261ecSmrgdixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client, 20805b261ecSmrg Mask type, Mask access) 20905b261ecSmrg{ 21005b261ecSmrg DrawablePtr pTmp; 2114642e01fSmrg int rc; 2124642e01fSmrg 21305b261ecSmrg *pDraw = NULL; 21405b261ecSmrg client->errorValue = id; 21505b261ecSmrg 21605b261ecSmrg if (id == INVALID) 21705b261ecSmrg return BadDrawable; 21805b261ecSmrg 219b86d567bSmrg rc = dixLookupResourceByClass((pointer *)&pTmp, id, RC_DRAWABLE, client, access); 2204642e01fSmrg 2214642e01fSmrg if (rc == BadValue) 22205b261ecSmrg return BadDrawable; 2234642e01fSmrg if (rc != Success) 2244642e01fSmrg return rc; 22505b261ecSmrg if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE))) 22605b261ecSmrg return BadMatch; 22705b261ecSmrg 22805b261ecSmrg *pDraw = pTmp; 22905b261ecSmrg return Success; 23005b261ecSmrg} 23105b261ecSmrg 23205b261ecSmrg_X_EXPORT int 23305b261ecSmrgdixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access) 23405b261ecSmrg{ 23505b261ecSmrg int rc; 23605b261ecSmrg rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access); 23705b261ecSmrg return (rc == BadDrawable) ? BadWindow : rc; 23805b261ecSmrg} 23905b261ecSmrg 24005b261ecSmrg_X_EXPORT int 24105b261ecSmrgdixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access) 24205b261ecSmrg{ 24305b261ecSmrg GCPtr pTmp = (GCPtr)SecurityLookupIDByType(client, id, RT_GC, access); 24405b261ecSmrg if (pTmp) { 24505b261ecSmrg *pGC = pTmp; 24605b261ecSmrg return Success; 24705b261ecSmrg } 24805b261ecSmrg client->errorValue = id; 24905b261ecSmrg *pGC = NULL; 25005b261ecSmrg return BadGC; 25105b261ecSmrg} 25205b261ecSmrg 25305b261ecSmrg_X_EXPORT int 25405b261ecSmrgdixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access) 25505b261ecSmrg{ 2564642e01fSmrg pointer pRes; 2574642e01fSmrg int rc = BadValue, clientIndex = CLIENT_ID(rid); 25805b261ecSmrg 2594642e01fSmrg if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT)) 2604642e01fSmrg goto bad; 26105b261ecSmrg 262b86d567bSmrg rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess); 2634642e01fSmrg if (rc != Success) 2644642e01fSmrg goto bad; 26505b261ecSmrg 2664642e01fSmrg rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access); 2674642e01fSmrg if (rc != Success) 2684642e01fSmrg goto bad; 26905b261ecSmrg 2704642e01fSmrg *pClient = clients[clientIndex]; 2714642e01fSmrg return Success; 2724642e01fSmrgbad: 2734642e01fSmrg if(client) 2744642e01fSmrg client->errorValue = rid; 2754642e01fSmrg *pClient = NULL; 2764642e01fSmrg return rc; 27705b261ecSmrg} 27805b261ecSmrg 27905b261ecSmrgint 28005b261ecSmrgAlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, 2814642e01fSmrg Bool toRoot, Bool map) 28205b261ecSmrg{ 28305b261ecSmrg int numnow; 28405b261ecSmrg SaveSetElt *pTmp = NULL; 28505b261ecSmrg int j; 28605b261ecSmrg 28705b261ecSmrg numnow = client->numSaved; 28805b261ecSmrg j = 0; 28905b261ecSmrg if (numnow) 29005b261ecSmrg { 29105b261ecSmrg pTmp = client->saveSet; 29205b261ecSmrg while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin)) 29305b261ecSmrg j++; 29405b261ecSmrg } 29505b261ecSmrg if (mode == SetModeInsert) 29605b261ecSmrg { 29705b261ecSmrg if (j < numnow) /* duplicate */ 29805b261ecSmrg return(Success); 29905b261ecSmrg numnow++; 30005b261ecSmrg pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); 30105b261ecSmrg if (!pTmp) 30205b261ecSmrg return(BadAlloc); 30305b261ecSmrg client->saveSet = pTmp; 30405b261ecSmrg client->numSaved = numnow; 30505b261ecSmrg SaveSetAssignWindow(client->saveSet[numnow - 1], pWin); 30605b261ecSmrg SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot); 3074642e01fSmrg SaveSetAssignMap(client->saveSet[numnow - 1], map); 30805b261ecSmrg return(Success); 30905b261ecSmrg } 31005b261ecSmrg else if ((mode == SetModeDelete) && (j < numnow)) 31105b261ecSmrg { 31205b261ecSmrg while (j < numnow-1) 31305b261ecSmrg { 31405b261ecSmrg pTmp[j] = pTmp[j+1]; 31505b261ecSmrg j++; 31605b261ecSmrg } 31705b261ecSmrg numnow--; 31805b261ecSmrg if (numnow) 31905b261ecSmrg { 32005b261ecSmrg pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); 32105b261ecSmrg if (pTmp) 32205b261ecSmrg client->saveSet = pTmp; 32305b261ecSmrg } 32405b261ecSmrg else 32505b261ecSmrg { 32605b261ecSmrg xfree(client->saveSet); 32705b261ecSmrg client->saveSet = (SaveSetElt *)NULL; 32805b261ecSmrg } 32905b261ecSmrg client->numSaved = numnow; 33005b261ecSmrg return(Success); 33105b261ecSmrg } 33205b261ecSmrg return(Success); 33305b261ecSmrg} 33405b261ecSmrg 33505b261ecSmrgvoid 33605b261ecSmrgDeleteWindowFromAnySaveSet(WindowPtr pWin) 33705b261ecSmrg{ 33805b261ecSmrg int i; 33905b261ecSmrg ClientPtr client; 34005b261ecSmrg 34105b261ecSmrg for (i = 0; i< currentMaxClients; i++) 34205b261ecSmrg { 34305b261ecSmrg client = clients[i]; 34405b261ecSmrg if (client && client->numSaved) 34505b261ecSmrg (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE); 34605b261ecSmrg } 34705b261ecSmrg} 34805b261ecSmrg 34905b261ecSmrg/* No-op Don't Do Anything : sometimes we need to be able to call a procedure 35005b261ecSmrg * that doesn't do anything. For example, on screen with only static 35105b261ecSmrg * colormaps, if someone calls install colormap, it's easier to have a dummy 35205b261ecSmrg * procedure to call than to check if there's a procedure 35305b261ecSmrg */ 35405b261ecSmrg_X_EXPORT void 35505b261ecSmrgNoopDDA(void) 35605b261ecSmrg{ 35705b261ecSmrg} 35805b261ecSmrg 35905b261ecSmrgtypedef struct _BlockHandler { 36005b261ecSmrg BlockHandlerProcPtr BlockHandler; 36105b261ecSmrg WakeupHandlerProcPtr WakeupHandler; 36205b261ecSmrg pointer blockData; 36305b261ecSmrg Bool deleted; 36405b261ecSmrg} BlockHandlerRec, *BlockHandlerPtr; 36505b261ecSmrg 36605b261ecSmrgstatic BlockHandlerPtr handlers; 36705b261ecSmrgstatic int numHandlers; 36805b261ecSmrgstatic int sizeHandlers; 36905b261ecSmrgstatic Bool inHandler; 37005b261ecSmrgstatic Bool handlerDeleted; 37105b261ecSmrg 37205b261ecSmrg/** 37305b261ecSmrg * 37405b261ecSmrg * \param pTimeout DIX doesn't want to know how OS represents time 37505b261ecSmrg * \param pReadMask nor how it represents the det of descriptors 37605b261ecSmrg */ 37705b261ecSmrgvoid 37805b261ecSmrgBlockHandler(pointer pTimeout, pointer pReadmask) 37905b261ecSmrg{ 38005b261ecSmrg int i, j; 38105b261ecSmrg 38205b261ecSmrg ++inHandler; 38305b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 38405b261ecSmrg (* screenInfo.screens[i]->BlockHandler)(i, 38505b261ecSmrg screenInfo.screens[i]->blockData, 38605b261ecSmrg pTimeout, pReadmask); 38705b261ecSmrg for (i = 0; i < numHandlers; i++) 38805b261ecSmrg (*handlers[i].BlockHandler) (handlers[i].blockData, 38905b261ecSmrg pTimeout, pReadmask); 39005b261ecSmrg if (handlerDeleted) 39105b261ecSmrg { 39205b261ecSmrg for (i = 0; i < numHandlers;) 39305b261ecSmrg if (handlers[i].deleted) 39405b261ecSmrg { 39505b261ecSmrg for (j = i; j < numHandlers - 1; j++) 39605b261ecSmrg handlers[j] = handlers[j+1]; 39705b261ecSmrg numHandlers--; 39805b261ecSmrg } 39905b261ecSmrg else 40005b261ecSmrg i++; 40105b261ecSmrg handlerDeleted = FALSE; 40205b261ecSmrg } 40305b261ecSmrg --inHandler; 40405b261ecSmrg} 40505b261ecSmrg 40605b261ecSmrg/** 40705b261ecSmrg * 40805b261ecSmrg * \param result 32 bits of undefined result from the wait 40905b261ecSmrg * \param pReadmask the resulting descriptor mask 41005b261ecSmrg */ 41105b261ecSmrgvoid 41205b261ecSmrgWakeupHandler(int result, pointer pReadmask) 41305b261ecSmrg{ 41405b261ecSmrg int i, j; 41505b261ecSmrg 41605b261ecSmrg ++inHandler; 41705b261ecSmrg for (i = numHandlers - 1; i >= 0; i--) 41805b261ecSmrg (*handlers[i].WakeupHandler) (handlers[i].blockData, 41905b261ecSmrg result, pReadmask); 42005b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 42105b261ecSmrg (* screenInfo.screens[i]->WakeupHandler)(i, 42205b261ecSmrg screenInfo.screens[i]->wakeupData, 42305b261ecSmrg result, pReadmask); 42405b261ecSmrg if (handlerDeleted) 42505b261ecSmrg { 42605b261ecSmrg for (i = 0; i < numHandlers;) 42705b261ecSmrg if (handlers[i].deleted) 42805b261ecSmrg { 42905b261ecSmrg for (j = i; j < numHandlers - 1; j++) 43005b261ecSmrg handlers[j] = handlers[j+1]; 43105b261ecSmrg numHandlers--; 43205b261ecSmrg } 43305b261ecSmrg else 43405b261ecSmrg i++; 43505b261ecSmrg handlerDeleted = FALSE; 43605b261ecSmrg } 43705b261ecSmrg --inHandler; 43805b261ecSmrg} 43905b261ecSmrg 44005b261ecSmrg/** 44105b261ecSmrg * Reentrant with BlockHandler and WakeupHandler, except wakeup won't 44205b261ecSmrg * get called until next time 44305b261ecSmrg */ 44405b261ecSmrg_X_EXPORT Bool 44505b261ecSmrgRegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, 44605b261ecSmrg WakeupHandlerProcPtr wakeupHandler, 44705b261ecSmrg pointer blockData) 44805b261ecSmrg{ 44905b261ecSmrg BlockHandlerPtr new; 45005b261ecSmrg 45105b261ecSmrg if (numHandlers >= sizeHandlers) 45205b261ecSmrg { 45305b261ecSmrg new = (BlockHandlerPtr) xrealloc (handlers, (numHandlers + 1) * 45405b261ecSmrg sizeof (BlockHandlerRec)); 45505b261ecSmrg if (!new) 45605b261ecSmrg return FALSE; 45705b261ecSmrg handlers = new; 45805b261ecSmrg sizeHandlers = numHandlers + 1; 45905b261ecSmrg } 46005b261ecSmrg handlers[numHandlers].BlockHandler = blockHandler; 46105b261ecSmrg handlers[numHandlers].WakeupHandler = wakeupHandler; 46205b261ecSmrg handlers[numHandlers].blockData = blockData; 46305b261ecSmrg handlers[numHandlers].deleted = FALSE; 46405b261ecSmrg numHandlers = numHandlers + 1; 46505b261ecSmrg return TRUE; 46605b261ecSmrg} 46705b261ecSmrg 46805b261ecSmrg_X_EXPORT void 46905b261ecSmrgRemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, 47005b261ecSmrg WakeupHandlerProcPtr wakeupHandler, 47105b261ecSmrg pointer blockData) 47205b261ecSmrg{ 47305b261ecSmrg int i; 47405b261ecSmrg 47505b261ecSmrg for (i = 0; i < numHandlers; i++) 47605b261ecSmrg if (handlers[i].BlockHandler == blockHandler && 47705b261ecSmrg handlers[i].WakeupHandler == wakeupHandler && 47805b261ecSmrg handlers[i].blockData == blockData) 47905b261ecSmrg { 48005b261ecSmrg if (inHandler) 48105b261ecSmrg { 48205b261ecSmrg handlerDeleted = TRUE; 48305b261ecSmrg handlers[i].deleted = TRUE; 48405b261ecSmrg } 48505b261ecSmrg else 48605b261ecSmrg { 48705b261ecSmrg for (; i < numHandlers - 1; i++) 48805b261ecSmrg handlers[i] = handlers[i+1]; 48905b261ecSmrg numHandlers--; 49005b261ecSmrg } 49105b261ecSmrg break; 49205b261ecSmrg } 49305b261ecSmrg} 49405b261ecSmrg 49505b261ecSmrgvoid 49605b261ecSmrgInitBlockAndWakeupHandlers (void) 49705b261ecSmrg{ 49805b261ecSmrg xfree (handlers); 49905b261ecSmrg handlers = (BlockHandlerPtr) 0; 50005b261ecSmrg numHandlers = 0; 50105b261ecSmrg sizeHandlers = 0; 50205b261ecSmrg} 50305b261ecSmrg 50405b261ecSmrg/* 50505b261ecSmrg * A general work queue. Perform some task before the server 50605b261ecSmrg * sleeps for input. 50705b261ecSmrg */ 50805b261ecSmrg 50905b261ecSmrgWorkQueuePtr workQueue; 51005b261ecSmrgstatic WorkQueuePtr *workQueueLast = &workQueue; 51105b261ecSmrg 51205b261ecSmrgvoid 51305b261ecSmrgProcessWorkQueue(void) 51405b261ecSmrg{ 51505b261ecSmrg WorkQueuePtr q, *p; 51605b261ecSmrg 51705b261ecSmrg p = &workQueue; 51805b261ecSmrg /* 51905b261ecSmrg * Scan the work queue once, calling each function. Those 52005b261ecSmrg * which return TRUE are removed from the queue, otherwise 52105b261ecSmrg * they will be called again. This must be reentrant with 52205b261ecSmrg * QueueWorkProc. 52305b261ecSmrg */ 52405b261ecSmrg while ((q = *p)) 52505b261ecSmrg { 52605b261ecSmrg if ((*q->function) (q->client, q->closure)) 52705b261ecSmrg { 52805b261ecSmrg /* remove q from the list */ 52905b261ecSmrg *p = q->next; /* don't fetch until after func called */ 53005b261ecSmrg xfree (q); 53105b261ecSmrg } 53205b261ecSmrg else 53305b261ecSmrg { 53405b261ecSmrg p = &q->next; /* don't fetch until after func called */ 53505b261ecSmrg } 53605b261ecSmrg } 53705b261ecSmrg workQueueLast = p; 53805b261ecSmrg} 53905b261ecSmrg 54005b261ecSmrgvoid 54105b261ecSmrgProcessWorkQueueZombies(void) 54205b261ecSmrg{ 54305b261ecSmrg WorkQueuePtr q, *p; 54405b261ecSmrg 54505b261ecSmrg p = &workQueue; 54605b261ecSmrg while ((q = *p)) 54705b261ecSmrg { 54805b261ecSmrg if (q->client && q->client->clientGone) 54905b261ecSmrg { 55005b261ecSmrg (void) (*q->function) (q->client, q->closure); 55105b261ecSmrg /* remove q from the list */ 55205b261ecSmrg *p = q->next; /* don't fetch until after func called */ 55305b261ecSmrg xfree (q); 55405b261ecSmrg } 55505b261ecSmrg else 55605b261ecSmrg { 55705b261ecSmrg p = &q->next; /* don't fetch until after func called */ 55805b261ecSmrg } 55905b261ecSmrg } 56005b261ecSmrg workQueueLast = p; 56105b261ecSmrg} 56205b261ecSmrg 56305b261ecSmrg_X_EXPORT Bool 56405b261ecSmrgQueueWorkProc ( 56505b261ecSmrg Bool (*function)(ClientPtr /* pClient */, pointer /* closure */), 56605b261ecSmrg ClientPtr client, pointer closure) 56705b261ecSmrg{ 56805b261ecSmrg WorkQueuePtr q; 56905b261ecSmrg 57005b261ecSmrg q = (WorkQueuePtr) xalloc (sizeof *q); 57105b261ecSmrg if (!q) 57205b261ecSmrg return FALSE; 57305b261ecSmrg q->function = function; 57405b261ecSmrg q->client = client; 57505b261ecSmrg q->closure = closure; 57605b261ecSmrg q->next = NULL; 57705b261ecSmrg *workQueueLast = q; 57805b261ecSmrg workQueueLast = &q->next; 57905b261ecSmrg return TRUE; 58005b261ecSmrg} 58105b261ecSmrg 58205b261ecSmrg/* 58305b261ecSmrg * Manage a queue of sleeping clients, awakening them 58405b261ecSmrg * when requested, by using the OS functions IgnoreClient 58505b261ecSmrg * and AttendClient. Note that this *ignores* the troubles 58605b261ecSmrg * with request data interleaving itself with events, but 58705b261ecSmrg * we'll leave that until a later time. 58805b261ecSmrg */ 58905b261ecSmrg 59005b261ecSmrgtypedef struct _SleepQueue { 59105b261ecSmrg struct _SleepQueue *next; 59205b261ecSmrg ClientPtr client; 59305b261ecSmrg ClientSleepProcPtr function; 59405b261ecSmrg pointer closure; 59505b261ecSmrg} SleepQueueRec, *SleepQueuePtr; 59605b261ecSmrg 59705b261ecSmrgstatic SleepQueuePtr sleepQueue = NULL; 59805b261ecSmrg 59905b261ecSmrg_X_EXPORT Bool 60005b261ecSmrgClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure) 60105b261ecSmrg{ 60205b261ecSmrg SleepQueuePtr q; 60305b261ecSmrg 60405b261ecSmrg q = (SleepQueuePtr) xalloc (sizeof *q); 60505b261ecSmrg if (!q) 60605b261ecSmrg return FALSE; 60705b261ecSmrg 60805b261ecSmrg IgnoreClient (client); 60905b261ecSmrg q->next = sleepQueue; 61005b261ecSmrg q->client = client; 61105b261ecSmrg q->function = function; 61205b261ecSmrg q->closure = closure; 61305b261ecSmrg sleepQueue = q; 61405b261ecSmrg return TRUE; 61505b261ecSmrg} 61605b261ecSmrg 61705b261ecSmrgBool 61805b261ecSmrgClientSignal (ClientPtr client) 61905b261ecSmrg{ 62005b261ecSmrg SleepQueuePtr q; 62105b261ecSmrg 62205b261ecSmrg for (q = sleepQueue; q; q = q->next) 62305b261ecSmrg if (q->client == client) 62405b261ecSmrg { 62505b261ecSmrg return QueueWorkProc (q->function, q->client, q->closure); 62605b261ecSmrg } 62705b261ecSmrg return FALSE; 62805b261ecSmrg} 62905b261ecSmrg 63005b261ecSmrg_X_EXPORT void 63105b261ecSmrgClientWakeup (ClientPtr client) 63205b261ecSmrg{ 63305b261ecSmrg SleepQueuePtr q, *prev; 63405b261ecSmrg 63505b261ecSmrg prev = &sleepQueue; 63605b261ecSmrg while ( (q = *prev) ) 63705b261ecSmrg { 63805b261ecSmrg if (q->client == client) 63905b261ecSmrg { 64005b261ecSmrg *prev = q->next; 64105b261ecSmrg xfree (q); 64205b261ecSmrg if (client->clientGone) 64305b261ecSmrg /* Oops -- new zombie cleanup code ensures this only 64405b261ecSmrg * happens from inside CloseDownClient; don't want to 64505b261ecSmrg * recurse here... 64605b261ecSmrg */ 64705b261ecSmrg /* CloseDownClient(client) */; 64805b261ecSmrg else 64905b261ecSmrg AttendClient (client); 65005b261ecSmrg break; 65105b261ecSmrg } 65205b261ecSmrg prev = &q->next; 65305b261ecSmrg } 65405b261ecSmrg} 65505b261ecSmrg 65605b261ecSmrgBool 65705b261ecSmrgClientIsAsleep (ClientPtr client) 65805b261ecSmrg{ 65905b261ecSmrg SleepQueuePtr q; 66005b261ecSmrg 66105b261ecSmrg for (q = sleepQueue; q; q = q->next) 66205b261ecSmrg if (q->client == client) 66305b261ecSmrg return TRUE; 66405b261ecSmrg return FALSE; 66505b261ecSmrg} 66605b261ecSmrg 66705b261ecSmrg/* 66805b261ecSmrg * Generic Callback Manager 66905b261ecSmrg */ 67005b261ecSmrg 67105b261ecSmrg/* ===== Private Procedures ===== */ 67205b261ecSmrg 67305b261ecSmrgstatic int numCallbackListsToCleanup = 0; 67405b261ecSmrgstatic CallbackListPtr **listsToCleanup = NULL; 67505b261ecSmrg 67605b261ecSmrgstatic Bool 67705b261ecSmrg_AddCallback( 67805b261ecSmrg CallbackListPtr *pcbl, 67905b261ecSmrg CallbackProcPtr callback, 68005b261ecSmrg pointer data) 68105b261ecSmrg{ 68205b261ecSmrg CallbackPtr cbr; 68305b261ecSmrg 68405b261ecSmrg cbr = (CallbackPtr) xalloc(sizeof(CallbackRec)); 68505b261ecSmrg if (!cbr) 68605b261ecSmrg return FALSE; 68705b261ecSmrg cbr->proc = callback; 68805b261ecSmrg cbr->data = data; 68905b261ecSmrg cbr->next = (*pcbl)->list; 69005b261ecSmrg cbr->deleted = FALSE; 69105b261ecSmrg (*pcbl)->list = cbr; 69205b261ecSmrg return TRUE; 69305b261ecSmrg} 69405b261ecSmrg 69505b261ecSmrgstatic Bool 69605b261ecSmrg_DeleteCallback( 69705b261ecSmrg CallbackListPtr *pcbl, 69805b261ecSmrg CallbackProcPtr callback, 69905b261ecSmrg pointer data) 70005b261ecSmrg{ 70105b261ecSmrg CallbackListPtr cbl = *pcbl; 70205b261ecSmrg CallbackPtr cbr, pcbr; 70305b261ecSmrg 70405b261ecSmrg for (pcbr = NULL, cbr = cbl->list; 70505b261ecSmrg cbr != NULL; 70605b261ecSmrg pcbr = cbr, cbr = cbr->next) 70705b261ecSmrg { 70805b261ecSmrg if ((cbr->proc == callback) && (cbr->data == data)) 70905b261ecSmrg break; 71005b261ecSmrg } 71105b261ecSmrg if (cbr != NULL) 71205b261ecSmrg { 71305b261ecSmrg if (cbl->inCallback) 71405b261ecSmrg { 71505b261ecSmrg ++(cbl->numDeleted); 71605b261ecSmrg cbr->deleted = TRUE; 71705b261ecSmrg } 71805b261ecSmrg else 71905b261ecSmrg { 72005b261ecSmrg if (pcbr == NULL) 72105b261ecSmrg cbl->list = cbr->next; 72205b261ecSmrg else 72305b261ecSmrg pcbr->next = cbr->next; 72405b261ecSmrg xfree(cbr); 72505b261ecSmrg } 72605b261ecSmrg return TRUE; 72705b261ecSmrg } 72805b261ecSmrg return FALSE; 72905b261ecSmrg} 73005b261ecSmrg 73105b261ecSmrgstatic void 73205b261ecSmrg_CallCallbacks( 73305b261ecSmrg CallbackListPtr *pcbl, 73405b261ecSmrg pointer call_data) 73505b261ecSmrg{ 73605b261ecSmrg CallbackListPtr cbl = *pcbl; 73705b261ecSmrg CallbackPtr cbr, pcbr; 73805b261ecSmrg 73905b261ecSmrg ++(cbl->inCallback); 74005b261ecSmrg for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) 74105b261ecSmrg { 74205b261ecSmrg (*(cbr->proc)) (pcbl, cbr->data, call_data); 74305b261ecSmrg } 74405b261ecSmrg --(cbl->inCallback); 74505b261ecSmrg 74605b261ecSmrg if (cbl->inCallback) return; 74705b261ecSmrg 74805b261ecSmrg /* Was the entire list marked for deletion? */ 74905b261ecSmrg 75005b261ecSmrg if (cbl->deleted) 75105b261ecSmrg { 75205b261ecSmrg DeleteCallbackList(pcbl); 75305b261ecSmrg return; 75405b261ecSmrg } 75505b261ecSmrg 75605b261ecSmrg /* Were some individual callbacks on the list marked for deletion? 75705b261ecSmrg * If so, do the deletions. 75805b261ecSmrg */ 75905b261ecSmrg 76005b261ecSmrg if (cbl->numDeleted) 76105b261ecSmrg { 76205b261ecSmrg for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; ) 76305b261ecSmrg { 76405b261ecSmrg if (cbr->deleted) 76505b261ecSmrg { 76605b261ecSmrg if (pcbr) 76705b261ecSmrg { 76805b261ecSmrg cbr = cbr->next; 76905b261ecSmrg xfree(pcbr->next); 77005b261ecSmrg pcbr->next = cbr; 77105b261ecSmrg } else 77205b261ecSmrg { 77305b261ecSmrg cbr = cbr->next; 77405b261ecSmrg xfree(cbl->list); 77505b261ecSmrg cbl->list = cbr; 77605b261ecSmrg } 77705b261ecSmrg cbl->numDeleted--; 77805b261ecSmrg } 77905b261ecSmrg else /* this one wasn't deleted */ 78005b261ecSmrg { 78105b261ecSmrg pcbr = cbr; 78205b261ecSmrg cbr = cbr->next; 78305b261ecSmrg } 78405b261ecSmrg } 78505b261ecSmrg } 78605b261ecSmrg} 78705b261ecSmrg 78805b261ecSmrgstatic void 78905b261ecSmrg_DeleteCallbackList( 79005b261ecSmrg CallbackListPtr *pcbl) 79105b261ecSmrg{ 79205b261ecSmrg CallbackListPtr cbl = *pcbl; 79305b261ecSmrg CallbackPtr cbr, nextcbr; 79405b261ecSmrg int i; 79505b261ecSmrg 79605b261ecSmrg if (cbl->inCallback) 79705b261ecSmrg { 79805b261ecSmrg cbl->deleted = TRUE; 79905b261ecSmrg return; 80005b261ecSmrg } 80105b261ecSmrg 80205b261ecSmrg for (i = 0; i < numCallbackListsToCleanup; i++) 80305b261ecSmrg { 8044642e01fSmrg if (listsToCleanup[i] == pcbl) 80505b261ecSmrg { 80605b261ecSmrg listsToCleanup[i] = NULL; 80705b261ecSmrg break; 80805b261ecSmrg } 80905b261ecSmrg } 81005b261ecSmrg 81105b261ecSmrg for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) 81205b261ecSmrg { 81305b261ecSmrg nextcbr = cbr->next; 81405b261ecSmrg xfree(cbr); 81505b261ecSmrg } 81605b261ecSmrg xfree(cbl); 81705b261ecSmrg *pcbl = NULL; 81805b261ecSmrg} 81905b261ecSmrg 82005b261ecSmrgstatic Bool 8214642e01fSmrgCreateCallbackList(CallbackListPtr *pcbl) 82205b261ecSmrg{ 82305b261ecSmrg CallbackListPtr cbl; 82405b261ecSmrg int i; 82505b261ecSmrg 82605b261ecSmrg if (!pcbl) return FALSE; 82705b261ecSmrg cbl = (CallbackListPtr) xalloc(sizeof(CallbackListRec)); 82805b261ecSmrg if (!cbl) return FALSE; 82905b261ecSmrg cbl->inCallback = 0; 83005b261ecSmrg cbl->deleted = FALSE; 83105b261ecSmrg cbl->numDeleted = 0; 83205b261ecSmrg cbl->list = NULL; 83305b261ecSmrg *pcbl = cbl; 83405b261ecSmrg 83505b261ecSmrg for (i = 0; i < numCallbackListsToCleanup; i++) 83605b261ecSmrg { 83705b261ecSmrg if (!listsToCleanup[i]) 83805b261ecSmrg { 83905b261ecSmrg listsToCleanup[i] = pcbl; 84005b261ecSmrg return TRUE; 84105b261ecSmrg } 84205b261ecSmrg } 84305b261ecSmrg 84405b261ecSmrg listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup, 84505b261ecSmrg sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1)); 84605b261ecSmrg listsToCleanup[numCallbackListsToCleanup] = pcbl; 84705b261ecSmrg numCallbackListsToCleanup++; 84805b261ecSmrg return TRUE; 84905b261ecSmrg} 85005b261ecSmrg 85105b261ecSmrg/* ===== Public Procedures ===== */ 85205b261ecSmrg 85305b261ecSmrg_X_EXPORT Bool 85405b261ecSmrgAddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) 85505b261ecSmrg{ 85605b261ecSmrg if (!pcbl) return FALSE; 85705b261ecSmrg if (!*pcbl) 85805b261ecSmrg { /* list hasn't been created yet; go create it */ 8594642e01fSmrg if (!CreateCallbackList(pcbl)) 86005b261ecSmrg return FALSE; 86105b261ecSmrg } 8624642e01fSmrg return _AddCallback(pcbl, callback, data); 86305b261ecSmrg} 86405b261ecSmrg 86505b261ecSmrg_X_EXPORT Bool 86605b261ecSmrgDeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) 86705b261ecSmrg{ 86805b261ecSmrg if (!pcbl || !*pcbl) return FALSE; 8694642e01fSmrg return _DeleteCallback(pcbl, callback, data); 87005b261ecSmrg} 87105b261ecSmrg 87205b261ecSmrgvoid 87305b261ecSmrgCallCallbacks(CallbackListPtr *pcbl, pointer call_data) 87405b261ecSmrg{ 87505b261ecSmrg if (!pcbl || !*pcbl) return; 8764642e01fSmrg _CallCallbacks(pcbl, call_data); 87705b261ecSmrg} 87805b261ecSmrg 87905b261ecSmrgvoid 88005b261ecSmrgDeleteCallbackList(CallbackListPtr *pcbl) 88105b261ecSmrg{ 88205b261ecSmrg if (!pcbl || !*pcbl) return; 8834642e01fSmrg _DeleteCallbackList(pcbl); 88405b261ecSmrg} 88505b261ecSmrg 88605b261ecSmrgvoid 88705b261ecSmrgInitCallbackManager(void) 88805b261ecSmrg{ 88905b261ecSmrg int i; 89005b261ecSmrg 89105b261ecSmrg for (i = 0; i < numCallbackListsToCleanup; i++) 89205b261ecSmrg { 89305b261ecSmrg DeleteCallbackList(listsToCleanup[i]); 89405b261ecSmrg } 89505b261ecSmrg if (listsToCleanup) xfree(listsToCleanup); 89605b261ecSmrg 89705b261ecSmrg numCallbackListsToCleanup = 0; 89805b261ecSmrg listsToCleanup = NULL; 89905b261ecSmrg} 900