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 2505b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 2605b261ecSmrg 2705b261ecSmrg All Rights Reserved 2805b261ecSmrg 2935c4bbdfSmrgPermission to use, copy, modify, and distribute this software and its 3035c4bbdfSmrgdocumentation for any purpose and without fee is hereby granted, 3105b261ecSmrgprovided that the above copyright notice appear in all copies and that 3235c4bbdfSmrgboth that copyright notice and this permission notice appear in 3305b261ecSmrgsupporting documentation, and that the name of Digital not be 3405b261ecSmrgused in advertising or publicity pertaining to distribution of the 3535c4bbdfSmrgsoftware without specific, written prior permission. 3605b261ecSmrg 3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 4305b261ecSmrgSOFTWARE. 4405b261ecSmrg 4505b261ecSmrg******************************************************************/ 4605b261ecSmrg 4705b261ecSmrg/* 4805b261ecSmrg 4905b261ecSmrg(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved. 5005b261ecSmrg 5105b261ecSmrgPermission to use, copy, modify, distribute, and sublicense this software and its 5205b261ecSmrgdocumentation for any purpose and without fee is hereby granted, provided that 5305b261ecSmrgthe above copyright notices appear in all copies and that both those copyright 5405b261ecSmrgnotices and this permission notice appear in supporting documentation and that 5505b261ecSmrgthe name of Adobe Systems Incorporated not be used in advertising or publicity 5605b261ecSmrgpertaining to distribution of the software without specific, written prior 5705b261ecSmrgpermission. No trademark license to use the Adobe trademarks is hereby 5805b261ecSmrggranted. If the Adobe trademark "Display PostScript"(tm) is used to describe 5905b261ecSmrgthis software, its functionality or for any other purpose, such use shall be 6005b261ecSmrglimited to a statement that this software works in conjunction with the Display 6105b261ecSmrgPostScript system. Proper trademark attribution to reflect Adobe's ownership 6205b261ecSmrgof the trademark shall be given whenever any such reference to the Display 6305b261ecSmrgPostScript system is made. 6405b261ecSmrg 6505b261ecSmrgADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY 6605b261ecSmrgPURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE 6705b261ecSmrgDISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED 6805b261ecSmrgWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- 6905b261ecSmrgINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU 7005b261ecSmrgOR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY 7105b261ecSmrgDAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT 7205b261ecSmrgLIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR 7305b261ecSmrgPERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER 7405b261ecSmrgSUPPORT FOR THE SOFTWARE. 7505b261ecSmrg 7605b261ecSmrgAdobe, PostScript, and Display PostScript are trademarks of Adobe Systems 7705b261ecSmrgIncorporated which may be registered in certain jurisdictions. 7805b261ecSmrg 7905b261ecSmrgAuthor: Adobe Systems Incorporated 8005b261ecSmrg 8105b261ecSmrg*/ 8205b261ecSmrg 8305b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 8405b261ecSmrg#include <dix-config.h> 8505b261ecSmrg#endif 8605b261ecSmrg 8705b261ecSmrg#include <X11/X.h> 8805b261ecSmrg#include <X11/Xmd.h> 8905b261ecSmrg#include "misc.h" 9005b261ecSmrg#include "windowstr.h" 9105b261ecSmrg#include "dixstruct.h" 9205b261ecSmrg#include "pixmapstr.h" 936747b715Smrg#include "gcstruct.h" 9405b261ecSmrg#include "scrnintstr.h" 9505b261ecSmrg#define XK_LATIN1 9605b261ecSmrg#include <X11/keysymdef.h> 9705b261ecSmrg#include "xace.h" 9805b261ecSmrg 9905b261ecSmrg/* 10005b261ecSmrg * CompareTimeStamps returns -1, 0, or +1 depending on if the first 10105b261ecSmrg * argument is less than, equal to or greater than the second argument. 10205b261ecSmrg */ 10305b261ecSmrg 1046747b715Smrgint 10505b261ecSmrgCompareTimeStamps(TimeStamp a, TimeStamp b) 10605b261ecSmrg{ 10705b261ecSmrg if (a.months < b.months) 10835c4bbdfSmrg return EARLIER; 10905b261ecSmrg if (a.months > b.months) 11035c4bbdfSmrg return LATER; 11105b261ecSmrg if (a.milliseconds < b.milliseconds) 11235c4bbdfSmrg return EARLIER; 11305b261ecSmrg if (a.milliseconds > b.milliseconds) 11435c4bbdfSmrg return LATER; 11505b261ecSmrg return SAMETIME; 11605b261ecSmrg} 11705b261ecSmrg 11805b261ecSmrg/* 11905b261ecSmrg * convert client times to server TimeStamps 12005b261ecSmrg */ 12105b261ecSmrg 12205b261ecSmrg#define HALFMONTH ((unsigned long) 1<<31) 1236747b715SmrgTimeStamp 12405b261ecSmrgClientTimeToServerTime(CARD32 c) 12505b261ecSmrg{ 12605b261ecSmrg TimeStamp ts; 12735c4bbdfSmrg 12805b261ecSmrg if (c == CurrentTime) 12935c4bbdfSmrg return currentTime; 13005b261ecSmrg ts.months = currentTime.months; 13105b261ecSmrg ts.milliseconds = c; 13235c4bbdfSmrg if (c > currentTime.milliseconds) { 13335c4bbdfSmrg if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH) 13435c4bbdfSmrg ts.months -= 1; 13505b261ecSmrg } 13635c4bbdfSmrg else if (c < currentTime.milliseconds) { 13735c4bbdfSmrg if (((unsigned long) currentTime.milliseconds - c) > HALFMONTH) 13835c4bbdfSmrg ts.months += 1; 13905b261ecSmrg } 14005b261ecSmrg return ts; 14105b261ecSmrg} 14205b261ecSmrg 14305b261ecSmrg/* 14405b261ecSmrg * ISO Latin-1 case conversion routine 14505b261ecSmrg * 14605b261ecSmrg * this routine always null-terminates the result, so 14705b261ecSmrg * beware of too-small buffers 14805b261ecSmrg */ 14905b261ecSmrg 15005b261ecSmrgstatic unsigned char 15135c4bbdfSmrgISOLatin1ToLower(unsigned char source) 15205b261ecSmrg{ 15335c4bbdfSmrg unsigned char dest; 15435c4bbdfSmrg 15505b261ecSmrg if ((source >= XK_A) && (source <= XK_Z)) 15635c4bbdfSmrg dest = source + (XK_a - XK_A); 15705b261ecSmrg else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis)) 15835c4bbdfSmrg dest = source + (XK_agrave - XK_Agrave); 15905b261ecSmrg else if ((source >= XK_Ooblique) && (source <= XK_Thorn)) 16035c4bbdfSmrg dest = source + (XK_oslash - XK_Ooblique); 16105b261ecSmrg else 16235c4bbdfSmrg dest = source; 16305b261ecSmrg return dest; 16405b261ecSmrg} 16505b261ecSmrg 16605b261ecSmrgint 16735c4bbdfSmrgCompareISOLatin1Lowered(const unsigned char *s1, int s1len, 16835c4bbdfSmrg const unsigned char *s2, int s2len) 16935c4bbdfSmrg{ 17035c4bbdfSmrg unsigned char c1, c2; 17135c4bbdfSmrg 17235c4bbdfSmrg for (;;) { 17335c4bbdfSmrg /* note -- compare against zero so that -1 ignores len */ 17435c4bbdfSmrg c1 = s1len-- ? *s1++ : '\0'; 17535c4bbdfSmrg c2 = s2len-- ? *s2++ : '\0'; 17635c4bbdfSmrg if (!c1 || 17735c4bbdfSmrg (c1 != c2 && 17835c4bbdfSmrg (c1 = ISOLatin1ToLower(c1)) != (c2 = ISOLatin1ToLower(c2)))) 17935c4bbdfSmrg break; 18005b261ecSmrg } 18105b261ecSmrg return (int) c1 - (int) c2; 18205b261ecSmrg} 18305b261ecSmrg 18405b261ecSmrg/* 18505b261ecSmrg * dixLookupWindow and dixLookupDrawable: 18605b261ecSmrg * Look up the window/drawable taking into account the client doing the 18705b261ecSmrg * lookup, the type of drawable desired, and the type of access desired. 18805b261ecSmrg * Return Success with *pDraw set if the window/drawable exists and the client 18905b261ecSmrg * is allowed access, else return an error code with *pDraw set to NULL. The 19005b261ecSmrg * access mask values are defined in resource.h. The type mask values are 19105b261ecSmrg * defined in pixmap.h, with zero equivalent to M_DRAWABLE. 19205b261ecSmrg */ 1936747b715Smrgint 19405b261ecSmrgdixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client, 19535c4bbdfSmrg Mask type, Mask access) 19605b261ecSmrg{ 19705b261ecSmrg DrawablePtr pTmp; 1984642e01fSmrg int rc; 1994642e01fSmrg 20005b261ecSmrg *pDraw = NULL; 20105b261ecSmrg 20235c4bbdfSmrg rc = dixLookupResourceByClass((void **) &pTmp, id, RC_DRAWABLE, client, 20335c4bbdfSmrg access); 2044642e01fSmrg 205475c125cSmrg if (rc != Success) 20635c4bbdfSmrg client->errorValue = id; 207475c125cSmrg 2084642e01fSmrg if (rc == BadValue) 20935c4bbdfSmrg return BadDrawable; 2104642e01fSmrg if (rc != Success) 21135c4bbdfSmrg return rc; 21205b261ecSmrg if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE))) 21335c4bbdfSmrg return BadMatch; 21405b261ecSmrg 21505b261ecSmrg *pDraw = pTmp; 21605b261ecSmrg return Success; 21705b261ecSmrg} 21805b261ecSmrg 2196747b715Smrgint 22005b261ecSmrgdixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access) 22105b261ecSmrg{ 22205b261ecSmrg int rc; 22335c4bbdfSmrg 22435c4bbdfSmrg rc = dixLookupDrawable((DrawablePtr *) pWin, id, client, M_WINDOW, access); 22535c4bbdfSmrg /* dixLookupDrawable returns BadMatch iff id is a valid Drawable 22635c4bbdfSmrg but is not a Window. Users of dixLookupWindow expect a BadWindow 22735c4bbdfSmrg error in this case; they don't care that it's a valid non-Window XID */ 22835c4bbdfSmrg if (rc == BadMatch) 22935c4bbdfSmrg rc = BadWindow; 23035c4bbdfSmrg /* Similarly, users of dixLookupWindow don't want BadDrawable. */ 23135c4bbdfSmrg if (rc == BadDrawable) 23235c4bbdfSmrg rc = BadWindow; 23335c4bbdfSmrg return rc; 23405b261ecSmrg} 23505b261ecSmrg 2366747b715Smrgint 23705b261ecSmrgdixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access) 23805b261ecSmrg{ 23935c4bbdfSmrg return dixLookupResourceByType((void **) pGC, id, RT_GC, client, access); 24005b261ecSmrg} 24105b261ecSmrg 2426747b715Smrgint 2436747b715SmrgdixLookupFontable(FontPtr *pFont, XID id, ClientPtr client, Mask access) 2446747b715Smrg{ 2456747b715Smrg int rc; 2466747b715Smrg GC *pGC; 24735c4bbdfSmrg 24835c4bbdfSmrg client->errorValue = id; /* EITHER font or gc */ 24935c4bbdfSmrg rc = dixLookupResourceByType((void **) pFont, id, RT_FONT, client, 25035c4bbdfSmrg access); 2516747b715Smrg if (rc != BadFont) 25235c4bbdfSmrg return rc; 25335c4bbdfSmrg rc = dixLookupResourceByType((void **) &pGC, id, RT_GC, client, access); 2546747b715Smrg if (rc == BadGC) 25535c4bbdfSmrg return BadFont; 2566747b715Smrg if (rc == Success) 25735c4bbdfSmrg *pFont = pGC->font; 2586747b715Smrg return rc; 2596747b715Smrg} 2606747b715Smrg 2616747b715Smrgint 26205b261ecSmrgdixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access) 26305b261ecSmrg{ 26435c4bbdfSmrg void *pRes; 2654642e01fSmrg int rc = BadValue, clientIndex = CLIENT_ID(rid); 26605b261ecSmrg 2674642e01fSmrg if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT)) 26835c4bbdfSmrg goto bad; 26905b261ecSmrg 270b86d567bSmrg rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess); 2714642e01fSmrg if (rc != Success) 27235c4bbdfSmrg goto bad; 27305b261ecSmrg 2744642e01fSmrg rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access); 2754642e01fSmrg if (rc != Success) 27635c4bbdfSmrg goto bad; 27705b261ecSmrg 2784642e01fSmrg *pClient = clients[clientIndex]; 2794642e01fSmrg return Success; 28035c4bbdfSmrg bad: 28135c4bbdfSmrg if (client) 2824642e01fSmrg client->errorValue = rid; 2834642e01fSmrg *pClient = NULL; 2844642e01fSmrg return rc; 28505b261ecSmrg} 28605b261ecSmrg 28705b261ecSmrgint 28805b261ecSmrgAlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, 2894642e01fSmrg Bool toRoot, Bool map) 29005b261ecSmrg{ 29105b261ecSmrg int numnow; 29205b261ecSmrg SaveSetElt *pTmp = NULL; 29305b261ecSmrg int j; 29405b261ecSmrg 29505b261ecSmrg numnow = client->numSaved; 29605b261ecSmrg j = 0; 29735c4bbdfSmrg if (numnow) { 29835c4bbdfSmrg pTmp = client->saveSet; 29935c4bbdfSmrg while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (void *) pWin)) 30035c4bbdfSmrg j++; 30105b261ecSmrg } 30235c4bbdfSmrg if (mode == SetModeInsert) { 30335c4bbdfSmrg if (j < numnow) /* duplicate */ 30435c4bbdfSmrg return Success; 30535c4bbdfSmrg numnow++; 30635c4bbdfSmrg pTmp = (SaveSetElt *) realloc(client->saveSet, sizeof(*pTmp) * numnow); 30735c4bbdfSmrg if (!pTmp) 30835c4bbdfSmrg return BadAlloc; 30935c4bbdfSmrg client->saveSet = pTmp; 31035c4bbdfSmrg client->numSaved = numnow; 31135c4bbdfSmrg SaveSetAssignWindow(client->saveSet[numnow - 1], pWin); 31235c4bbdfSmrg SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot); 31335c4bbdfSmrg SaveSetAssignMap(client->saveSet[numnow - 1], map); 31435c4bbdfSmrg return Success; 31505b261ecSmrg } 31635c4bbdfSmrg else if ((mode == SetModeDelete) && (j < numnow)) { 31735c4bbdfSmrg while (j < numnow - 1) { 31835c4bbdfSmrg pTmp[j] = pTmp[j + 1]; 31935c4bbdfSmrg j++; 32035c4bbdfSmrg } 32135c4bbdfSmrg numnow--; 32235c4bbdfSmrg if (numnow) { 32335c4bbdfSmrg pTmp = 32435c4bbdfSmrg (SaveSetElt *) realloc(client->saveSet, sizeof(*pTmp) * numnow); 32535c4bbdfSmrg if (pTmp) 32635c4bbdfSmrg client->saveSet = pTmp; 32735c4bbdfSmrg } 32835c4bbdfSmrg else { 3296747b715Smrg free(client->saveSet); 33035c4bbdfSmrg client->saveSet = (SaveSetElt *) NULL; 33135c4bbdfSmrg } 33235c4bbdfSmrg client->numSaved = numnow; 33335c4bbdfSmrg return Success; 33405b261ecSmrg } 3356747b715Smrg return Success; 33605b261ecSmrg} 33705b261ecSmrg 33805b261ecSmrgvoid 33905b261ecSmrgDeleteWindowFromAnySaveSet(WindowPtr pWin) 34005b261ecSmrg{ 34105b261ecSmrg int i; 34205b261ecSmrg ClientPtr client; 34335c4bbdfSmrg 34435c4bbdfSmrg for (i = 0; i < currentMaxClients; i++) { 34535c4bbdfSmrg client = clients[i]; 34635c4bbdfSmrg if (client && client->numSaved) 34735c4bbdfSmrg (void) AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, 34835c4bbdfSmrg TRUE); 34905b261ecSmrg } 35005b261ecSmrg} 35105b261ecSmrg 35205b261ecSmrg/* No-op Don't Do Anything : sometimes we need to be able to call a procedure 35305b261ecSmrg * that doesn't do anything. For example, on screen with only static 35405b261ecSmrg * colormaps, if someone calls install colormap, it's easier to have a dummy 35535c4bbdfSmrg * procedure to call than to check if there's a procedure 35605b261ecSmrg */ 3576747b715Smrgvoid 35805b261ecSmrgNoopDDA(void) 35905b261ecSmrg{ 36005b261ecSmrg} 36105b261ecSmrg 36205b261ecSmrgtypedef struct _BlockHandler { 3631b5d61b8Smrg ServerBlockHandlerProcPtr BlockHandler; 3641b5d61b8Smrg ServerWakeupHandlerProcPtr WakeupHandler; 36535c4bbdfSmrg void *blockData; 36635c4bbdfSmrg Bool deleted; 36705b261ecSmrg} BlockHandlerRec, *BlockHandlerPtr; 36805b261ecSmrg 36935c4bbdfSmrgstatic BlockHandlerPtr handlers; 37035c4bbdfSmrgstatic int numHandlers; 37135c4bbdfSmrgstatic int sizeHandlers; 37235c4bbdfSmrgstatic Bool inHandler; 37335c4bbdfSmrgstatic Bool handlerDeleted; 37405b261ecSmrg 37505b261ecSmrg/** 37635c4bbdfSmrg * 37705b261ecSmrg * \param pTimeout DIX doesn't want to know how OS represents time 37805b261ecSmrg * \param pReadMask nor how it represents the det of descriptors 37905b261ecSmrg */ 38005b261ecSmrgvoid 3811b5d61b8SmrgBlockHandler(void *pTimeout) 38205b261ecSmrg{ 38305b261ecSmrg int i, j; 38435c4bbdfSmrg 38505b261ecSmrg ++inHandler; 38605b261ecSmrg for (i = 0; i < numHandlers; i++) 38735c4bbdfSmrg if (!handlers[i].deleted) 3881b5d61b8Smrg (*handlers[i].BlockHandler) (handlers[i].blockData, pTimeout); 3891b5d61b8Smrg 3901b5d61b8Smrg for (i = 0; i < screenInfo.numGPUScreens; i++) 3911b5d61b8Smrg (*screenInfo.gpuscreens[i]->BlockHandler) (screenInfo.gpuscreens[i], pTimeout); 3921b5d61b8Smrg 3931b5d61b8Smrg for (i = 0; i < screenInfo.numScreens; i++) 3941b5d61b8Smrg (*screenInfo.screens[i]->BlockHandler) (screenInfo.screens[i], pTimeout); 3951b5d61b8Smrg 39635c4bbdfSmrg if (handlerDeleted) { 39735c4bbdfSmrg for (i = 0; i < numHandlers;) 39835c4bbdfSmrg if (handlers[i].deleted) { 39935c4bbdfSmrg for (j = i; j < numHandlers - 1; j++) 40035c4bbdfSmrg handlers[j] = handlers[j + 1]; 40135c4bbdfSmrg numHandlers--; 40235c4bbdfSmrg } 40335c4bbdfSmrg else 40435c4bbdfSmrg i++; 40535c4bbdfSmrg handlerDeleted = FALSE; 40605b261ecSmrg } 40705b261ecSmrg --inHandler; 40805b261ecSmrg} 40905b261ecSmrg 41005b261ecSmrg/** 41105b261ecSmrg * 41205b261ecSmrg * \param result 32 bits of undefined result from the wait 41305b261ecSmrg * \param pReadmask the resulting descriptor mask 41405b261ecSmrg */ 41505b261ecSmrgvoid 4161b5d61b8SmrgWakeupHandler(int result) 41705b261ecSmrg{ 41805b261ecSmrg int i, j; 41905b261ecSmrg 42005b261ecSmrg ++inHandler; 42105b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 4221b5d61b8Smrg (*screenInfo.screens[i]->WakeupHandler) (screenInfo.screens[i], result); 42335c4bbdfSmrg for (i = 0; i < screenInfo.numGPUScreens; i++) 4241b5d61b8Smrg (*screenInfo.gpuscreens[i]->WakeupHandler) (screenInfo.gpuscreens[i], result); 4251b5d61b8Smrg for (i = numHandlers - 1; i >= 0; i--) 4261b5d61b8Smrg if (!handlers[i].deleted) 4271b5d61b8Smrg (*handlers[i].WakeupHandler) (handlers[i].blockData, result); 42835c4bbdfSmrg if (handlerDeleted) { 42935c4bbdfSmrg for (i = 0; i < numHandlers;) 43035c4bbdfSmrg if (handlers[i].deleted) { 43135c4bbdfSmrg for (j = i; j < numHandlers - 1; j++) 43235c4bbdfSmrg handlers[j] = handlers[j + 1]; 43335c4bbdfSmrg numHandlers--; 43435c4bbdfSmrg } 43535c4bbdfSmrg else 43635c4bbdfSmrg i++; 43735c4bbdfSmrg handlerDeleted = FALSE; 43805b261ecSmrg } 43905b261ecSmrg --inHandler; 44005b261ecSmrg} 44105b261ecSmrg 44205b261ecSmrg/** 44305b261ecSmrg * Reentrant with BlockHandler and WakeupHandler, except wakeup won't 44405b261ecSmrg * get called until next time 44505b261ecSmrg */ 4466747b715SmrgBool 4471b5d61b8SmrgRegisterBlockAndWakeupHandlers(ServerBlockHandlerProcPtr blockHandler, 4481b5d61b8Smrg ServerWakeupHandlerProcPtr wakeupHandler, 44935c4bbdfSmrg void *blockData) 45005b261ecSmrg{ 45105b261ecSmrg BlockHandlerPtr new; 45205b261ecSmrg 45335c4bbdfSmrg if (numHandlers >= sizeHandlers) { 4546747b715Smrg new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) * 45535c4bbdfSmrg sizeof(BlockHandlerRec)); 45635c4bbdfSmrg if (!new) 45735c4bbdfSmrg return FALSE; 45835c4bbdfSmrg handlers = new; 45935c4bbdfSmrg 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 4701b5d61b8SmrgRemoveBlockAndWakeupHandlers(ServerBlockHandlerProcPtr blockHandler, 4711b5d61b8Smrg ServerWakeupHandlerProcPtr wakeupHandler, 47235c4bbdfSmrg void *blockData) 47305b261ecSmrg{ 47435c4bbdfSmrg int i; 47505b261ecSmrg 47605b261ecSmrg for (i = 0; i < numHandlers; i++) 47735c4bbdfSmrg if (handlers[i].BlockHandler == blockHandler && 47835c4bbdfSmrg handlers[i].WakeupHandler == wakeupHandler && 47935c4bbdfSmrg handlers[i].blockData == blockData) { 48035c4bbdfSmrg if (inHandler) { 48135c4bbdfSmrg handlerDeleted = TRUE; 48235c4bbdfSmrg handlers[i].deleted = TRUE; 48335c4bbdfSmrg } 48435c4bbdfSmrg else { 48535c4bbdfSmrg for (; i < numHandlers - 1; i++) 48635c4bbdfSmrg handlers[i] = handlers[i + 1]; 48735c4bbdfSmrg numHandlers--; 48835c4bbdfSmrg } 48935c4bbdfSmrg break; 49035c4bbdfSmrg } 49105b261ecSmrg} 49205b261ecSmrg 49305b261ecSmrgvoid 49435c4bbdfSmrgInitBlockAndWakeupHandlers(void) 49505b261ecSmrg{ 4966747b715Smrg free(handlers); 49705b261ecSmrg handlers = (BlockHandlerPtr) 0; 49805b261ecSmrg numHandlers = 0; 49905b261ecSmrg sizeHandlers = 0; 50005b261ecSmrg} 50105b261ecSmrg 50205b261ecSmrg/* 50305b261ecSmrg * A general work queue. Perform some task before the server 50405b261ecSmrg * sleeps for input. 50505b261ecSmrg */ 50605b261ecSmrg 50735c4bbdfSmrgWorkQueuePtr workQueue; 50835c4bbdfSmrgstatic WorkQueuePtr *workQueueLast = &workQueue; 50905b261ecSmrg 5103517b66bSmrgvoid 5113517b66bSmrgClearWorkQueue(void) 5123517b66bSmrg{ 5133517b66bSmrg WorkQueuePtr q, *p; 5143517b66bSmrg 5153517b66bSmrg p = &workQueue; 5163517b66bSmrg while ((q = *p)) { 5173517b66bSmrg *p = q->next; 5183517b66bSmrg free(q); 5193517b66bSmrg } 5203517b66bSmrg workQueueLast = p; 5213517b66bSmrg} 5223517b66bSmrg 52305b261ecSmrgvoid 52405b261ecSmrgProcessWorkQueue(void) 52505b261ecSmrg{ 52635c4bbdfSmrg WorkQueuePtr q, *p; 52705b261ecSmrg 52805b261ecSmrg p = &workQueue; 52905b261ecSmrg /* 53005b261ecSmrg * Scan the work queue once, calling each function. Those 53105b261ecSmrg * which return TRUE are removed from the queue, otherwise 53205b261ecSmrg * they will be called again. This must be reentrant with 53305b261ecSmrg * QueueWorkProc. 53405b261ecSmrg */ 53535c4bbdfSmrg while ((q = *p)) { 53635c4bbdfSmrg if ((*q->function) (q->client, q->closure)) { 53735c4bbdfSmrg /* remove q from the list */ 53835c4bbdfSmrg *p = q->next; /* don't fetch until after func called */ 53935c4bbdfSmrg free(q); 54035c4bbdfSmrg } 54135c4bbdfSmrg else { 54235c4bbdfSmrg p = &q->next; /* don't fetch until after func called */ 54335c4bbdfSmrg } 54405b261ecSmrg } 54505b261ecSmrg workQueueLast = p; 54605b261ecSmrg} 54705b261ecSmrg 54805b261ecSmrgvoid 54905b261ecSmrgProcessWorkQueueZombies(void) 55005b261ecSmrg{ 55135c4bbdfSmrg WorkQueuePtr q, *p; 55205b261ecSmrg 55305b261ecSmrg p = &workQueue; 55435c4bbdfSmrg while ((q = *p)) { 55535c4bbdfSmrg if (q->client && q->client->clientGone) { 55635c4bbdfSmrg (void) (*q->function) (q->client, q->closure); 55735c4bbdfSmrg /* remove q from the list */ 55835c4bbdfSmrg *p = q->next; /* don't fetch until after func called */ 55935c4bbdfSmrg free(q); 56035c4bbdfSmrg } 56135c4bbdfSmrg else { 56235c4bbdfSmrg p = &q->next; /* don't fetch until after func called */ 56335c4bbdfSmrg } 56405b261ecSmrg } 56505b261ecSmrg workQueueLast = p; 56605b261ecSmrg} 56705b261ecSmrg 5686747b715SmrgBool 56935c4bbdfSmrgQueueWorkProc(Bool (*function) (ClientPtr pClient, void *closure), 57035c4bbdfSmrg ClientPtr client, void *closure) 57105b261ecSmrg{ 57235c4bbdfSmrg WorkQueuePtr q; 57305b261ecSmrg 5746747b715Smrg q = malloc(sizeof *q); 57505b261ecSmrg if (!q) 57635c4bbdfSmrg return FALSE; 57705b261ecSmrg q->function = function; 57805b261ecSmrg q->client = client; 57905b261ecSmrg q->closure = closure; 58005b261ecSmrg q->next = NULL; 58105b261ecSmrg *workQueueLast = q; 58205b261ecSmrg workQueueLast = &q->next; 58305b261ecSmrg return TRUE; 58405b261ecSmrg} 58505b261ecSmrg 58605b261ecSmrg/* 58705b261ecSmrg * Manage a queue of sleeping clients, awakening them 58805b261ecSmrg * when requested, by using the OS functions IgnoreClient 58905b261ecSmrg * and AttendClient. Note that this *ignores* the troubles 59005b261ecSmrg * with request data interleaving itself with events, but 59105b261ecSmrg * we'll leave that until a later time. 59205b261ecSmrg */ 59305b261ecSmrg 59405b261ecSmrgtypedef struct _SleepQueue { 59535c4bbdfSmrg struct _SleepQueue *next; 59635c4bbdfSmrg ClientPtr client; 59735c4bbdfSmrg ClientSleepProcPtr function; 59835c4bbdfSmrg void *closure; 59905b261ecSmrg} SleepQueueRec, *SleepQueuePtr; 60005b261ecSmrg 60135c4bbdfSmrgstatic SleepQueuePtr sleepQueue = NULL; 60205b261ecSmrg 6036747b715SmrgBool 60435c4bbdfSmrgClientSleep(ClientPtr client, ClientSleepProcPtr function, void *closure) 60505b261ecSmrg{ 60635c4bbdfSmrg SleepQueuePtr q; 60705b261ecSmrg 6086747b715Smrg q = malloc(sizeof *q); 60905b261ecSmrg if (!q) 61035c4bbdfSmrg return FALSE; 61105b261ecSmrg 61235c4bbdfSmrg IgnoreClient(client); 61305b261ecSmrg q->next = sleepQueue; 61405b261ecSmrg q->client = client; 61505b261ecSmrg q->function = function; 61605b261ecSmrg q->closure = closure; 61705b261ecSmrg sleepQueue = q; 61805b261ecSmrg return TRUE; 61905b261ecSmrg} 62005b261ecSmrg 62105b261ecSmrgBool 62235c4bbdfSmrgClientSignal(ClientPtr client) 62305b261ecSmrg{ 62435c4bbdfSmrg SleepQueuePtr q; 62505b261ecSmrg 62605b261ecSmrg for (q = sleepQueue; q; q = q->next) 62735c4bbdfSmrg if (q->client == client) { 62835c4bbdfSmrg return QueueWorkProc(q->function, q->client, q->closure); 62935c4bbdfSmrg } 63005b261ecSmrg return FALSE; 63105b261ecSmrg} 63205b261ecSmrg 63335c4bbdfSmrgint 63435c4bbdfSmrgClientSignalAll(ClientPtr client, ClientSleepProcPtr function, void *closure) 63535c4bbdfSmrg{ 63635c4bbdfSmrg SleepQueuePtr q; 63735c4bbdfSmrg int count = 0; 63835c4bbdfSmrg 63935c4bbdfSmrg for (q = sleepQueue; q; q = q->next) { 64035c4bbdfSmrg if (!(client == CLIENT_SIGNAL_ANY || q->client == client)) 64135c4bbdfSmrg continue; 64235c4bbdfSmrg 64335c4bbdfSmrg if (!(function == CLIENT_SIGNAL_ANY || q->function == function)) 64435c4bbdfSmrg continue; 64535c4bbdfSmrg 64635c4bbdfSmrg if (!(closure == CLIENT_SIGNAL_ANY || q->closure == closure)) 64735c4bbdfSmrg continue; 64835c4bbdfSmrg 64935c4bbdfSmrg count += QueueWorkProc(q->function, q->client, q->closure); 65035c4bbdfSmrg } 65135c4bbdfSmrg 65235c4bbdfSmrg return count; 65335c4bbdfSmrg} 65435c4bbdfSmrg 6556747b715Smrgvoid 65635c4bbdfSmrgClientWakeup(ClientPtr client) 65705b261ecSmrg{ 65835c4bbdfSmrg SleepQueuePtr q, *prev; 65905b261ecSmrg 66005b261ecSmrg prev = &sleepQueue; 66135c4bbdfSmrg while ((q = *prev)) { 66235c4bbdfSmrg if (q->client == client) { 66335c4bbdfSmrg *prev = q->next; 66435c4bbdfSmrg free(q); 66525da500fSmrg AttendClient(client); 66635c4bbdfSmrg break; 66735c4bbdfSmrg } 66835c4bbdfSmrg prev = &q->next; 66905b261ecSmrg } 67005b261ecSmrg} 67105b261ecSmrg 67205b261ecSmrgBool 67335c4bbdfSmrgClientIsAsleep(ClientPtr client) 67405b261ecSmrg{ 67535c4bbdfSmrg SleepQueuePtr q; 67605b261ecSmrg 67705b261ecSmrg for (q = sleepQueue; q; q = q->next) 67835c4bbdfSmrg if (q->client == client) 67935c4bbdfSmrg return TRUE; 68005b261ecSmrg return FALSE; 68105b261ecSmrg} 68205b261ecSmrg 68305b261ecSmrg/* 68405b261ecSmrg * Generic Callback Manager 68505b261ecSmrg */ 68605b261ecSmrg 68705b261ecSmrg/* ===== Private Procedures ===== */ 68805b261ecSmrg 68905b261ecSmrgstatic int numCallbackListsToCleanup = 0; 69005b261ecSmrgstatic CallbackListPtr **listsToCleanup = NULL; 69105b261ecSmrg 6926747b715Smrgstatic Bool 69335c4bbdfSmrg_AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data) 69405b261ecSmrg{ 69535c4bbdfSmrg CallbackPtr cbr; 69605b261ecSmrg 6976747b715Smrg cbr = malloc(sizeof(CallbackRec)); 69805b261ecSmrg if (!cbr) 69935c4bbdfSmrg return FALSE; 70005b261ecSmrg cbr->proc = callback; 70105b261ecSmrg cbr->data = data; 70205b261ecSmrg cbr->next = (*pcbl)->list; 70305b261ecSmrg cbr->deleted = FALSE; 70405b261ecSmrg (*pcbl)->list = cbr; 70505b261ecSmrg return TRUE; 70605b261ecSmrg} 70705b261ecSmrg 70835c4bbdfSmrgstatic Bool 70935c4bbdfSmrg_DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data) 71005b261ecSmrg{ 71105b261ecSmrg CallbackListPtr cbl = *pcbl; 71235c4bbdfSmrg CallbackPtr cbr, pcbr; 71335c4bbdfSmrg 71435c4bbdfSmrg for (pcbr = NULL, cbr = cbl->list; cbr != NULL; pcbr = cbr, cbr = cbr->next) { 71535c4bbdfSmrg if ((cbr->proc == callback) && (cbr->data == data)) 71635c4bbdfSmrg break; 71705b261ecSmrg } 71835c4bbdfSmrg if (cbr != NULL) { 71935c4bbdfSmrg if (cbl->inCallback) { 72035c4bbdfSmrg ++(cbl->numDeleted); 72135c4bbdfSmrg cbr->deleted = TRUE; 72235c4bbdfSmrg } 72335c4bbdfSmrg else { 72435c4bbdfSmrg if (pcbr == NULL) 72535c4bbdfSmrg cbl->list = cbr->next; 72635c4bbdfSmrg else 72735c4bbdfSmrg pcbr->next = cbr->next; 72835c4bbdfSmrg free(cbr); 72935c4bbdfSmrg } 73035c4bbdfSmrg return TRUE; 73105b261ecSmrg } 73205b261ecSmrg return FALSE; 73305b261ecSmrg} 73405b261ecSmrg 73535c4bbdfSmrgvoid 73635c4bbdfSmrg_CallCallbacks(CallbackListPtr *pcbl, void *call_data) 73705b261ecSmrg{ 73805b261ecSmrg CallbackListPtr cbl = *pcbl; 73935c4bbdfSmrg CallbackPtr cbr, pcbr; 74005b261ecSmrg 74105b261ecSmrg ++(cbl->inCallback); 74235c4bbdfSmrg for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) { 74335c4bbdfSmrg (*(cbr->proc)) (pcbl, cbr->data, call_data); 74405b261ecSmrg } 74505b261ecSmrg --(cbl->inCallback); 74605b261ecSmrg 74735c4bbdfSmrg if (cbl->inCallback) 74835c4bbdfSmrg return; 74905b261ecSmrg 75005b261ecSmrg /* Was the entire list marked for deletion? */ 75105b261ecSmrg 75235c4bbdfSmrg if (cbl->deleted) { 75335c4bbdfSmrg DeleteCallbackList(pcbl); 75435c4bbdfSmrg return; 75505b261ecSmrg } 75605b261ecSmrg 75705b261ecSmrg /* Were some individual callbacks on the list marked for deletion? 75805b261ecSmrg * If so, do the deletions. 75905b261ecSmrg */ 76005b261ecSmrg 76135c4bbdfSmrg if (cbl->numDeleted) { 76235c4bbdfSmrg for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted;) { 76335c4bbdfSmrg if (cbr->deleted) { 76435c4bbdfSmrg if (pcbr) { 76535c4bbdfSmrg cbr = cbr->next; 76635c4bbdfSmrg free(pcbr->next); 76735c4bbdfSmrg pcbr->next = cbr; 76835c4bbdfSmrg } 76935c4bbdfSmrg else { 77035c4bbdfSmrg cbr = cbr->next; 77135c4bbdfSmrg free(cbl->list); 77235c4bbdfSmrg cbl->list = cbr; 77335c4bbdfSmrg } 77435c4bbdfSmrg cbl->numDeleted--; 77535c4bbdfSmrg } 77635c4bbdfSmrg else { /* this one wasn't deleted */ 77735c4bbdfSmrg 77835c4bbdfSmrg pcbr = cbr; 77935c4bbdfSmrg cbr = cbr->next; 78035c4bbdfSmrg } 78135c4bbdfSmrg } 78205b261ecSmrg } 78305b261ecSmrg} 78405b261ecSmrg 78505b261ecSmrgstatic void 78635c4bbdfSmrg_DeleteCallbackList(CallbackListPtr *pcbl) 78705b261ecSmrg{ 78805b261ecSmrg CallbackListPtr cbl = *pcbl; 78935c4bbdfSmrg CallbackPtr cbr, nextcbr; 79005b261ecSmrg int i; 79105b261ecSmrg 79235c4bbdfSmrg if (cbl->inCallback) { 79335c4bbdfSmrg cbl->deleted = TRUE; 79435c4bbdfSmrg return; 79505b261ecSmrg } 79605b261ecSmrg 79735c4bbdfSmrg for (i = 0; i < numCallbackListsToCleanup; i++) { 79835c4bbdfSmrg if (listsToCleanup[i] == pcbl) { 79935c4bbdfSmrg listsToCleanup[i] = NULL; 80035c4bbdfSmrg break; 80135c4bbdfSmrg } 80205b261ecSmrg } 80305b261ecSmrg 80435c4bbdfSmrg for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) { 80535c4bbdfSmrg nextcbr = cbr->next; 80635c4bbdfSmrg free(cbr); 80705b261ecSmrg } 8086747b715Smrg free(cbl); 80905b261ecSmrg *pcbl = NULL; 81005b261ecSmrg} 81105b261ecSmrg 81205b261ecSmrgstatic Bool 8134642e01fSmrgCreateCallbackList(CallbackListPtr *pcbl) 81405b261ecSmrg{ 81535c4bbdfSmrg CallbackListPtr cbl; 81605b261ecSmrg int i; 81705b261ecSmrg 81835c4bbdfSmrg if (!pcbl) 81935c4bbdfSmrg return FALSE; 8206747b715Smrg cbl = malloc(sizeof(CallbackListRec)); 82135c4bbdfSmrg if (!cbl) 82235c4bbdfSmrg return FALSE; 82305b261ecSmrg cbl->inCallback = 0; 82405b261ecSmrg cbl->deleted = FALSE; 82505b261ecSmrg cbl->numDeleted = 0; 82605b261ecSmrg cbl->list = NULL; 82705b261ecSmrg *pcbl = cbl; 82805b261ecSmrg 82935c4bbdfSmrg for (i = 0; i < numCallbackListsToCleanup; i++) { 83035c4bbdfSmrg if (!listsToCleanup[i]) { 83135c4bbdfSmrg listsToCleanup[i] = pcbl; 83235c4bbdfSmrg return TRUE; 83335c4bbdfSmrg } 83405b261ecSmrg } 83505b261ecSmrg 83635c4bbdfSmrg listsToCleanup = (CallbackListPtr **) xnfrealloc(listsToCleanup, 83735c4bbdfSmrg sizeof(CallbackListPtr *) * 83835c4bbdfSmrg (numCallbackListsToCleanup 83935c4bbdfSmrg + 1)); 84005b261ecSmrg listsToCleanup[numCallbackListsToCleanup] = pcbl; 84105b261ecSmrg numCallbackListsToCleanup++; 84205b261ecSmrg return TRUE; 84305b261ecSmrg} 84405b261ecSmrg 84505b261ecSmrg/* ===== Public Procedures ===== */ 84605b261ecSmrg 8476747b715SmrgBool 84835c4bbdfSmrgAddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data) 84905b261ecSmrg{ 85035c4bbdfSmrg if (!pcbl) 85135c4bbdfSmrg return FALSE; 85235c4bbdfSmrg if (!*pcbl) { /* list hasn't been created yet; go create it */ 85335c4bbdfSmrg if (!CreateCallbackList(pcbl)) 85435c4bbdfSmrg return FALSE; 85505b261ecSmrg } 8564642e01fSmrg return _AddCallback(pcbl, callback, data); 85705b261ecSmrg} 85805b261ecSmrg 8596747b715SmrgBool 86035c4bbdfSmrgDeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data) 86105b261ecSmrg{ 86235c4bbdfSmrg if (!pcbl || !*pcbl) 86335c4bbdfSmrg return FALSE; 8644642e01fSmrg return _DeleteCallback(pcbl, callback, data); 86505b261ecSmrg} 86605b261ecSmrg 86705b261ecSmrgvoid 86805b261ecSmrgDeleteCallbackList(CallbackListPtr *pcbl) 86905b261ecSmrg{ 87035c4bbdfSmrg if (!pcbl || !*pcbl) 87135c4bbdfSmrg return; 8724642e01fSmrg _DeleteCallbackList(pcbl); 87305b261ecSmrg} 87405b261ecSmrg 8756747b715Smrgvoid 87635c4bbdfSmrgDeleteCallbackManager(void) 87705b261ecSmrg{ 87805b261ecSmrg int i; 87905b261ecSmrg 88035c4bbdfSmrg for (i = 0; i < numCallbackListsToCleanup; i++) { 88135c4bbdfSmrg DeleteCallbackList(listsToCleanup[i]); 88205b261ecSmrg } 8836747b715Smrg free(listsToCleanup); 88405b261ecSmrg 88505b261ecSmrg numCallbackListsToCleanup = 0; 88605b261ecSmrg listsToCleanup = NULL; 88705b261ecSmrg} 88835c4bbdfSmrg 88935c4bbdfSmrgvoid 89035c4bbdfSmrgInitCallbackManager(void) 89135c4bbdfSmrg{ 89235c4bbdfSmrg DeleteCallbackManager(); 89335c4bbdfSmrg} 89435c4bbdfSmrg 89535c4bbdfSmrg/** 89635c4bbdfSmrg * Coordinates the global GL context used by modules in the X Server 89735c4bbdfSmrg * doing rendering with OpenGL. 89835c4bbdfSmrg * 89935c4bbdfSmrg * When setting a GL context (glXMakeCurrent() or eglMakeCurrent()), 90035c4bbdfSmrg * there is an expensive implied glFlush() required by the GLX and EGL 90135c4bbdfSmrg * APIs, so modules don't want to have to do it on every request. But 90235c4bbdfSmrg * the individual modules using GL also don't know about each other, 90335c4bbdfSmrg * so they have to coordinate who owns the current context. 90435c4bbdfSmrg * 90535c4bbdfSmrg * When you're about to do a MakeCurrent, you should set this variable 90635c4bbdfSmrg * to your context's address, and you can skip MakeCurrent if it's 90735c4bbdfSmrg * already set to yours. 90835c4bbdfSmrg * 90935c4bbdfSmrg * When you're about to do a DestroyContext, you should set this to 91035c4bbdfSmrg * NULL if it's set to your context. 91135c4bbdfSmrg * 91235c4bbdfSmrg * When you're about to do an unbindContext on a DRI driver, you 91335c4bbdfSmrg * should set this to NULL. Despite the unbindContext interface 91435c4bbdfSmrg * sounding like it only unbinds the passed in context, it actually 91535c4bbdfSmrg * unconditionally clears the dispatch table even if the given 91635c4bbdfSmrg * context wasn't current. 91735c4bbdfSmrg */ 91835c4bbdfSmrgvoid *lastGLContext = NULL; 919