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