dixutils.c revision 35c4bbdf
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 {
36305b261ecSmrg    BlockHandlerProcPtr BlockHandler;
36405b261ecSmrg    WakeupHandlerProcPtr 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
38135c4bbdfSmrgBlockHandler(void *pTimeout, void *pReadmask)
38205b261ecSmrg{
38305b261ecSmrg    int i, j;
38435c4bbdfSmrg
38505b261ecSmrg    ++inHandler;
38605b261ecSmrg    for (i = 0; i < screenInfo.numScreens; i++)
38735c4bbdfSmrg        (*screenInfo.screens[i]->BlockHandler) (screenInfo.screens[i],
38835c4bbdfSmrg                                                pTimeout, pReadmask);
38935c4bbdfSmrg    for (i = 0; i < screenInfo.numGPUScreens; i++)
39035c4bbdfSmrg        (*screenInfo.gpuscreens[i]->BlockHandler) (screenInfo.gpuscreens[i],
39135c4bbdfSmrg                                                   pTimeout, pReadmask);
39205b261ecSmrg    for (i = 0; i < numHandlers; i++)
39335c4bbdfSmrg        if (!handlers[i].deleted)
39435c4bbdfSmrg            (*handlers[i].BlockHandler) (handlers[i].blockData,
39535c4bbdfSmrg                                         pTimeout, pReadmask);
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
41635c4bbdfSmrgWakeupHandler(int result, void *pReadmask)
41705b261ecSmrg{
41805b261ecSmrg    int i, j;
41905b261ecSmrg
42005b261ecSmrg    ++inHandler;
42105b261ecSmrg    for (i = numHandlers - 1; i >= 0; i--)
42235c4bbdfSmrg        if (!handlers[i].deleted)
42335c4bbdfSmrg            (*handlers[i].WakeupHandler) (handlers[i].blockData,
42435c4bbdfSmrg                                          result, pReadmask);
42505b261ecSmrg    for (i = 0; i < screenInfo.numScreens; i++)
42635c4bbdfSmrg        (*screenInfo.screens[i]->WakeupHandler) (screenInfo.screens[i],
42735c4bbdfSmrg                                                 result, pReadmask);
42835c4bbdfSmrg    for (i = 0; i < screenInfo.numGPUScreens; i++)
42935c4bbdfSmrg        (*screenInfo.gpuscreens[i]->WakeupHandler) (screenInfo.gpuscreens[i],
43035c4bbdfSmrg                                                    result, pReadmask);
43135c4bbdfSmrg    if (handlerDeleted) {
43235c4bbdfSmrg        for (i = 0; i < numHandlers;)
43335c4bbdfSmrg            if (handlers[i].deleted) {
43435c4bbdfSmrg                for (j = i; j < numHandlers - 1; j++)
43535c4bbdfSmrg                    handlers[j] = handlers[j + 1];
43635c4bbdfSmrg                numHandlers--;
43735c4bbdfSmrg            }
43835c4bbdfSmrg            else
43935c4bbdfSmrg                i++;
44035c4bbdfSmrg        handlerDeleted = FALSE;
44105b261ecSmrg    }
44205b261ecSmrg    --inHandler;
44305b261ecSmrg}
44405b261ecSmrg
44505b261ecSmrg/**
44605b261ecSmrg * Reentrant with BlockHandler and WakeupHandler, except wakeup won't
44705b261ecSmrg * get called until next time
44805b261ecSmrg */
4496747b715SmrgBool
45035c4bbdfSmrgRegisterBlockAndWakeupHandlers(BlockHandlerProcPtr blockHandler,
45135c4bbdfSmrg                               WakeupHandlerProcPtr wakeupHandler,
45235c4bbdfSmrg                               void *blockData)
45305b261ecSmrg{
45405b261ecSmrg    BlockHandlerPtr new;
45505b261ecSmrg
45635c4bbdfSmrg    if (numHandlers >= sizeHandlers) {
4576747b715Smrg        new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) *
45835c4bbdfSmrg                                        sizeof(BlockHandlerRec));
45935c4bbdfSmrg        if (!new)
46035c4bbdfSmrg            return FALSE;
46135c4bbdfSmrg        handlers = new;
46235c4bbdfSmrg        sizeHandlers = numHandlers + 1;
46305b261ecSmrg    }
46405b261ecSmrg    handlers[numHandlers].BlockHandler = blockHandler;
46505b261ecSmrg    handlers[numHandlers].WakeupHandler = wakeupHandler;
46605b261ecSmrg    handlers[numHandlers].blockData = blockData;
46705b261ecSmrg    handlers[numHandlers].deleted = FALSE;
46805b261ecSmrg    numHandlers = numHandlers + 1;
46905b261ecSmrg    return TRUE;
47005b261ecSmrg}
47105b261ecSmrg
4726747b715Smrgvoid
47335c4bbdfSmrgRemoveBlockAndWakeupHandlers(BlockHandlerProcPtr blockHandler,
47435c4bbdfSmrg                             WakeupHandlerProcPtr wakeupHandler,
47535c4bbdfSmrg                             void *blockData)
47605b261ecSmrg{
47735c4bbdfSmrg    int i;
47805b261ecSmrg
47905b261ecSmrg    for (i = 0; i < numHandlers; i++)
48035c4bbdfSmrg        if (handlers[i].BlockHandler == blockHandler &&
48135c4bbdfSmrg            handlers[i].WakeupHandler == wakeupHandler &&
48235c4bbdfSmrg            handlers[i].blockData == blockData) {
48335c4bbdfSmrg            if (inHandler) {
48435c4bbdfSmrg                handlerDeleted = TRUE;
48535c4bbdfSmrg                handlers[i].deleted = TRUE;
48635c4bbdfSmrg            }
48735c4bbdfSmrg            else {
48835c4bbdfSmrg                for (; i < numHandlers - 1; i++)
48935c4bbdfSmrg                    handlers[i] = handlers[i + 1];
49035c4bbdfSmrg                numHandlers--;
49135c4bbdfSmrg            }
49235c4bbdfSmrg            break;
49335c4bbdfSmrg        }
49405b261ecSmrg}
49505b261ecSmrg
49605b261ecSmrgvoid
49735c4bbdfSmrgInitBlockAndWakeupHandlers(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
51035c4bbdfSmrgWorkQueuePtr workQueue;
51135c4bbdfSmrgstatic WorkQueuePtr *workQueueLast = &workQueue;
51205b261ecSmrg
51305b261ecSmrgvoid
51405b261ecSmrgProcessWorkQueue(void)
51505b261ecSmrg{
51635c4bbdfSmrg    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     */
52535c4bbdfSmrg    while ((q = *p)) {
52635c4bbdfSmrg        if ((*q->function) (q->client, q->closure)) {
52735c4bbdfSmrg            /* remove q from the list */
52835c4bbdfSmrg            *p = q->next;       /* don't fetch until after func called */
52935c4bbdfSmrg            free(q);
53035c4bbdfSmrg        }
53135c4bbdfSmrg        else {
53235c4bbdfSmrg            p = &q->next;       /* don't fetch until after func called */
53335c4bbdfSmrg        }
53405b261ecSmrg    }
53505b261ecSmrg    workQueueLast = p;
53605b261ecSmrg}
53705b261ecSmrg
53805b261ecSmrgvoid
53905b261ecSmrgProcessWorkQueueZombies(void)
54005b261ecSmrg{
54135c4bbdfSmrg    WorkQueuePtr q, *p;
54205b261ecSmrg
54305b261ecSmrg    p = &workQueue;
54435c4bbdfSmrg    while ((q = *p)) {
54535c4bbdfSmrg        if (q->client && q->client->clientGone) {
54635c4bbdfSmrg            (void) (*q->function) (q->client, q->closure);
54735c4bbdfSmrg            /* remove q from the list */
54835c4bbdfSmrg            *p = q->next;       /* don't fetch until after func called */
54935c4bbdfSmrg            free(q);
55035c4bbdfSmrg        }
55135c4bbdfSmrg        else {
55235c4bbdfSmrg            p = &q->next;       /* don't fetch until after func called */
55335c4bbdfSmrg        }
55405b261ecSmrg    }
55505b261ecSmrg    workQueueLast = p;
55605b261ecSmrg}
55705b261ecSmrg
5586747b715SmrgBool
55935c4bbdfSmrgQueueWorkProc(Bool (*function) (ClientPtr pClient, void *closure),
56035c4bbdfSmrg              ClientPtr client, void *closure)
56105b261ecSmrg{
56235c4bbdfSmrg    WorkQueuePtr q;
56305b261ecSmrg
5646747b715Smrg    q = malloc(sizeof *q);
56505b261ecSmrg    if (!q)
56635c4bbdfSmrg        return FALSE;
56705b261ecSmrg    q->function = function;
56805b261ecSmrg    q->client = client;
56905b261ecSmrg    q->closure = closure;
57005b261ecSmrg    q->next = NULL;
57105b261ecSmrg    *workQueueLast = q;
57205b261ecSmrg    workQueueLast = &q->next;
57305b261ecSmrg    return TRUE;
57405b261ecSmrg}
57505b261ecSmrg
57605b261ecSmrg/*
57705b261ecSmrg * Manage a queue of sleeping clients, awakening them
57805b261ecSmrg * when requested, by using the OS functions IgnoreClient
57905b261ecSmrg * and AttendClient.  Note that this *ignores* the troubles
58005b261ecSmrg * with request data interleaving itself with events, but
58105b261ecSmrg * we'll leave that until a later time.
58205b261ecSmrg */
58305b261ecSmrg
58405b261ecSmrgtypedef struct _SleepQueue {
58535c4bbdfSmrg    struct _SleepQueue *next;
58635c4bbdfSmrg    ClientPtr client;
58735c4bbdfSmrg    ClientSleepProcPtr function;
58835c4bbdfSmrg    void *closure;
58905b261ecSmrg} SleepQueueRec, *SleepQueuePtr;
59005b261ecSmrg
59135c4bbdfSmrgstatic SleepQueuePtr sleepQueue = NULL;
59205b261ecSmrg
5936747b715SmrgBool
59435c4bbdfSmrgClientSleep(ClientPtr client, ClientSleepProcPtr function, void *closure)
59505b261ecSmrg{
59635c4bbdfSmrg    SleepQueuePtr q;
59705b261ecSmrg
5986747b715Smrg    q = malloc(sizeof *q);
59905b261ecSmrg    if (!q)
60035c4bbdfSmrg        return FALSE;
60105b261ecSmrg
60235c4bbdfSmrg    IgnoreClient(client);
60305b261ecSmrg    q->next = sleepQueue;
60405b261ecSmrg    q->client = client;
60505b261ecSmrg    q->function = function;
60605b261ecSmrg    q->closure = closure;
60705b261ecSmrg    sleepQueue = q;
60805b261ecSmrg    return TRUE;
60905b261ecSmrg}
61005b261ecSmrg
61105b261ecSmrgBool
61235c4bbdfSmrgClientSignal(ClientPtr client)
61305b261ecSmrg{
61435c4bbdfSmrg    SleepQueuePtr q;
61505b261ecSmrg
61605b261ecSmrg    for (q = sleepQueue; q; q = q->next)
61735c4bbdfSmrg        if (q->client == client) {
61835c4bbdfSmrg            return QueueWorkProc(q->function, q->client, q->closure);
61935c4bbdfSmrg        }
62005b261ecSmrg    return FALSE;
62105b261ecSmrg}
62205b261ecSmrg
62335c4bbdfSmrgint
62435c4bbdfSmrgClientSignalAll(ClientPtr client, ClientSleepProcPtr function, void *closure)
62535c4bbdfSmrg{
62635c4bbdfSmrg    SleepQueuePtr q;
62735c4bbdfSmrg    int count = 0;
62835c4bbdfSmrg
62935c4bbdfSmrg    for (q = sleepQueue; q; q = q->next) {
63035c4bbdfSmrg        if (!(client == CLIENT_SIGNAL_ANY || q->client == client))
63135c4bbdfSmrg            continue;
63235c4bbdfSmrg
63335c4bbdfSmrg        if (!(function == CLIENT_SIGNAL_ANY || q->function == function))
63435c4bbdfSmrg            continue;
63535c4bbdfSmrg
63635c4bbdfSmrg        if (!(closure == CLIENT_SIGNAL_ANY || q->closure == closure))
63735c4bbdfSmrg            continue;
63835c4bbdfSmrg
63935c4bbdfSmrg        count += QueueWorkProc(q->function, q->client, q->closure);
64035c4bbdfSmrg    }
64135c4bbdfSmrg
64235c4bbdfSmrg    return count;
64335c4bbdfSmrg}
64435c4bbdfSmrg
6456747b715Smrgvoid
64635c4bbdfSmrgClientWakeup(ClientPtr client)
64705b261ecSmrg{
64835c4bbdfSmrg    SleepQueuePtr q, *prev;
64905b261ecSmrg
65005b261ecSmrg    prev = &sleepQueue;
65135c4bbdfSmrg    while ((q = *prev)) {
65235c4bbdfSmrg        if (q->client == client) {
65335c4bbdfSmrg            *prev = q->next;
65435c4bbdfSmrg            free(q);
65535c4bbdfSmrg            if (client->clientGone)
65635c4bbdfSmrg                /* Oops -- new zombie cleanup code ensures this only
65735c4bbdfSmrg                 * happens from inside CloseDownClient; don't want to
65835c4bbdfSmrg                 * recurse here...
65935c4bbdfSmrg                 */
66035c4bbdfSmrg                /* CloseDownClient(client) */ ;
66135c4bbdfSmrg            else
66235c4bbdfSmrg                AttendClient(client);
66335c4bbdfSmrg            break;
66435c4bbdfSmrg        }
66535c4bbdfSmrg        prev = &q->next;
66605b261ecSmrg    }
66705b261ecSmrg}
66805b261ecSmrg
66905b261ecSmrgBool
67035c4bbdfSmrgClientIsAsleep(ClientPtr client)
67105b261ecSmrg{
67235c4bbdfSmrg    SleepQueuePtr q;
67305b261ecSmrg
67405b261ecSmrg    for (q = sleepQueue; q; q = q->next)
67535c4bbdfSmrg        if (q->client == client)
67635c4bbdfSmrg            return TRUE;
67705b261ecSmrg    return FALSE;
67805b261ecSmrg}
67905b261ecSmrg
68005b261ecSmrg/*
68105b261ecSmrg *  Generic Callback Manager
68205b261ecSmrg */
68305b261ecSmrg
68405b261ecSmrg/* ===== Private Procedures ===== */
68505b261ecSmrg
68605b261ecSmrgstatic int numCallbackListsToCleanup = 0;
68705b261ecSmrgstatic CallbackListPtr **listsToCleanup = NULL;
68805b261ecSmrg
6896747b715Smrgstatic Bool
69035c4bbdfSmrg_AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
69105b261ecSmrg{
69235c4bbdfSmrg    CallbackPtr cbr;
69305b261ecSmrg
6946747b715Smrg    cbr = malloc(sizeof(CallbackRec));
69505b261ecSmrg    if (!cbr)
69635c4bbdfSmrg        return FALSE;
69705b261ecSmrg    cbr->proc = callback;
69805b261ecSmrg    cbr->data = data;
69905b261ecSmrg    cbr->next = (*pcbl)->list;
70005b261ecSmrg    cbr->deleted = FALSE;
70105b261ecSmrg    (*pcbl)->list = cbr;
70205b261ecSmrg    return TRUE;
70305b261ecSmrg}
70405b261ecSmrg
70535c4bbdfSmrgstatic Bool
70635c4bbdfSmrg_DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
70705b261ecSmrg{
70805b261ecSmrg    CallbackListPtr cbl = *pcbl;
70935c4bbdfSmrg    CallbackPtr cbr, pcbr;
71035c4bbdfSmrg
71135c4bbdfSmrg    for (pcbr = NULL, cbr = cbl->list; cbr != NULL; pcbr = cbr, cbr = cbr->next) {
71235c4bbdfSmrg        if ((cbr->proc == callback) && (cbr->data == data))
71335c4bbdfSmrg            break;
71405b261ecSmrg    }
71535c4bbdfSmrg    if (cbr != NULL) {
71635c4bbdfSmrg        if (cbl->inCallback) {
71735c4bbdfSmrg            ++(cbl->numDeleted);
71835c4bbdfSmrg            cbr->deleted = TRUE;
71935c4bbdfSmrg        }
72035c4bbdfSmrg        else {
72135c4bbdfSmrg            if (pcbr == NULL)
72235c4bbdfSmrg                cbl->list = cbr->next;
72335c4bbdfSmrg            else
72435c4bbdfSmrg                pcbr->next = cbr->next;
72535c4bbdfSmrg            free(cbr);
72635c4bbdfSmrg        }
72735c4bbdfSmrg        return TRUE;
72805b261ecSmrg    }
72905b261ecSmrg    return FALSE;
73005b261ecSmrg}
73105b261ecSmrg
73235c4bbdfSmrgvoid
73335c4bbdfSmrg_CallCallbacks(CallbackListPtr *pcbl, void *call_data)
73405b261ecSmrg{
73505b261ecSmrg    CallbackListPtr cbl = *pcbl;
73635c4bbdfSmrg    CallbackPtr cbr, pcbr;
73705b261ecSmrg
73805b261ecSmrg    ++(cbl->inCallback);
73935c4bbdfSmrg    for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) {
74035c4bbdfSmrg        (*(cbr->proc)) (pcbl, cbr->data, call_data);
74105b261ecSmrg    }
74205b261ecSmrg    --(cbl->inCallback);
74305b261ecSmrg
74435c4bbdfSmrg    if (cbl->inCallback)
74535c4bbdfSmrg        return;
74605b261ecSmrg
74705b261ecSmrg    /* Was the entire list marked for deletion? */
74805b261ecSmrg
74935c4bbdfSmrg    if (cbl->deleted) {
75035c4bbdfSmrg        DeleteCallbackList(pcbl);
75135c4bbdfSmrg        return;
75205b261ecSmrg    }
75305b261ecSmrg
75405b261ecSmrg    /* Were some individual callbacks on the list marked for deletion?
75505b261ecSmrg     * If so, do the deletions.
75605b261ecSmrg     */
75705b261ecSmrg
75835c4bbdfSmrg    if (cbl->numDeleted) {
75935c4bbdfSmrg        for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted;) {
76035c4bbdfSmrg            if (cbr->deleted) {
76135c4bbdfSmrg                if (pcbr) {
76235c4bbdfSmrg                    cbr = cbr->next;
76335c4bbdfSmrg                    free(pcbr->next);
76435c4bbdfSmrg                    pcbr->next = cbr;
76535c4bbdfSmrg                }
76635c4bbdfSmrg                else {
76735c4bbdfSmrg                    cbr = cbr->next;
76835c4bbdfSmrg                    free(cbl->list);
76935c4bbdfSmrg                    cbl->list = cbr;
77035c4bbdfSmrg                }
77135c4bbdfSmrg                cbl->numDeleted--;
77235c4bbdfSmrg            }
77335c4bbdfSmrg            else {              /* this one wasn't deleted */
77435c4bbdfSmrg
77535c4bbdfSmrg                pcbr = cbr;
77635c4bbdfSmrg                cbr = cbr->next;
77735c4bbdfSmrg            }
77835c4bbdfSmrg        }
77905b261ecSmrg    }
78005b261ecSmrg}
78105b261ecSmrg
78205b261ecSmrgstatic void
78335c4bbdfSmrg_DeleteCallbackList(CallbackListPtr *pcbl)
78405b261ecSmrg{
78505b261ecSmrg    CallbackListPtr cbl = *pcbl;
78635c4bbdfSmrg    CallbackPtr cbr, nextcbr;
78705b261ecSmrg    int i;
78805b261ecSmrg
78935c4bbdfSmrg    if (cbl->inCallback) {
79035c4bbdfSmrg        cbl->deleted = TRUE;
79135c4bbdfSmrg        return;
79205b261ecSmrg    }
79305b261ecSmrg
79435c4bbdfSmrg    for (i = 0; i < numCallbackListsToCleanup; i++) {
79535c4bbdfSmrg        if (listsToCleanup[i] == pcbl) {
79635c4bbdfSmrg            listsToCleanup[i] = NULL;
79735c4bbdfSmrg            break;
79835c4bbdfSmrg        }
79905b261ecSmrg    }
80005b261ecSmrg
80135c4bbdfSmrg    for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) {
80235c4bbdfSmrg        nextcbr = cbr->next;
80335c4bbdfSmrg        free(cbr);
80405b261ecSmrg    }
8056747b715Smrg    free(cbl);
80605b261ecSmrg    *pcbl = NULL;
80705b261ecSmrg}
80805b261ecSmrg
80905b261ecSmrgstatic Bool
8104642e01fSmrgCreateCallbackList(CallbackListPtr *pcbl)
81105b261ecSmrg{
81235c4bbdfSmrg    CallbackListPtr cbl;
81305b261ecSmrg    int i;
81405b261ecSmrg
81535c4bbdfSmrg    if (!pcbl)
81635c4bbdfSmrg        return FALSE;
8176747b715Smrg    cbl = malloc(sizeof(CallbackListRec));
81835c4bbdfSmrg    if (!cbl)
81935c4bbdfSmrg        return FALSE;
82005b261ecSmrg    cbl->inCallback = 0;
82105b261ecSmrg    cbl->deleted = FALSE;
82205b261ecSmrg    cbl->numDeleted = 0;
82305b261ecSmrg    cbl->list = NULL;
82405b261ecSmrg    *pcbl = cbl;
82505b261ecSmrg
82635c4bbdfSmrg    for (i = 0; i < numCallbackListsToCleanup; i++) {
82735c4bbdfSmrg        if (!listsToCleanup[i]) {
82835c4bbdfSmrg            listsToCleanup[i] = pcbl;
82935c4bbdfSmrg            return TRUE;
83035c4bbdfSmrg        }
83105b261ecSmrg    }
83205b261ecSmrg
83335c4bbdfSmrg    listsToCleanup = (CallbackListPtr **) xnfrealloc(listsToCleanup,
83435c4bbdfSmrg                                                     sizeof(CallbackListPtr *) *
83535c4bbdfSmrg                                                     (numCallbackListsToCleanup
83635c4bbdfSmrg                                                      + 1));
83705b261ecSmrg    listsToCleanup[numCallbackListsToCleanup] = pcbl;
83805b261ecSmrg    numCallbackListsToCleanup++;
83905b261ecSmrg    return TRUE;
84005b261ecSmrg}
84105b261ecSmrg
84205b261ecSmrg/* ===== Public Procedures ===== */
84305b261ecSmrg
8446747b715SmrgBool
84535c4bbdfSmrgAddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
84605b261ecSmrg{
84735c4bbdfSmrg    if (!pcbl)
84835c4bbdfSmrg        return FALSE;
84935c4bbdfSmrg    if (!*pcbl) {               /* list hasn't been created yet; go create it */
85035c4bbdfSmrg        if (!CreateCallbackList(pcbl))
85135c4bbdfSmrg            return FALSE;
85205b261ecSmrg    }
8534642e01fSmrg    return _AddCallback(pcbl, callback, data);
85405b261ecSmrg}
85505b261ecSmrg
8566747b715SmrgBool
85735c4bbdfSmrgDeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
85805b261ecSmrg{
85935c4bbdfSmrg    if (!pcbl || !*pcbl)
86035c4bbdfSmrg        return FALSE;
8614642e01fSmrg    return _DeleteCallback(pcbl, callback, data);
86205b261ecSmrg}
86305b261ecSmrg
86405b261ecSmrgvoid
86505b261ecSmrgDeleteCallbackList(CallbackListPtr *pcbl)
86605b261ecSmrg{
86735c4bbdfSmrg    if (!pcbl || !*pcbl)
86835c4bbdfSmrg        return;
8694642e01fSmrg    _DeleteCallbackList(pcbl);
87005b261ecSmrg}
87105b261ecSmrg
8726747b715Smrgvoid
87335c4bbdfSmrgDeleteCallbackManager(void)
87405b261ecSmrg{
87505b261ecSmrg    int i;
87605b261ecSmrg
87735c4bbdfSmrg    for (i = 0; i < numCallbackListsToCleanup; i++) {
87835c4bbdfSmrg        DeleteCallbackList(listsToCleanup[i]);
87905b261ecSmrg    }
8806747b715Smrg    free(listsToCleanup);
88105b261ecSmrg
88205b261ecSmrg    numCallbackListsToCleanup = 0;
88305b261ecSmrg    listsToCleanup = NULL;
88405b261ecSmrg}
88535c4bbdfSmrg
88635c4bbdfSmrgvoid
88735c4bbdfSmrgInitCallbackManager(void)
88835c4bbdfSmrg{
88935c4bbdfSmrg    DeleteCallbackManager();
89035c4bbdfSmrg}
89135c4bbdfSmrg
89235c4bbdfSmrg/**
89335c4bbdfSmrg * Coordinates the global GL context used by modules in the X Server
89435c4bbdfSmrg * doing rendering with OpenGL.
89535c4bbdfSmrg *
89635c4bbdfSmrg * When setting a GL context (glXMakeCurrent() or eglMakeCurrent()),
89735c4bbdfSmrg * there is an expensive implied glFlush() required by the GLX and EGL
89835c4bbdfSmrg * APIs, so modules don't want to have to do it on every request.  But
89935c4bbdfSmrg * the individual modules using GL also don't know about each other,
90035c4bbdfSmrg * so they have to coordinate who owns the current context.
90135c4bbdfSmrg *
90235c4bbdfSmrg * When you're about to do a MakeCurrent, you should set this variable
90335c4bbdfSmrg * to your context's address, and you can skip MakeCurrent if it's
90435c4bbdfSmrg * already set to yours.
90535c4bbdfSmrg *
90635c4bbdfSmrg * When you're about to do a DestroyContext, you should set this to
90735c4bbdfSmrg * NULL if it's set to your context.
90835c4bbdfSmrg *
90935c4bbdfSmrg * When you're about to do an unbindContext on a DRI driver, you
91035c4bbdfSmrg * should set this to NULL.  Despite the unbindContext interface
91135c4bbdfSmrg * sounding like it only unbinds the passed in context, it actually
91235c4bbdfSmrg * unconditionally clears the dispatch table even if the given
91335c4bbdfSmrg * context wasn't current.
91435c4bbdfSmrg */
91535c4bbdfSmrgvoid *lastGLContext = NULL;
916