dixutils.c revision 6747b715
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" 956747b715Smrg#include "gcstruct.h" 9605b261ecSmrg#include "scrnintstr.h" 9705b261ecSmrg#define XK_LATIN1 9805b261ecSmrg#include <X11/keysymdef.h> 9905b261ecSmrg#include "xace.h" 10005b261ecSmrg 10105b261ecSmrg/* 10205b261ecSmrg * CompareTimeStamps returns -1, 0, or +1 depending on if the first 10305b261ecSmrg * argument is less than, equal to or greater than the second argument. 10405b261ecSmrg */ 10505b261ecSmrg 1066747b715Smrgint 10705b261ecSmrgCompareTimeStamps(TimeStamp a, TimeStamp b) 10805b261ecSmrg{ 10905b261ecSmrg if (a.months < b.months) 11005b261ecSmrg return EARLIER; 11105b261ecSmrg if (a.months > b.months) 11205b261ecSmrg return LATER; 11305b261ecSmrg if (a.milliseconds < b.milliseconds) 11405b261ecSmrg return EARLIER; 11505b261ecSmrg if (a.milliseconds > b.milliseconds) 11605b261ecSmrg return LATER; 11705b261ecSmrg return SAMETIME; 11805b261ecSmrg} 11905b261ecSmrg 12005b261ecSmrg/* 12105b261ecSmrg * convert client times to server TimeStamps 12205b261ecSmrg */ 12305b261ecSmrg 12405b261ecSmrg#define HALFMONTH ((unsigned long) 1<<31) 1256747b715SmrgTimeStamp 12605b261ecSmrgClientTimeToServerTime(CARD32 c) 12705b261ecSmrg{ 12805b261ecSmrg TimeStamp ts; 12905b261ecSmrg if (c == CurrentTime) 13005b261ecSmrg return currentTime; 13105b261ecSmrg ts.months = currentTime.months; 13205b261ecSmrg ts.milliseconds = c; 13305b261ecSmrg if (c > currentTime.milliseconds) 13405b261ecSmrg { 13505b261ecSmrg if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH) 13605b261ecSmrg ts.months -= 1; 13705b261ecSmrg } 13805b261ecSmrg else if (c < currentTime.milliseconds) 13905b261ecSmrg { 14005b261ecSmrg if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH) 14105b261ecSmrg ts.months += 1; 14205b261ecSmrg } 14305b261ecSmrg return ts; 14405b261ecSmrg} 14505b261ecSmrg 14605b261ecSmrg/* 14705b261ecSmrg * ISO Latin-1 case conversion routine 14805b261ecSmrg * 14905b261ecSmrg * this routine always null-terminates the result, so 15005b261ecSmrg * beware of too-small buffers 15105b261ecSmrg */ 15205b261ecSmrg 15305b261ecSmrgstatic unsigned char 15405b261ecSmrgISOLatin1ToLower (unsigned char source) 15505b261ecSmrg{ 15605b261ecSmrg unsigned char dest; 15705b261ecSmrg if ((source >= XK_A) && (source <= XK_Z)) 15805b261ecSmrg dest = source + (XK_a - XK_A); 15905b261ecSmrg else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis)) 16005b261ecSmrg dest = source + (XK_agrave - XK_Agrave); 16105b261ecSmrg else if ((source >= XK_Ooblique) && (source <= XK_Thorn)) 16205b261ecSmrg dest = source + (XK_oslash - XK_Ooblique); 16305b261ecSmrg else 16405b261ecSmrg dest = source; 16505b261ecSmrg return dest; 16605b261ecSmrg} 16705b261ecSmrg 16805b261ecSmrg 16905b261ecSmrgint 17005b261ecSmrgCompareISOLatin1Lowered(unsigned char *s1, int s1len, 17105b261ecSmrg unsigned char *s2, int s2len) 17205b261ecSmrg{ 17305b261ecSmrg unsigned char c1, c2; 17405b261ecSmrg 17505b261ecSmrg for (;;) 17605b261ecSmrg { 17705b261ecSmrg /* note -- compare against zero so that -1 ignores len */ 17805b261ecSmrg c1 = s1len-- ? *s1++ : '\0'; 17905b261ecSmrg c2 = s2len-- ? *s2++ : '\0'; 18005b261ecSmrg if (!c1 || 18105b261ecSmrg (c1 != c2 && 18205b261ecSmrg (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2)))) 18305b261ecSmrg break; 18405b261ecSmrg } 18505b261ecSmrg return (int) c1 - (int) c2; 18605b261ecSmrg} 18705b261ecSmrg 18805b261ecSmrg/* 18905b261ecSmrg * dixLookupWindow and dixLookupDrawable: 19005b261ecSmrg * Look up the window/drawable taking into account the client doing the 19105b261ecSmrg * lookup, the type of drawable desired, and the type of access desired. 19205b261ecSmrg * Return Success with *pDraw set if the window/drawable exists and the client 19305b261ecSmrg * is allowed access, else return an error code with *pDraw set to NULL. The 19405b261ecSmrg * access mask values are defined in resource.h. The type mask values are 19505b261ecSmrg * defined in pixmap.h, with zero equivalent to M_DRAWABLE. 19605b261ecSmrg */ 1976747b715Smrgint 19805b261ecSmrgdixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client, 19905b261ecSmrg Mask type, Mask access) 20005b261ecSmrg{ 20105b261ecSmrg DrawablePtr pTmp; 2024642e01fSmrg int rc; 2034642e01fSmrg 20405b261ecSmrg *pDraw = NULL; 20505b261ecSmrg client->errorValue = id; 20605b261ecSmrg 20705b261ecSmrg if (id == INVALID) 20805b261ecSmrg return BadDrawable; 20905b261ecSmrg 210b86d567bSmrg rc = dixLookupResourceByClass((pointer *)&pTmp, id, RC_DRAWABLE, client, access); 2114642e01fSmrg 2124642e01fSmrg if (rc == BadValue) 21305b261ecSmrg return BadDrawable; 2144642e01fSmrg if (rc != Success) 2154642e01fSmrg return rc; 21605b261ecSmrg if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE))) 21705b261ecSmrg return BadMatch; 21805b261ecSmrg 21905b261ecSmrg *pDraw = pTmp; 22005b261ecSmrg return Success; 22105b261ecSmrg} 22205b261ecSmrg 2236747b715Smrgint 22405b261ecSmrgdixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access) 22505b261ecSmrg{ 22605b261ecSmrg int rc; 22705b261ecSmrg rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access); 22805b261ecSmrg return (rc == BadDrawable) ? BadWindow : rc; 22905b261ecSmrg} 23005b261ecSmrg 2316747b715Smrgint 23205b261ecSmrgdixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access) 23305b261ecSmrg{ 2346747b715Smrg return dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access); 23505b261ecSmrg} 23605b261ecSmrg 2376747b715Smrgint 2386747b715SmrgdixLookupFontable(FontPtr *pFont, XID id, ClientPtr client, Mask access) 2396747b715Smrg{ 2406747b715Smrg int rc; 2416747b715Smrg GC *pGC; 2426747b715Smrg client->errorValue = id; /* EITHER font or gc */ 2436747b715Smrg rc = dixLookupResourceByType((pointer *) pFont, id, RT_FONT, client, access); 2446747b715Smrg if (rc != BadFont) 2456747b715Smrg return rc; 2466747b715Smrg rc = dixLookupResourceByType((pointer *) &pGC, id, RT_GC, client, access); 2476747b715Smrg if (rc == BadGC) 2486747b715Smrg return BadFont; 2496747b715Smrg if (rc == Success) 2506747b715Smrg *pFont = pGC->font; 2516747b715Smrg return rc; 2526747b715Smrg} 2536747b715Smrg 2546747b715Smrgint 25505b261ecSmrgdixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access) 25605b261ecSmrg{ 2574642e01fSmrg pointer pRes; 2584642e01fSmrg int rc = BadValue, clientIndex = CLIENT_ID(rid); 25905b261ecSmrg 2604642e01fSmrg if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT)) 2614642e01fSmrg goto bad; 26205b261ecSmrg 263b86d567bSmrg rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess); 2644642e01fSmrg if (rc != Success) 2654642e01fSmrg goto bad; 26605b261ecSmrg 2674642e01fSmrg rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access); 2684642e01fSmrg if (rc != Success) 2694642e01fSmrg goto bad; 27005b261ecSmrg 2714642e01fSmrg *pClient = clients[clientIndex]; 2724642e01fSmrg return Success; 2734642e01fSmrgbad: 2744642e01fSmrg if(client) 2754642e01fSmrg client->errorValue = rid; 2764642e01fSmrg *pClient = NULL; 2774642e01fSmrg return rc; 27805b261ecSmrg} 27905b261ecSmrg 28005b261ecSmrgint 28105b261ecSmrgAlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, 2824642e01fSmrg Bool toRoot, Bool map) 28305b261ecSmrg{ 28405b261ecSmrg int numnow; 28505b261ecSmrg SaveSetElt *pTmp = NULL; 28605b261ecSmrg int j; 28705b261ecSmrg 28805b261ecSmrg numnow = client->numSaved; 28905b261ecSmrg j = 0; 29005b261ecSmrg if (numnow) 29105b261ecSmrg { 29205b261ecSmrg pTmp = client->saveSet; 29305b261ecSmrg while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin)) 29405b261ecSmrg j++; 29505b261ecSmrg } 29605b261ecSmrg if (mode == SetModeInsert) 29705b261ecSmrg { 29805b261ecSmrg if (j < numnow) /* duplicate */ 2996747b715Smrg return Success; 30005b261ecSmrg numnow++; 3016747b715Smrg pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow); 30205b261ecSmrg if (!pTmp) 3036747b715Smrg return BadAlloc; 30405b261ecSmrg client->saveSet = pTmp; 30505b261ecSmrg client->numSaved = numnow; 30605b261ecSmrg SaveSetAssignWindow(client->saveSet[numnow - 1], pWin); 30705b261ecSmrg SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot); 3084642e01fSmrg SaveSetAssignMap(client->saveSet[numnow - 1], map); 3096747b715Smrg return Success; 31005b261ecSmrg } 31105b261ecSmrg else if ((mode == SetModeDelete) && (j < numnow)) 31205b261ecSmrg { 31305b261ecSmrg while (j < numnow-1) 31405b261ecSmrg { 31505b261ecSmrg pTmp[j] = pTmp[j+1]; 31605b261ecSmrg j++; 31705b261ecSmrg } 31805b261ecSmrg numnow--; 31905b261ecSmrg if (numnow) 32005b261ecSmrg { 3216747b715Smrg pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow); 32205b261ecSmrg if (pTmp) 32305b261ecSmrg client->saveSet = pTmp; 32405b261ecSmrg } 32505b261ecSmrg else 32605b261ecSmrg { 3276747b715Smrg free(client->saveSet); 32805b261ecSmrg client->saveSet = (SaveSetElt *)NULL; 32905b261ecSmrg } 33005b261ecSmrg client->numSaved = numnow; 3316747b715Smrg return Success; 33205b261ecSmrg } 3336747b715Smrg return Success; 33405b261ecSmrg} 33505b261ecSmrg 33605b261ecSmrgvoid 33705b261ecSmrgDeleteWindowFromAnySaveSet(WindowPtr pWin) 33805b261ecSmrg{ 33905b261ecSmrg int i; 34005b261ecSmrg ClientPtr client; 34105b261ecSmrg 34205b261ecSmrg for (i = 0; i< currentMaxClients; i++) 34305b261ecSmrg { 34405b261ecSmrg client = clients[i]; 34505b261ecSmrg if (client && client->numSaved) 34605b261ecSmrg (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE); 34705b261ecSmrg } 34805b261ecSmrg} 34905b261ecSmrg 35005b261ecSmrg/* No-op Don't Do Anything : sometimes we need to be able to call a procedure 35105b261ecSmrg * that doesn't do anything. For example, on screen with only static 35205b261ecSmrg * colormaps, if someone calls install colormap, it's easier to have a dummy 35305b261ecSmrg * procedure to call than to check if there's a procedure 35405b261ecSmrg */ 3556747b715Smrgvoid 35605b261ecSmrgNoopDDA(void) 35705b261ecSmrg{ 35805b261ecSmrg} 35905b261ecSmrg 36005b261ecSmrgtypedef struct _BlockHandler { 36105b261ecSmrg BlockHandlerProcPtr BlockHandler; 36205b261ecSmrg WakeupHandlerProcPtr WakeupHandler; 36305b261ecSmrg pointer blockData; 36405b261ecSmrg Bool deleted; 36505b261ecSmrg} BlockHandlerRec, *BlockHandlerPtr; 36605b261ecSmrg 36705b261ecSmrgstatic BlockHandlerPtr handlers; 36805b261ecSmrgstatic int numHandlers; 36905b261ecSmrgstatic int sizeHandlers; 37005b261ecSmrgstatic Bool inHandler; 37105b261ecSmrgstatic Bool handlerDeleted; 37205b261ecSmrg 37305b261ecSmrg/** 37405b261ecSmrg * 37505b261ecSmrg * \param pTimeout DIX doesn't want to know how OS represents time 37605b261ecSmrg * \param pReadMask nor how it represents the det of descriptors 37705b261ecSmrg */ 37805b261ecSmrgvoid 37905b261ecSmrgBlockHandler(pointer pTimeout, pointer pReadmask) 38005b261ecSmrg{ 38105b261ecSmrg int i, j; 38205b261ecSmrg 38305b261ecSmrg ++inHandler; 38405b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 38505b261ecSmrg (* screenInfo.screens[i]->BlockHandler)(i, 38605b261ecSmrg screenInfo.screens[i]->blockData, 38705b261ecSmrg pTimeout, pReadmask); 38805b261ecSmrg for (i = 0; i < numHandlers; i++) 38905b261ecSmrg (*handlers[i].BlockHandler) (handlers[i].blockData, 39005b261ecSmrg pTimeout, pReadmask); 39105b261ecSmrg if (handlerDeleted) 39205b261ecSmrg { 39305b261ecSmrg for (i = 0; i < numHandlers;) 39405b261ecSmrg if (handlers[i].deleted) 39505b261ecSmrg { 39605b261ecSmrg for (j = i; j < numHandlers - 1; j++) 39705b261ecSmrg handlers[j] = handlers[j+1]; 39805b261ecSmrg numHandlers--; 39905b261ecSmrg } 40005b261ecSmrg else 40105b261ecSmrg i++; 40205b261ecSmrg handlerDeleted = FALSE; 40305b261ecSmrg } 40405b261ecSmrg --inHandler; 40505b261ecSmrg} 40605b261ecSmrg 40705b261ecSmrg/** 40805b261ecSmrg * 40905b261ecSmrg * \param result 32 bits of undefined result from the wait 41005b261ecSmrg * \param pReadmask the resulting descriptor mask 41105b261ecSmrg */ 41205b261ecSmrgvoid 41305b261ecSmrgWakeupHandler(int result, pointer pReadmask) 41405b261ecSmrg{ 41505b261ecSmrg int i, j; 41605b261ecSmrg 41705b261ecSmrg ++inHandler; 41805b261ecSmrg for (i = numHandlers - 1; i >= 0; i--) 41905b261ecSmrg (*handlers[i].WakeupHandler) (handlers[i].blockData, 42005b261ecSmrg result, pReadmask); 42105b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 42205b261ecSmrg (* screenInfo.screens[i]->WakeupHandler)(i, 42305b261ecSmrg screenInfo.screens[i]->wakeupData, 42405b261ecSmrg result, pReadmask); 42505b261ecSmrg if (handlerDeleted) 42605b261ecSmrg { 42705b261ecSmrg for (i = 0; i < numHandlers;) 42805b261ecSmrg if (handlers[i].deleted) 42905b261ecSmrg { 43005b261ecSmrg for (j = i; j < numHandlers - 1; j++) 43105b261ecSmrg handlers[j] = handlers[j+1]; 43205b261ecSmrg numHandlers--; 43305b261ecSmrg } 43405b261ecSmrg else 43505b261ecSmrg i++; 43605b261ecSmrg handlerDeleted = FALSE; 43705b261ecSmrg } 43805b261ecSmrg --inHandler; 43905b261ecSmrg} 44005b261ecSmrg 44105b261ecSmrg/** 44205b261ecSmrg * Reentrant with BlockHandler and WakeupHandler, except wakeup won't 44305b261ecSmrg * get called until next time 44405b261ecSmrg */ 4456747b715SmrgBool 44605b261ecSmrgRegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, 44705b261ecSmrg WakeupHandlerProcPtr wakeupHandler, 44805b261ecSmrg pointer blockData) 44905b261ecSmrg{ 45005b261ecSmrg BlockHandlerPtr new; 45105b261ecSmrg 45205b261ecSmrg if (numHandlers >= sizeHandlers) 45305b261ecSmrg { 4546747b715Smrg new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) * 45505b261ecSmrg sizeof (BlockHandlerRec)); 45605b261ecSmrg if (!new) 45705b261ecSmrg return FALSE; 45805b261ecSmrg handlers = new; 45905b261ecSmrg sizeHandlers = numHandlers + 1; 46005b261ecSmrg } 46105b261ecSmrg handlers[numHandlers].BlockHandler = blockHandler; 46205b261ecSmrg handlers[numHandlers].WakeupHandler = wakeupHandler; 46305b261ecSmrg handlers[numHandlers].blockData = blockData; 46405b261ecSmrg handlers[numHandlers].deleted = FALSE; 46505b261ecSmrg numHandlers = numHandlers + 1; 46605b261ecSmrg return TRUE; 46705b261ecSmrg} 46805b261ecSmrg 4696747b715Smrgvoid 47005b261ecSmrgRemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, 47105b261ecSmrg WakeupHandlerProcPtr wakeupHandler, 47205b261ecSmrg pointer blockData) 47305b261ecSmrg{ 47405b261ecSmrg int i; 47505b261ecSmrg 47605b261ecSmrg for (i = 0; i < numHandlers; i++) 47705b261ecSmrg if (handlers[i].BlockHandler == blockHandler && 47805b261ecSmrg handlers[i].WakeupHandler == wakeupHandler && 47905b261ecSmrg handlers[i].blockData == blockData) 48005b261ecSmrg { 48105b261ecSmrg if (inHandler) 48205b261ecSmrg { 48305b261ecSmrg handlerDeleted = TRUE; 48405b261ecSmrg handlers[i].deleted = TRUE; 48505b261ecSmrg } 48605b261ecSmrg else 48705b261ecSmrg { 48805b261ecSmrg for (; i < numHandlers - 1; i++) 48905b261ecSmrg handlers[i] = handlers[i+1]; 49005b261ecSmrg numHandlers--; 49105b261ecSmrg } 49205b261ecSmrg break; 49305b261ecSmrg } 49405b261ecSmrg} 49505b261ecSmrg 49605b261ecSmrgvoid 49705b261ecSmrgInitBlockAndWakeupHandlers (void) 49805b261ecSmrg{ 4996747b715Smrg free(handlers); 50005b261ecSmrg handlers = (BlockHandlerPtr) 0; 50105b261ecSmrg numHandlers = 0; 50205b261ecSmrg sizeHandlers = 0; 50305b261ecSmrg} 50405b261ecSmrg 50505b261ecSmrg/* 50605b261ecSmrg * A general work queue. Perform some task before the server 50705b261ecSmrg * sleeps for input. 50805b261ecSmrg */ 50905b261ecSmrg 51005b261ecSmrgWorkQueuePtr workQueue; 51105b261ecSmrgstatic WorkQueuePtr *workQueueLast = &workQueue; 51205b261ecSmrg 51305b261ecSmrgvoid 51405b261ecSmrgProcessWorkQueue(void) 51505b261ecSmrg{ 51605b261ecSmrg WorkQueuePtr q, *p; 51705b261ecSmrg 51805b261ecSmrg p = &workQueue; 51905b261ecSmrg /* 52005b261ecSmrg * Scan the work queue once, calling each function. Those 52105b261ecSmrg * which return TRUE are removed from the queue, otherwise 52205b261ecSmrg * they will be called again. This must be reentrant with 52305b261ecSmrg * QueueWorkProc. 52405b261ecSmrg */ 52505b261ecSmrg while ((q = *p)) 52605b261ecSmrg { 52705b261ecSmrg if ((*q->function) (q->client, q->closure)) 52805b261ecSmrg { 52905b261ecSmrg /* remove q from the list */ 53005b261ecSmrg *p = q->next; /* don't fetch until after func called */ 5316747b715Smrg free(q); 53205b261ecSmrg } 53305b261ecSmrg else 53405b261ecSmrg { 53505b261ecSmrg p = &q->next; /* don't fetch until after func called */ 53605b261ecSmrg } 53705b261ecSmrg } 53805b261ecSmrg workQueueLast = p; 53905b261ecSmrg} 54005b261ecSmrg 54105b261ecSmrgvoid 54205b261ecSmrgProcessWorkQueueZombies(void) 54305b261ecSmrg{ 54405b261ecSmrg WorkQueuePtr q, *p; 54505b261ecSmrg 54605b261ecSmrg p = &workQueue; 54705b261ecSmrg while ((q = *p)) 54805b261ecSmrg { 54905b261ecSmrg if (q->client && q->client->clientGone) 55005b261ecSmrg { 55105b261ecSmrg (void) (*q->function) (q->client, q->closure); 55205b261ecSmrg /* remove q from the list */ 55305b261ecSmrg *p = q->next; /* don't fetch until after func called */ 5546747b715Smrg free(q); 55505b261ecSmrg } 55605b261ecSmrg else 55705b261ecSmrg { 55805b261ecSmrg p = &q->next; /* don't fetch until after func called */ 55905b261ecSmrg } 56005b261ecSmrg } 56105b261ecSmrg workQueueLast = p; 56205b261ecSmrg} 56305b261ecSmrg 5646747b715SmrgBool 56505b261ecSmrgQueueWorkProc ( 56605b261ecSmrg Bool (*function)(ClientPtr /* pClient */, pointer /* closure */), 56705b261ecSmrg ClientPtr client, pointer closure) 56805b261ecSmrg{ 56905b261ecSmrg WorkQueuePtr q; 57005b261ecSmrg 5716747b715Smrg q = malloc(sizeof *q); 57205b261ecSmrg if (!q) 57305b261ecSmrg return FALSE; 57405b261ecSmrg q->function = function; 57505b261ecSmrg q->client = client; 57605b261ecSmrg q->closure = closure; 57705b261ecSmrg q->next = NULL; 57805b261ecSmrg *workQueueLast = q; 57905b261ecSmrg workQueueLast = &q->next; 58005b261ecSmrg return TRUE; 58105b261ecSmrg} 58205b261ecSmrg 58305b261ecSmrg/* 58405b261ecSmrg * Manage a queue of sleeping clients, awakening them 58505b261ecSmrg * when requested, by using the OS functions IgnoreClient 58605b261ecSmrg * and AttendClient. Note that this *ignores* the troubles 58705b261ecSmrg * with request data interleaving itself with events, but 58805b261ecSmrg * we'll leave that until a later time. 58905b261ecSmrg */ 59005b261ecSmrg 59105b261ecSmrgtypedef struct _SleepQueue { 59205b261ecSmrg struct _SleepQueue *next; 59305b261ecSmrg ClientPtr client; 59405b261ecSmrg ClientSleepProcPtr function; 59505b261ecSmrg pointer closure; 59605b261ecSmrg} SleepQueueRec, *SleepQueuePtr; 59705b261ecSmrg 59805b261ecSmrgstatic SleepQueuePtr sleepQueue = NULL; 59905b261ecSmrg 6006747b715SmrgBool 60105b261ecSmrgClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure) 60205b261ecSmrg{ 60305b261ecSmrg SleepQueuePtr q; 60405b261ecSmrg 6056747b715Smrg q = malloc(sizeof *q); 60605b261ecSmrg if (!q) 60705b261ecSmrg return FALSE; 60805b261ecSmrg 60905b261ecSmrg IgnoreClient (client); 61005b261ecSmrg q->next = sleepQueue; 61105b261ecSmrg q->client = client; 61205b261ecSmrg q->function = function; 61305b261ecSmrg q->closure = closure; 61405b261ecSmrg sleepQueue = q; 61505b261ecSmrg return TRUE; 61605b261ecSmrg} 61705b261ecSmrg 61805b261ecSmrgBool 61905b261ecSmrgClientSignal (ClientPtr client) 62005b261ecSmrg{ 62105b261ecSmrg SleepQueuePtr q; 62205b261ecSmrg 62305b261ecSmrg for (q = sleepQueue; q; q = q->next) 62405b261ecSmrg if (q->client == client) 62505b261ecSmrg { 62605b261ecSmrg return QueueWorkProc (q->function, q->client, q->closure); 62705b261ecSmrg } 62805b261ecSmrg return FALSE; 62905b261ecSmrg} 63005b261ecSmrg 6316747b715Smrgvoid 63205b261ecSmrgClientWakeup (ClientPtr client) 63305b261ecSmrg{ 63405b261ecSmrg SleepQueuePtr q, *prev; 63505b261ecSmrg 63605b261ecSmrg prev = &sleepQueue; 63705b261ecSmrg while ( (q = *prev) ) 63805b261ecSmrg { 63905b261ecSmrg if (q->client == client) 64005b261ecSmrg { 64105b261ecSmrg *prev = q->next; 6426747b715Smrg free(q); 64305b261ecSmrg if (client->clientGone) 64405b261ecSmrg /* Oops -- new zombie cleanup code ensures this only 64505b261ecSmrg * happens from inside CloseDownClient; don't want to 64605b261ecSmrg * recurse here... 64705b261ecSmrg */ 64805b261ecSmrg /* CloseDownClient(client) */; 64905b261ecSmrg else 65005b261ecSmrg AttendClient (client); 65105b261ecSmrg break; 65205b261ecSmrg } 65305b261ecSmrg prev = &q->next; 65405b261ecSmrg } 65505b261ecSmrg} 65605b261ecSmrg 65705b261ecSmrgBool 65805b261ecSmrgClientIsAsleep (ClientPtr client) 65905b261ecSmrg{ 66005b261ecSmrg SleepQueuePtr q; 66105b261ecSmrg 66205b261ecSmrg for (q = sleepQueue; q; q = q->next) 66305b261ecSmrg if (q->client == client) 66405b261ecSmrg return TRUE; 66505b261ecSmrg return FALSE; 66605b261ecSmrg} 66705b261ecSmrg 66805b261ecSmrg/* 66905b261ecSmrg * Generic Callback Manager 67005b261ecSmrg */ 67105b261ecSmrg 67205b261ecSmrg/* ===== Private Procedures ===== */ 67305b261ecSmrg 67405b261ecSmrgstatic int numCallbackListsToCleanup = 0; 67505b261ecSmrgstatic CallbackListPtr **listsToCleanup = NULL; 67605b261ecSmrg 6776747b715Smrgstatic Bool 67805b261ecSmrg_AddCallback( 67905b261ecSmrg CallbackListPtr *pcbl, 68005b261ecSmrg CallbackProcPtr callback, 68105b261ecSmrg pointer data) 68205b261ecSmrg{ 68305b261ecSmrg CallbackPtr cbr; 68405b261ecSmrg 6856747b715Smrg cbr = malloc(sizeof(CallbackRec)); 68605b261ecSmrg if (!cbr) 68705b261ecSmrg return FALSE; 68805b261ecSmrg cbr->proc = callback; 68905b261ecSmrg cbr->data = data; 69005b261ecSmrg cbr->next = (*pcbl)->list; 69105b261ecSmrg cbr->deleted = FALSE; 69205b261ecSmrg (*pcbl)->list = cbr; 69305b261ecSmrg return TRUE; 69405b261ecSmrg} 69505b261ecSmrg 69605b261ecSmrgstatic Bool 69705b261ecSmrg_DeleteCallback( 69805b261ecSmrg CallbackListPtr *pcbl, 69905b261ecSmrg CallbackProcPtr callback, 70005b261ecSmrg pointer data) 70105b261ecSmrg{ 70205b261ecSmrg CallbackListPtr cbl = *pcbl; 70305b261ecSmrg CallbackPtr cbr, pcbr; 70405b261ecSmrg 70505b261ecSmrg for (pcbr = NULL, cbr = cbl->list; 70605b261ecSmrg cbr != NULL; 70705b261ecSmrg pcbr = cbr, cbr = cbr->next) 70805b261ecSmrg { 70905b261ecSmrg if ((cbr->proc == callback) && (cbr->data == data)) 71005b261ecSmrg break; 71105b261ecSmrg } 71205b261ecSmrg if (cbr != NULL) 71305b261ecSmrg { 71405b261ecSmrg if (cbl->inCallback) 71505b261ecSmrg { 71605b261ecSmrg ++(cbl->numDeleted); 71705b261ecSmrg cbr->deleted = TRUE; 71805b261ecSmrg } 71905b261ecSmrg else 72005b261ecSmrg { 72105b261ecSmrg if (pcbr == NULL) 72205b261ecSmrg cbl->list = cbr->next; 72305b261ecSmrg else 72405b261ecSmrg pcbr->next = cbr->next; 7256747b715Smrg free(cbr); 72605b261ecSmrg } 72705b261ecSmrg return TRUE; 72805b261ecSmrg } 72905b261ecSmrg return FALSE; 73005b261ecSmrg} 73105b261ecSmrg 73205b261ecSmrgstatic void 73305b261ecSmrg_CallCallbacks( 73405b261ecSmrg CallbackListPtr *pcbl, 73505b261ecSmrg pointer call_data) 73605b261ecSmrg{ 73705b261ecSmrg CallbackListPtr cbl = *pcbl; 73805b261ecSmrg CallbackPtr cbr, pcbr; 73905b261ecSmrg 74005b261ecSmrg ++(cbl->inCallback); 74105b261ecSmrg for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) 74205b261ecSmrg { 74305b261ecSmrg (*(cbr->proc)) (pcbl, cbr->data, call_data); 74405b261ecSmrg } 74505b261ecSmrg --(cbl->inCallback); 74605b261ecSmrg 74705b261ecSmrg if (cbl->inCallback) return; 74805b261ecSmrg 74905b261ecSmrg /* Was the entire list marked for deletion? */ 75005b261ecSmrg 75105b261ecSmrg if (cbl->deleted) 75205b261ecSmrg { 75305b261ecSmrg DeleteCallbackList(pcbl); 75405b261ecSmrg return; 75505b261ecSmrg } 75605b261ecSmrg 75705b261ecSmrg /* Were some individual callbacks on the list marked for deletion? 75805b261ecSmrg * If so, do the deletions. 75905b261ecSmrg */ 76005b261ecSmrg 76105b261ecSmrg if (cbl->numDeleted) 76205b261ecSmrg { 76305b261ecSmrg for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; ) 76405b261ecSmrg { 76505b261ecSmrg if (cbr->deleted) 76605b261ecSmrg { 76705b261ecSmrg if (pcbr) 76805b261ecSmrg { 76905b261ecSmrg cbr = cbr->next; 7706747b715Smrg free(pcbr->next); 77105b261ecSmrg pcbr->next = cbr; 77205b261ecSmrg } else 77305b261ecSmrg { 77405b261ecSmrg cbr = cbr->next; 7756747b715Smrg free(cbl->list); 77605b261ecSmrg cbl->list = cbr; 77705b261ecSmrg } 77805b261ecSmrg cbl->numDeleted--; 77905b261ecSmrg } 78005b261ecSmrg else /* this one wasn't deleted */ 78105b261ecSmrg { 78205b261ecSmrg pcbr = cbr; 78305b261ecSmrg cbr = cbr->next; 78405b261ecSmrg } 78505b261ecSmrg } 78605b261ecSmrg } 78705b261ecSmrg} 78805b261ecSmrg 78905b261ecSmrgstatic void 79005b261ecSmrg_DeleteCallbackList( 79105b261ecSmrg CallbackListPtr *pcbl) 79205b261ecSmrg{ 79305b261ecSmrg CallbackListPtr cbl = *pcbl; 79405b261ecSmrg CallbackPtr cbr, nextcbr; 79505b261ecSmrg int i; 79605b261ecSmrg 79705b261ecSmrg if (cbl->inCallback) 79805b261ecSmrg { 79905b261ecSmrg cbl->deleted = TRUE; 80005b261ecSmrg return; 80105b261ecSmrg } 80205b261ecSmrg 80305b261ecSmrg for (i = 0; i < numCallbackListsToCleanup; i++) 80405b261ecSmrg { 8054642e01fSmrg if (listsToCleanup[i] == pcbl) 80605b261ecSmrg { 80705b261ecSmrg listsToCleanup[i] = NULL; 80805b261ecSmrg break; 80905b261ecSmrg } 81005b261ecSmrg } 81105b261ecSmrg 81205b261ecSmrg for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) 81305b261ecSmrg { 81405b261ecSmrg nextcbr = cbr->next; 8156747b715Smrg free(cbr); 81605b261ecSmrg } 8176747b715Smrg free(cbl); 81805b261ecSmrg *pcbl = NULL; 81905b261ecSmrg} 82005b261ecSmrg 82105b261ecSmrgstatic Bool 8224642e01fSmrgCreateCallbackList(CallbackListPtr *pcbl) 82305b261ecSmrg{ 82405b261ecSmrg CallbackListPtr cbl; 82505b261ecSmrg int i; 82605b261ecSmrg 82705b261ecSmrg if (!pcbl) return FALSE; 8286747b715Smrg cbl = malloc(sizeof(CallbackListRec)); 82905b261ecSmrg if (!cbl) return FALSE; 83005b261ecSmrg cbl->inCallback = 0; 83105b261ecSmrg cbl->deleted = FALSE; 83205b261ecSmrg cbl->numDeleted = 0; 83305b261ecSmrg cbl->list = NULL; 83405b261ecSmrg *pcbl = cbl; 83505b261ecSmrg 83605b261ecSmrg for (i = 0; i < numCallbackListsToCleanup; i++) 83705b261ecSmrg { 83805b261ecSmrg if (!listsToCleanup[i]) 83905b261ecSmrg { 84005b261ecSmrg listsToCleanup[i] = pcbl; 84105b261ecSmrg return TRUE; 84205b261ecSmrg } 84305b261ecSmrg } 84405b261ecSmrg 84505b261ecSmrg listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup, 84605b261ecSmrg sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1)); 84705b261ecSmrg listsToCleanup[numCallbackListsToCleanup] = pcbl; 84805b261ecSmrg numCallbackListsToCleanup++; 84905b261ecSmrg return TRUE; 85005b261ecSmrg} 85105b261ecSmrg 85205b261ecSmrg/* ===== Public Procedures ===== */ 85305b261ecSmrg 8546747b715SmrgBool 85505b261ecSmrgAddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) 85605b261ecSmrg{ 85705b261ecSmrg if (!pcbl) return FALSE; 85805b261ecSmrg if (!*pcbl) 85905b261ecSmrg { /* list hasn't been created yet; go create it */ 8604642e01fSmrg if (!CreateCallbackList(pcbl)) 86105b261ecSmrg return FALSE; 86205b261ecSmrg } 8634642e01fSmrg return _AddCallback(pcbl, callback, data); 86405b261ecSmrg} 86505b261ecSmrg 8666747b715SmrgBool 86705b261ecSmrgDeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) 86805b261ecSmrg{ 86905b261ecSmrg if (!pcbl || !*pcbl) return FALSE; 8704642e01fSmrg return _DeleteCallback(pcbl, callback, data); 87105b261ecSmrg} 87205b261ecSmrg 8736747b715Smrgvoid 87405b261ecSmrgCallCallbacks(CallbackListPtr *pcbl, pointer call_data) 87505b261ecSmrg{ 87605b261ecSmrg if (!pcbl || !*pcbl) return; 8774642e01fSmrg _CallCallbacks(pcbl, call_data); 87805b261ecSmrg} 87905b261ecSmrg 88005b261ecSmrgvoid 88105b261ecSmrgDeleteCallbackList(CallbackListPtr *pcbl) 88205b261ecSmrg{ 88305b261ecSmrg if (!pcbl || !*pcbl) return; 8844642e01fSmrg _DeleteCallbackList(pcbl); 88505b261ecSmrg} 88605b261ecSmrg 8876747b715Smrgvoid 88805b261ecSmrgInitCallbackManager(void) 88905b261ecSmrg{ 89005b261ecSmrg int i; 89105b261ecSmrg 89205b261ecSmrg for (i = 0; i < numCallbackListsToCleanup; i++) 89305b261ecSmrg { 89405b261ecSmrg DeleteCallbackList(listsToCleanup[i]); 89505b261ecSmrg } 8966747b715Smrg free(listsToCleanup); 89705b261ecSmrg 89805b261ecSmrg numCallbackListsToCleanup = 0; 89905b261ecSmrg listsToCleanup = NULL; 90005b261ecSmrg} 901