dixutils.c revision 05b261ec
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; 21105b261ecSmrg RESTYPE rtype; 21205b261ecSmrg *pDraw = NULL; 21305b261ecSmrg client->errorValue = id; 21405b261ecSmrg 21505b261ecSmrg if (id == INVALID) 21605b261ecSmrg return BadDrawable; 21705b261ecSmrg 21805b261ecSmrg if (id == client->lastDrawableID) { 21905b261ecSmrg pTmp = client->lastDrawable; 22005b261ecSmrg 22105b261ecSmrg /* an access check is required for cached drawables */ 22205b261ecSmrg rtype = (type & M_WINDOW) ? RT_WINDOW : RT_PIXMAP; 22305b261ecSmrg if (!XaceHook(XACE_RESOURCE_ACCESS, client, id, rtype, access, pTmp)) 22405b261ecSmrg return BadDrawable; 22505b261ecSmrg } else 22605b261ecSmrg pTmp = (DrawablePtr)SecurityLookupIDByClass(client, id, RC_DRAWABLE, 22705b261ecSmrg access); 22805b261ecSmrg if (!pTmp) 22905b261ecSmrg return BadDrawable; 23005b261ecSmrg if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE))) 23105b261ecSmrg return BadMatch; 23205b261ecSmrg 23305b261ecSmrg if (type & M_DRAWABLE) { 23405b261ecSmrg client->lastDrawable = pTmp; 23505b261ecSmrg client->lastDrawableID = id; 23605b261ecSmrg client->lastGCID = INVALID; 23705b261ecSmrg client->lastGC = (GCPtr)NULL; 23805b261ecSmrg } 23905b261ecSmrg *pDraw = pTmp; 24005b261ecSmrg return Success; 24105b261ecSmrg} 24205b261ecSmrg 24305b261ecSmrg_X_EXPORT int 24405b261ecSmrgdixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access) 24505b261ecSmrg{ 24605b261ecSmrg int rc; 24705b261ecSmrg rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access); 24805b261ecSmrg return (rc == BadDrawable) ? BadWindow : rc; 24905b261ecSmrg} 25005b261ecSmrg 25105b261ecSmrg_X_EXPORT int 25205b261ecSmrgdixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access) 25305b261ecSmrg{ 25405b261ecSmrg GCPtr pTmp = (GCPtr)SecurityLookupIDByType(client, id, RT_GC, access); 25505b261ecSmrg if (pTmp) { 25605b261ecSmrg *pGC = pTmp; 25705b261ecSmrg return Success; 25805b261ecSmrg } 25905b261ecSmrg client->errorValue = id; 26005b261ecSmrg *pGC = NULL; 26105b261ecSmrg return BadGC; 26205b261ecSmrg} 26305b261ecSmrg 26405b261ecSmrg_X_EXPORT int 26505b261ecSmrgdixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access) 26605b261ecSmrg{ 26705b261ecSmrg pointer pRes = (pointer)SecurityLookupIDByClass(client, rid, RC_ANY, 26805b261ecSmrg access); 26905b261ecSmrg int clientIndex = CLIENT_ID(rid); 27005b261ecSmrg client->errorValue = rid; 27105b261ecSmrg 27205b261ecSmrg if (clientIndex && pRes && clients[clientIndex] && !(rid & SERVER_BIT)) { 27305b261ecSmrg *pClient = clients[clientIndex]; 27405b261ecSmrg return Success; 27505b261ecSmrg } 27605b261ecSmrg *pClient = NULL; 27705b261ecSmrg return BadValue; 27805b261ecSmrg} 27905b261ecSmrg 28005b261ecSmrg/* 28105b261ecSmrg * These are deprecated compatibility functions and will be removed soon! 28205b261ecSmrg * Please use the new dixLookup*() functions above. 28305b261ecSmrg */ 28405b261ecSmrg_X_EXPORT _X_DEPRECATED WindowPtr 28505b261ecSmrgSecurityLookupWindow(XID id, ClientPtr client, Mask access_mode) 28605b261ecSmrg{ 28705b261ecSmrg WindowPtr pWin; 28805b261ecSmrg int i = dixLookupWindow(&pWin, id, client, access_mode); 28905b261ecSmrg static int warn = 1; 29005b261ecSmrg if (warn-- > 0) 29105b261ecSmrg ErrorF("Warning: LookupWindow()/SecurityLookupWindow() " 29205b261ecSmrg "are deprecated. Please convert your driver/module " 29305b261ecSmrg "to use dixLookupWindow().\n"); 29405b261ecSmrg return (i == Success) ? pWin : NULL; 29505b261ecSmrg} 29605b261ecSmrg 29705b261ecSmrg_X_EXPORT _X_DEPRECATED WindowPtr 29805b261ecSmrgLookupWindow(XID id, ClientPtr client) 29905b261ecSmrg{ 30005b261ecSmrg return SecurityLookupWindow(id, client, DixUnknownAccess); 30105b261ecSmrg} 30205b261ecSmrg 30305b261ecSmrg_X_EXPORT _X_DEPRECATED pointer 30405b261ecSmrgSecurityLookupDrawable(XID id, ClientPtr client, Mask access_mode) 30505b261ecSmrg{ 30605b261ecSmrg DrawablePtr pDraw; 30705b261ecSmrg int i = dixLookupDrawable(&pDraw, id, client, M_DRAWABLE, access_mode); 30805b261ecSmrg static int warn = 1; 30905b261ecSmrg if (warn-- > 0) 31005b261ecSmrg ErrorF("Warning: LookupDrawable()/SecurityLookupDrawable() " 31105b261ecSmrg "are deprecated. Please convert your driver/module " 31205b261ecSmrg "to use dixLookupDrawable().\n"); 31305b261ecSmrg return (i == Success) ? pDraw : NULL; 31405b261ecSmrg} 31505b261ecSmrg 31605b261ecSmrg_X_EXPORT _X_DEPRECATED pointer 31705b261ecSmrgLookupDrawable(XID id, ClientPtr client) 31805b261ecSmrg{ 31905b261ecSmrg return SecurityLookupDrawable(id, client, DixUnknownAccess); 32005b261ecSmrg} 32105b261ecSmrg 32205b261ecSmrg_X_EXPORT _X_DEPRECATED ClientPtr 32305b261ecSmrgLookupClient(XID id, ClientPtr client) 32405b261ecSmrg{ 32505b261ecSmrg ClientPtr pClient; 32605b261ecSmrg int i = dixLookupClient(&pClient, id, client, DixUnknownAccess); 32705b261ecSmrg static int warn = 1; 32805b261ecSmrg if (warn-- > 0) 32905b261ecSmrg ErrorF("Warning: LookupClient() is deprecated. Please convert your " 33005b261ecSmrg "driver/module to use dixLookupClient().\n"); 33105b261ecSmrg return (i == Success) ? pClient : NULL; 33205b261ecSmrg} 33305b261ecSmrg 33405b261ecSmrg/* end deprecated functions */ 33505b261ecSmrg 33605b261ecSmrgint 33705b261ecSmrgAlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, 33805b261ecSmrg Bool toRoot, Bool remap) 33905b261ecSmrg{ 34005b261ecSmrg int numnow; 34105b261ecSmrg SaveSetElt *pTmp = NULL; 34205b261ecSmrg int j; 34305b261ecSmrg 34405b261ecSmrg numnow = client->numSaved; 34505b261ecSmrg j = 0; 34605b261ecSmrg if (numnow) 34705b261ecSmrg { 34805b261ecSmrg pTmp = client->saveSet; 34905b261ecSmrg while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin)) 35005b261ecSmrg j++; 35105b261ecSmrg } 35205b261ecSmrg if (mode == SetModeInsert) 35305b261ecSmrg { 35405b261ecSmrg if (j < numnow) /* duplicate */ 35505b261ecSmrg return(Success); 35605b261ecSmrg numnow++; 35705b261ecSmrg pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); 35805b261ecSmrg if (!pTmp) 35905b261ecSmrg return(BadAlloc); 36005b261ecSmrg client->saveSet = pTmp; 36105b261ecSmrg client->numSaved = numnow; 36205b261ecSmrg SaveSetAssignWindow(client->saveSet[numnow - 1], pWin); 36305b261ecSmrg SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot); 36405b261ecSmrg SaveSetAssignRemap(client->saveSet[numnow - 1], remap); 36505b261ecSmrg return(Success); 36605b261ecSmrg } 36705b261ecSmrg else if ((mode == SetModeDelete) && (j < numnow)) 36805b261ecSmrg { 36905b261ecSmrg while (j < numnow-1) 37005b261ecSmrg { 37105b261ecSmrg pTmp[j] = pTmp[j+1]; 37205b261ecSmrg j++; 37305b261ecSmrg } 37405b261ecSmrg numnow--; 37505b261ecSmrg if (numnow) 37605b261ecSmrg { 37705b261ecSmrg pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); 37805b261ecSmrg if (pTmp) 37905b261ecSmrg client->saveSet = pTmp; 38005b261ecSmrg } 38105b261ecSmrg else 38205b261ecSmrg { 38305b261ecSmrg xfree(client->saveSet); 38405b261ecSmrg client->saveSet = (SaveSetElt *)NULL; 38505b261ecSmrg } 38605b261ecSmrg client->numSaved = numnow; 38705b261ecSmrg return(Success); 38805b261ecSmrg } 38905b261ecSmrg return(Success); 39005b261ecSmrg} 39105b261ecSmrg 39205b261ecSmrgvoid 39305b261ecSmrgDeleteWindowFromAnySaveSet(WindowPtr pWin) 39405b261ecSmrg{ 39505b261ecSmrg int i; 39605b261ecSmrg ClientPtr client; 39705b261ecSmrg 39805b261ecSmrg for (i = 0; i< currentMaxClients; i++) 39905b261ecSmrg { 40005b261ecSmrg client = clients[i]; 40105b261ecSmrg if (client && client->numSaved) 40205b261ecSmrg (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE); 40305b261ecSmrg } 40405b261ecSmrg} 40505b261ecSmrg 40605b261ecSmrg/* No-op Don't Do Anything : sometimes we need to be able to call a procedure 40705b261ecSmrg * that doesn't do anything. For example, on screen with only static 40805b261ecSmrg * colormaps, if someone calls install colormap, it's easier to have a dummy 40905b261ecSmrg * procedure to call than to check if there's a procedure 41005b261ecSmrg */ 41105b261ecSmrg_X_EXPORT void 41205b261ecSmrgNoopDDA(void) 41305b261ecSmrg{ 41405b261ecSmrg} 41505b261ecSmrg 41605b261ecSmrgtypedef struct _BlockHandler { 41705b261ecSmrg BlockHandlerProcPtr BlockHandler; 41805b261ecSmrg WakeupHandlerProcPtr WakeupHandler; 41905b261ecSmrg pointer blockData; 42005b261ecSmrg Bool deleted; 42105b261ecSmrg} BlockHandlerRec, *BlockHandlerPtr; 42205b261ecSmrg 42305b261ecSmrgstatic BlockHandlerPtr handlers; 42405b261ecSmrgstatic int numHandlers; 42505b261ecSmrgstatic int sizeHandlers; 42605b261ecSmrgstatic Bool inHandler; 42705b261ecSmrgstatic Bool handlerDeleted; 42805b261ecSmrg 42905b261ecSmrg/** 43005b261ecSmrg * 43105b261ecSmrg * \param pTimeout DIX doesn't want to know how OS represents time 43205b261ecSmrg * \param pReadMask nor how it represents the det of descriptors 43305b261ecSmrg */ 43405b261ecSmrgvoid 43505b261ecSmrgBlockHandler(pointer pTimeout, pointer pReadmask) 43605b261ecSmrg{ 43705b261ecSmrg int i, j; 43805b261ecSmrg 43905b261ecSmrg ++inHandler; 44005b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 44105b261ecSmrg (* screenInfo.screens[i]->BlockHandler)(i, 44205b261ecSmrg screenInfo.screens[i]->blockData, 44305b261ecSmrg pTimeout, pReadmask); 44405b261ecSmrg for (i = 0; i < numHandlers; i++) 44505b261ecSmrg (*handlers[i].BlockHandler) (handlers[i].blockData, 44605b261ecSmrg pTimeout, pReadmask); 44705b261ecSmrg if (handlerDeleted) 44805b261ecSmrg { 44905b261ecSmrg for (i = 0; i < numHandlers;) 45005b261ecSmrg if (handlers[i].deleted) 45105b261ecSmrg { 45205b261ecSmrg for (j = i; j < numHandlers - 1; j++) 45305b261ecSmrg handlers[j] = handlers[j+1]; 45405b261ecSmrg numHandlers--; 45505b261ecSmrg } 45605b261ecSmrg else 45705b261ecSmrg i++; 45805b261ecSmrg handlerDeleted = FALSE; 45905b261ecSmrg } 46005b261ecSmrg --inHandler; 46105b261ecSmrg} 46205b261ecSmrg 46305b261ecSmrg/** 46405b261ecSmrg * 46505b261ecSmrg * \param result 32 bits of undefined result from the wait 46605b261ecSmrg * \param pReadmask the resulting descriptor mask 46705b261ecSmrg */ 46805b261ecSmrgvoid 46905b261ecSmrgWakeupHandler(int result, pointer pReadmask) 47005b261ecSmrg{ 47105b261ecSmrg int i, j; 47205b261ecSmrg 47305b261ecSmrg ++inHandler; 47405b261ecSmrg for (i = numHandlers - 1; i >= 0; i--) 47505b261ecSmrg (*handlers[i].WakeupHandler) (handlers[i].blockData, 47605b261ecSmrg result, pReadmask); 47705b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 47805b261ecSmrg (* screenInfo.screens[i]->WakeupHandler)(i, 47905b261ecSmrg screenInfo.screens[i]->wakeupData, 48005b261ecSmrg result, pReadmask); 48105b261ecSmrg if (handlerDeleted) 48205b261ecSmrg { 48305b261ecSmrg for (i = 0; i < numHandlers;) 48405b261ecSmrg if (handlers[i].deleted) 48505b261ecSmrg { 48605b261ecSmrg for (j = i; j < numHandlers - 1; j++) 48705b261ecSmrg handlers[j] = handlers[j+1]; 48805b261ecSmrg numHandlers--; 48905b261ecSmrg } 49005b261ecSmrg else 49105b261ecSmrg i++; 49205b261ecSmrg handlerDeleted = FALSE; 49305b261ecSmrg } 49405b261ecSmrg --inHandler; 49505b261ecSmrg} 49605b261ecSmrg 49705b261ecSmrg/** 49805b261ecSmrg * Reentrant with BlockHandler and WakeupHandler, except wakeup won't 49905b261ecSmrg * get called until next time 50005b261ecSmrg */ 50105b261ecSmrg_X_EXPORT Bool 50205b261ecSmrgRegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, 50305b261ecSmrg WakeupHandlerProcPtr wakeupHandler, 50405b261ecSmrg pointer blockData) 50505b261ecSmrg{ 50605b261ecSmrg BlockHandlerPtr new; 50705b261ecSmrg 50805b261ecSmrg if (numHandlers >= sizeHandlers) 50905b261ecSmrg { 51005b261ecSmrg new = (BlockHandlerPtr) xrealloc (handlers, (numHandlers + 1) * 51105b261ecSmrg sizeof (BlockHandlerRec)); 51205b261ecSmrg if (!new) 51305b261ecSmrg return FALSE; 51405b261ecSmrg handlers = new; 51505b261ecSmrg sizeHandlers = numHandlers + 1; 51605b261ecSmrg } 51705b261ecSmrg handlers[numHandlers].BlockHandler = blockHandler; 51805b261ecSmrg handlers[numHandlers].WakeupHandler = wakeupHandler; 51905b261ecSmrg handlers[numHandlers].blockData = blockData; 52005b261ecSmrg handlers[numHandlers].deleted = FALSE; 52105b261ecSmrg numHandlers = numHandlers + 1; 52205b261ecSmrg return TRUE; 52305b261ecSmrg} 52405b261ecSmrg 52505b261ecSmrg_X_EXPORT void 52605b261ecSmrgRemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, 52705b261ecSmrg WakeupHandlerProcPtr wakeupHandler, 52805b261ecSmrg pointer blockData) 52905b261ecSmrg{ 53005b261ecSmrg int i; 53105b261ecSmrg 53205b261ecSmrg for (i = 0; i < numHandlers; i++) 53305b261ecSmrg if (handlers[i].BlockHandler == blockHandler && 53405b261ecSmrg handlers[i].WakeupHandler == wakeupHandler && 53505b261ecSmrg handlers[i].blockData == blockData) 53605b261ecSmrg { 53705b261ecSmrg if (inHandler) 53805b261ecSmrg { 53905b261ecSmrg handlerDeleted = TRUE; 54005b261ecSmrg handlers[i].deleted = TRUE; 54105b261ecSmrg } 54205b261ecSmrg else 54305b261ecSmrg { 54405b261ecSmrg for (; i < numHandlers - 1; i++) 54505b261ecSmrg handlers[i] = handlers[i+1]; 54605b261ecSmrg numHandlers--; 54705b261ecSmrg } 54805b261ecSmrg break; 54905b261ecSmrg } 55005b261ecSmrg} 55105b261ecSmrg 55205b261ecSmrgvoid 55305b261ecSmrgInitBlockAndWakeupHandlers (void) 55405b261ecSmrg{ 55505b261ecSmrg xfree (handlers); 55605b261ecSmrg handlers = (BlockHandlerPtr) 0; 55705b261ecSmrg numHandlers = 0; 55805b261ecSmrg sizeHandlers = 0; 55905b261ecSmrg} 56005b261ecSmrg 56105b261ecSmrg/* 56205b261ecSmrg * A general work queue. Perform some task before the server 56305b261ecSmrg * sleeps for input. 56405b261ecSmrg */ 56505b261ecSmrg 56605b261ecSmrgWorkQueuePtr workQueue; 56705b261ecSmrgstatic WorkQueuePtr *workQueueLast = &workQueue; 56805b261ecSmrg 56905b261ecSmrgvoid 57005b261ecSmrgProcessWorkQueue(void) 57105b261ecSmrg{ 57205b261ecSmrg WorkQueuePtr q, *p; 57305b261ecSmrg 57405b261ecSmrg p = &workQueue; 57505b261ecSmrg /* 57605b261ecSmrg * Scan the work queue once, calling each function. Those 57705b261ecSmrg * which return TRUE are removed from the queue, otherwise 57805b261ecSmrg * they will be called again. This must be reentrant with 57905b261ecSmrg * QueueWorkProc. 58005b261ecSmrg */ 58105b261ecSmrg while ((q = *p)) 58205b261ecSmrg { 58305b261ecSmrg if ((*q->function) (q->client, q->closure)) 58405b261ecSmrg { 58505b261ecSmrg /* remove q from the list */ 58605b261ecSmrg *p = q->next; /* don't fetch until after func called */ 58705b261ecSmrg xfree (q); 58805b261ecSmrg } 58905b261ecSmrg else 59005b261ecSmrg { 59105b261ecSmrg p = &q->next; /* don't fetch until after func called */ 59205b261ecSmrg } 59305b261ecSmrg } 59405b261ecSmrg workQueueLast = p; 59505b261ecSmrg} 59605b261ecSmrg 59705b261ecSmrgvoid 59805b261ecSmrgProcessWorkQueueZombies(void) 59905b261ecSmrg{ 60005b261ecSmrg WorkQueuePtr q, *p; 60105b261ecSmrg 60205b261ecSmrg p = &workQueue; 60305b261ecSmrg while ((q = *p)) 60405b261ecSmrg { 60505b261ecSmrg if (q->client && q->client->clientGone) 60605b261ecSmrg { 60705b261ecSmrg (void) (*q->function) (q->client, q->closure); 60805b261ecSmrg /* remove q from the list */ 60905b261ecSmrg *p = q->next; /* don't fetch until after func called */ 61005b261ecSmrg xfree (q); 61105b261ecSmrg } 61205b261ecSmrg else 61305b261ecSmrg { 61405b261ecSmrg p = &q->next; /* don't fetch until after func called */ 61505b261ecSmrg } 61605b261ecSmrg } 61705b261ecSmrg workQueueLast = p; 61805b261ecSmrg} 61905b261ecSmrg 62005b261ecSmrg_X_EXPORT Bool 62105b261ecSmrgQueueWorkProc ( 62205b261ecSmrg Bool (*function)(ClientPtr /* pClient */, pointer /* closure */), 62305b261ecSmrg ClientPtr client, pointer closure) 62405b261ecSmrg{ 62505b261ecSmrg WorkQueuePtr q; 62605b261ecSmrg 62705b261ecSmrg q = (WorkQueuePtr) xalloc (sizeof *q); 62805b261ecSmrg if (!q) 62905b261ecSmrg return FALSE; 63005b261ecSmrg q->function = function; 63105b261ecSmrg q->client = client; 63205b261ecSmrg q->closure = closure; 63305b261ecSmrg q->next = NULL; 63405b261ecSmrg *workQueueLast = q; 63505b261ecSmrg workQueueLast = &q->next; 63605b261ecSmrg return TRUE; 63705b261ecSmrg} 63805b261ecSmrg 63905b261ecSmrg/* 64005b261ecSmrg * Manage a queue of sleeping clients, awakening them 64105b261ecSmrg * when requested, by using the OS functions IgnoreClient 64205b261ecSmrg * and AttendClient. Note that this *ignores* the troubles 64305b261ecSmrg * with request data interleaving itself with events, but 64405b261ecSmrg * we'll leave that until a later time. 64505b261ecSmrg */ 64605b261ecSmrg 64705b261ecSmrgtypedef struct _SleepQueue { 64805b261ecSmrg struct _SleepQueue *next; 64905b261ecSmrg ClientPtr client; 65005b261ecSmrg ClientSleepProcPtr function; 65105b261ecSmrg pointer closure; 65205b261ecSmrg} SleepQueueRec, *SleepQueuePtr; 65305b261ecSmrg 65405b261ecSmrgstatic SleepQueuePtr sleepQueue = NULL; 65505b261ecSmrg 65605b261ecSmrg_X_EXPORT Bool 65705b261ecSmrgClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure) 65805b261ecSmrg{ 65905b261ecSmrg SleepQueuePtr q; 66005b261ecSmrg 66105b261ecSmrg q = (SleepQueuePtr) xalloc (sizeof *q); 66205b261ecSmrg if (!q) 66305b261ecSmrg return FALSE; 66405b261ecSmrg 66505b261ecSmrg IgnoreClient (client); 66605b261ecSmrg q->next = sleepQueue; 66705b261ecSmrg q->client = client; 66805b261ecSmrg q->function = function; 66905b261ecSmrg q->closure = closure; 67005b261ecSmrg sleepQueue = q; 67105b261ecSmrg return TRUE; 67205b261ecSmrg} 67305b261ecSmrg 67405b261ecSmrgBool 67505b261ecSmrgClientSignal (ClientPtr client) 67605b261ecSmrg{ 67705b261ecSmrg SleepQueuePtr q; 67805b261ecSmrg 67905b261ecSmrg for (q = sleepQueue; q; q = q->next) 68005b261ecSmrg if (q->client == client) 68105b261ecSmrg { 68205b261ecSmrg return QueueWorkProc (q->function, q->client, q->closure); 68305b261ecSmrg } 68405b261ecSmrg return FALSE; 68505b261ecSmrg} 68605b261ecSmrg 68705b261ecSmrg_X_EXPORT void 68805b261ecSmrgClientWakeup (ClientPtr client) 68905b261ecSmrg{ 69005b261ecSmrg SleepQueuePtr q, *prev; 69105b261ecSmrg 69205b261ecSmrg prev = &sleepQueue; 69305b261ecSmrg while ( (q = *prev) ) 69405b261ecSmrg { 69505b261ecSmrg if (q->client == client) 69605b261ecSmrg { 69705b261ecSmrg *prev = q->next; 69805b261ecSmrg xfree (q); 69905b261ecSmrg if (client->clientGone) 70005b261ecSmrg /* Oops -- new zombie cleanup code ensures this only 70105b261ecSmrg * happens from inside CloseDownClient; don't want to 70205b261ecSmrg * recurse here... 70305b261ecSmrg */ 70405b261ecSmrg /* CloseDownClient(client) */; 70505b261ecSmrg else 70605b261ecSmrg AttendClient (client); 70705b261ecSmrg break; 70805b261ecSmrg } 70905b261ecSmrg prev = &q->next; 71005b261ecSmrg } 71105b261ecSmrg} 71205b261ecSmrg 71305b261ecSmrgBool 71405b261ecSmrgClientIsAsleep (ClientPtr client) 71505b261ecSmrg{ 71605b261ecSmrg SleepQueuePtr q; 71705b261ecSmrg 71805b261ecSmrg for (q = sleepQueue; q; q = q->next) 71905b261ecSmrg if (q->client == client) 72005b261ecSmrg return TRUE; 72105b261ecSmrg return FALSE; 72205b261ecSmrg} 72305b261ecSmrg 72405b261ecSmrg/* 72505b261ecSmrg * Generic Callback Manager 72605b261ecSmrg */ 72705b261ecSmrg 72805b261ecSmrg/* ===== Private Procedures ===== */ 72905b261ecSmrg 73005b261ecSmrgstatic int numCallbackListsToCleanup = 0; 73105b261ecSmrgstatic CallbackListPtr **listsToCleanup = NULL; 73205b261ecSmrg 73305b261ecSmrgstatic Bool 73405b261ecSmrg_AddCallback( 73505b261ecSmrg CallbackListPtr *pcbl, 73605b261ecSmrg CallbackProcPtr callback, 73705b261ecSmrg pointer data) 73805b261ecSmrg{ 73905b261ecSmrg CallbackPtr cbr; 74005b261ecSmrg 74105b261ecSmrg cbr = (CallbackPtr) xalloc(sizeof(CallbackRec)); 74205b261ecSmrg if (!cbr) 74305b261ecSmrg return FALSE; 74405b261ecSmrg cbr->proc = callback; 74505b261ecSmrg cbr->data = data; 74605b261ecSmrg cbr->next = (*pcbl)->list; 74705b261ecSmrg cbr->deleted = FALSE; 74805b261ecSmrg (*pcbl)->list = cbr; 74905b261ecSmrg return TRUE; 75005b261ecSmrg} 75105b261ecSmrg 75205b261ecSmrgstatic Bool 75305b261ecSmrg_DeleteCallback( 75405b261ecSmrg CallbackListPtr *pcbl, 75505b261ecSmrg CallbackProcPtr callback, 75605b261ecSmrg pointer data) 75705b261ecSmrg{ 75805b261ecSmrg CallbackListPtr cbl = *pcbl; 75905b261ecSmrg CallbackPtr cbr, pcbr; 76005b261ecSmrg 76105b261ecSmrg for (pcbr = NULL, cbr = cbl->list; 76205b261ecSmrg cbr != NULL; 76305b261ecSmrg pcbr = cbr, cbr = cbr->next) 76405b261ecSmrg { 76505b261ecSmrg if ((cbr->proc == callback) && (cbr->data == data)) 76605b261ecSmrg break; 76705b261ecSmrg } 76805b261ecSmrg if (cbr != NULL) 76905b261ecSmrg { 77005b261ecSmrg if (cbl->inCallback) 77105b261ecSmrg { 77205b261ecSmrg ++(cbl->numDeleted); 77305b261ecSmrg cbr->deleted = TRUE; 77405b261ecSmrg } 77505b261ecSmrg else 77605b261ecSmrg { 77705b261ecSmrg if (pcbr == NULL) 77805b261ecSmrg cbl->list = cbr->next; 77905b261ecSmrg else 78005b261ecSmrg pcbr->next = cbr->next; 78105b261ecSmrg xfree(cbr); 78205b261ecSmrg } 78305b261ecSmrg return TRUE; 78405b261ecSmrg } 78505b261ecSmrg return FALSE; 78605b261ecSmrg} 78705b261ecSmrg 78805b261ecSmrgstatic void 78905b261ecSmrg_CallCallbacks( 79005b261ecSmrg CallbackListPtr *pcbl, 79105b261ecSmrg pointer call_data) 79205b261ecSmrg{ 79305b261ecSmrg CallbackListPtr cbl = *pcbl; 79405b261ecSmrg CallbackPtr cbr, pcbr; 79505b261ecSmrg 79605b261ecSmrg ++(cbl->inCallback); 79705b261ecSmrg for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) 79805b261ecSmrg { 79905b261ecSmrg (*(cbr->proc)) (pcbl, cbr->data, call_data); 80005b261ecSmrg } 80105b261ecSmrg --(cbl->inCallback); 80205b261ecSmrg 80305b261ecSmrg if (cbl->inCallback) return; 80405b261ecSmrg 80505b261ecSmrg /* Was the entire list marked for deletion? */ 80605b261ecSmrg 80705b261ecSmrg if (cbl->deleted) 80805b261ecSmrg { 80905b261ecSmrg DeleteCallbackList(pcbl); 81005b261ecSmrg return; 81105b261ecSmrg } 81205b261ecSmrg 81305b261ecSmrg /* Were some individual callbacks on the list marked for deletion? 81405b261ecSmrg * If so, do the deletions. 81505b261ecSmrg */ 81605b261ecSmrg 81705b261ecSmrg if (cbl->numDeleted) 81805b261ecSmrg { 81905b261ecSmrg for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; ) 82005b261ecSmrg { 82105b261ecSmrg if (cbr->deleted) 82205b261ecSmrg { 82305b261ecSmrg if (pcbr) 82405b261ecSmrg { 82505b261ecSmrg cbr = cbr->next; 82605b261ecSmrg xfree(pcbr->next); 82705b261ecSmrg pcbr->next = cbr; 82805b261ecSmrg } else 82905b261ecSmrg { 83005b261ecSmrg cbr = cbr->next; 83105b261ecSmrg xfree(cbl->list); 83205b261ecSmrg cbl->list = cbr; 83305b261ecSmrg } 83405b261ecSmrg cbl->numDeleted--; 83505b261ecSmrg } 83605b261ecSmrg else /* this one wasn't deleted */ 83705b261ecSmrg { 83805b261ecSmrg pcbr = cbr; 83905b261ecSmrg cbr = cbr->next; 84005b261ecSmrg } 84105b261ecSmrg } 84205b261ecSmrg } 84305b261ecSmrg} 84405b261ecSmrg 84505b261ecSmrgstatic void 84605b261ecSmrg_DeleteCallbackList( 84705b261ecSmrg CallbackListPtr *pcbl) 84805b261ecSmrg{ 84905b261ecSmrg CallbackListPtr cbl = *pcbl; 85005b261ecSmrg CallbackPtr cbr, nextcbr; 85105b261ecSmrg int i; 85205b261ecSmrg 85305b261ecSmrg if (cbl->inCallback) 85405b261ecSmrg { 85505b261ecSmrg cbl->deleted = TRUE; 85605b261ecSmrg return; 85705b261ecSmrg } 85805b261ecSmrg 85905b261ecSmrg for (i = 0; i < numCallbackListsToCleanup; i++) 86005b261ecSmrg { 86105b261ecSmrg if ((listsToCleanup[i] = pcbl) != 0) 86205b261ecSmrg { 86305b261ecSmrg listsToCleanup[i] = NULL; 86405b261ecSmrg break; 86505b261ecSmrg } 86605b261ecSmrg } 86705b261ecSmrg 86805b261ecSmrg for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) 86905b261ecSmrg { 87005b261ecSmrg nextcbr = cbr->next; 87105b261ecSmrg xfree(cbr); 87205b261ecSmrg } 87305b261ecSmrg xfree(cbl); 87405b261ecSmrg *pcbl = NULL; 87505b261ecSmrg} 87605b261ecSmrg 87705b261ecSmrgstatic CallbackFuncsRec default_cbfuncs = 87805b261ecSmrg{ 87905b261ecSmrg _AddCallback, 88005b261ecSmrg _DeleteCallback, 88105b261ecSmrg _CallCallbacks, 88205b261ecSmrg _DeleteCallbackList 88305b261ecSmrg}; 88405b261ecSmrg 88505b261ecSmrgstatic Bool 88605b261ecSmrgCreateCallbackList(CallbackListPtr *pcbl, CallbackFuncsPtr cbfuncs) 88705b261ecSmrg{ 88805b261ecSmrg CallbackListPtr cbl; 88905b261ecSmrg int i; 89005b261ecSmrg 89105b261ecSmrg if (!pcbl) return FALSE; 89205b261ecSmrg cbl = (CallbackListPtr) xalloc(sizeof(CallbackListRec)); 89305b261ecSmrg if (!cbl) return FALSE; 89405b261ecSmrg cbl->funcs = cbfuncs ? *cbfuncs : default_cbfuncs; 89505b261ecSmrg cbl->inCallback = 0; 89605b261ecSmrg cbl->deleted = FALSE; 89705b261ecSmrg cbl->numDeleted = 0; 89805b261ecSmrg cbl->list = NULL; 89905b261ecSmrg *pcbl = cbl; 90005b261ecSmrg 90105b261ecSmrg for (i = 0; i < numCallbackListsToCleanup; i++) 90205b261ecSmrg { 90305b261ecSmrg if (!listsToCleanup[i]) 90405b261ecSmrg { 90505b261ecSmrg listsToCleanup[i] = pcbl; 90605b261ecSmrg return TRUE; 90705b261ecSmrg } 90805b261ecSmrg } 90905b261ecSmrg 91005b261ecSmrg listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup, 91105b261ecSmrg sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1)); 91205b261ecSmrg listsToCleanup[numCallbackListsToCleanup] = pcbl; 91305b261ecSmrg numCallbackListsToCleanup++; 91405b261ecSmrg return TRUE; 91505b261ecSmrg} 91605b261ecSmrg 91705b261ecSmrg/* ===== Public Procedures ===== */ 91805b261ecSmrg 91905b261ecSmrg_X_EXPORT Bool 92005b261ecSmrgAddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) 92105b261ecSmrg{ 92205b261ecSmrg if (!pcbl) return FALSE; 92305b261ecSmrg if (!*pcbl) 92405b261ecSmrg { /* list hasn't been created yet; go create it */ 92505b261ecSmrg if (!CreateCallbackList(pcbl, (CallbackFuncsPtr)NULL)) 92605b261ecSmrg return FALSE; 92705b261ecSmrg } 92805b261ecSmrg return ((*(*pcbl)->funcs.AddCallback) (pcbl, callback, data)); 92905b261ecSmrg} 93005b261ecSmrg 93105b261ecSmrg_X_EXPORT Bool 93205b261ecSmrgDeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) 93305b261ecSmrg{ 93405b261ecSmrg if (!pcbl || !*pcbl) return FALSE; 93505b261ecSmrg return ((*(*pcbl)->funcs.DeleteCallback) (pcbl, callback, data)); 93605b261ecSmrg} 93705b261ecSmrg 93805b261ecSmrgvoid 93905b261ecSmrgCallCallbacks(CallbackListPtr *pcbl, pointer call_data) 94005b261ecSmrg{ 94105b261ecSmrg if (!pcbl || !*pcbl) return; 94205b261ecSmrg (*(*pcbl)->funcs.CallCallbacks) (pcbl, call_data); 94305b261ecSmrg} 94405b261ecSmrg 94505b261ecSmrgvoid 94605b261ecSmrgDeleteCallbackList(CallbackListPtr *pcbl) 94705b261ecSmrg{ 94805b261ecSmrg if (!pcbl || !*pcbl) return; 94905b261ecSmrg (*(*pcbl)->funcs.DeleteCallbackList) (pcbl); 95005b261ecSmrg} 95105b261ecSmrg 95205b261ecSmrgvoid 95305b261ecSmrgInitCallbackManager(void) 95405b261ecSmrg{ 95505b261ecSmrg int i; 95605b261ecSmrg 95705b261ecSmrg for (i = 0; i < numCallbackListsToCleanup; i++) 95805b261ecSmrg { 95905b261ecSmrg DeleteCallbackList(listsToCleanup[i]); 96005b261ecSmrg } 96105b261ecSmrg if (listsToCleanup) xfree(listsToCleanup); 96205b261ecSmrg 96305b261ecSmrg numCallbackListsToCleanup = 0; 96405b261ecSmrg listsToCleanup = NULL; 96505b261ecSmrg} 966