dixutils.c revision 05b261ec
105b261ecSmrg/***********************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrg
2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2705b261ecSmrg
2805b261ecSmrg                        All Rights Reserved
2905b261ecSmrg
3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3205b261ecSmrgprovided that the above copyright notice appear in all copies and that
3305b261ecSmrgboth that copyright notice and this permission notice appear in
3405b261ecSmrgsupporting documentation, and that the name of Digital not be
3505b261ecSmrgused in advertising or publicity pertaining to distribution of the
3605b261ecSmrgsoftware without specific, written prior permission.
3705b261ecSmrg
3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4405b261ecSmrgSOFTWARE.
4505b261ecSmrg
4605b261ecSmrg******************************************************************/
4705b261ecSmrg
4805b261ecSmrg/*
4905b261ecSmrg
5005b261ecSmrg(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved.
5105b261ecSmrg
5205b261ecSmrgPermission to use, copy, modify, distribute, and sublicense this software and its
5305b261ecSmrgdocumentation for any purpose and without fee is hereby granted, provided that
5405b261ecSmrgthe above copyright notices appear in all copies and that both those copyright
5505b261ecSmrgnotices and this permission notice appear in supporting documentation and that
5605b261ecSmrgthe name of Adobe Systems Incorporated not be used in advertising or publicity
5705b261ecSmrgpertaining to distribution of the software without specific, written prior
5805b261ecSmrgpermission.  No trademark license to use the Adobe trademarks is hereby
5905b261ecSmrggranted.  If the Adobe trademark "Display PostScript"(tm) is used to describe
6005b261ecSmrgthis software, its functionality or for any other purpose, such use shall be
6105b261ecSmrglimited to a statement that this software works in conjunction with the Display
6205b261ecSmrgPostScript system.  Proper trademark attribution to reflect Adobe's ownership
6305b261ecSmrgof the trademark shall be given whenever any such reference to the Display
6405b261ecSmrgPostScript system is made.
6505b261ecSmrg
6605b261ecSmrgADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY
6705b261ecSmrgPURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.  ADOBE
6805b261ecSmrgDISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
6905b261ecSmrgWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
7005b261ecSmrgINFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO EVENT SHALL ADOBE BE LIABLE TO YOU
7105b261ecSmrgOR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
7205b261ecSmrgDAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT
7305b261ecSmrgLIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR
7405b261ecSmrgPERFORMANCE OF THIS SOFTWARE.  ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER
7505b261ecSmrgSUPPORT FOR THE SOFTWARE.
7605b261ecSmrg
7705b261ecSmrgAdobe, PostScript, and Display PostScript are trademarks of Adobe Systems
7805b261ecSmrgIncorporated which may be registered in certain jurisdictions.
7905b261ecSmrg
8005b261ecSmrgAuthor:  Adobe Systems Incorporated
8105b261ecSmrg
8205b261ecSmrg*/
8305b261ecSmrg
8405b261ecSmrg
8505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
8605b261ecSmrg#include <dix-config.h>
8705b261ecSmrg#endif
8805b261ecSmrg
8905b261ecSmrg#include <X11/X.h>
9005b261ecSmrg#include <X11/Xmd.h>
9105b261ecSmrg#include "misc.h"
9205b261ecSmrg#include "windowstr.h"
9305b261ecSmrg#include "dixstruct.h"
9405b261ecSmrg#include "pixmapstr.h"
9505b261ecSmrg#include "scrnintstr.h"
9605b261ecSmrg#define  XK_LATIN1
9705b261ecSmrg#include <X11/keysymdef.h>
9805b261ecSmrg#include "xace.h"
9905b261ecSmrg
10005b261ecSmrg/*
10105b261ecSmrg * CompareTimeStamps returns -1, 0, or +1 depending on if the first
10205b261ecSmrg * argument is less than, equal to or greater than the second argument.
10305b261ecSmrg */
10405b261ecSmrg
10505b261ecSmrg_X_EXPORT int
10605b261ecSmrgCompareTimeStamps(TimeStamp a, TimeStamp b)
10705b261ecSmrg{
10805b261ecSmrg    if (a.months < b.months)
10905b261ecSmrg	return EARLIER;
11005b261ecSmrg    if (a.months > b.months)
11105b261ecSmrg	return LATER;
11205b261ecSmrg    if (a.milliseconds < b.milliseconds)
11305b261ecSmrg	return EARLIER;
11405b261ecSmrg    if (a.milliseconds > b.milliseconds)
11505b261ecSmrg	return LATER;
11605b261ecSmrg    return SAMETIME;
11705b261ecSmrg}
11805b261ecSmrg
11905b261ecSmrg/*
12005b261ecSmrg * convert client times to server TimeStamps
12105b261ecSmrg */
12205b261ecSmrg
12305b261ecSmrg#define HALFMONTH ((unsigned long) 1<<31)
12405b261ecSmrg_X_EXPORT TimeStamp
12505b261ecSmrgClientTimeToServerTime(CARD32 c)
12605b261ecSmrg{
12705b261ecSmrg    TimeStamp ts;
12805b261ecSmrg    if (c == CurrentTime)
12905b261ecSmrg	return currentTime;
13005b261ecSmrg    ts.months = currentTime.months;
13105b261ecSmrg    ts.milliseconds = c;
13205b261ecSmrg    if (c > currentTime.milliseconds)
13305b261ecSmrg    {
13405b261ecSmrg	if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH)
13505b261ecSmrg	    ts.months -= 1;
13605b261ecSmrg    }
13705b261ecSmrg    else if (c < currentTime.milliseconds)
13805b261ecSmrg    {
13905b261ecSmrg	if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH)
14005b261ecSmrg	    ts.months += 1;
14105b261ecSmrg    }
14205b261ecSmrg    return ts;
14305b261ecSmrg}
14405b261ecSmrg
14505b261ecSmrg/*
14605b261ecSmrg * ISO Latin-1 case conversion routine
14705b261ecSmrg *
14805b261ecSmrg * this routine always null-terminates the result, so
14905b261ecSmrg * beware of too-small buffers
15005b261ecSmrg */
15105b261ecSmrg
15205b261ecSmrgstatic unsigned char
15305b261ecSmrgISOLatin1ToLower (unsigned char source)
15405b261ecSmrg{
15505b261ecSmrg    unsigned char   dest;
15605b261ecSmrg    if ((source >= XK_A) && (source <= XK_Z))
15705b261ecSmrg       dest = source + (XK_a - XK_A);
15805b261ecSmrg    else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis))
15905b261ecSmrg       dest = source + (XK_agrave - XK_Agrave);
16005b261ecSmrg    else if ((source >= XK_Ooblique) && (source <= XK_Thorn))
16105b261ecSmrg       dest = source + (XK_oslash - XK_Ooblique);
16205b261ecSmrg    else
16305b261ecSmrg       dest = source;
16405b261ecSmrg    return dest;
16505b261ecSmrg}
16605b261ecSmrg
16705b261ecSmrg
16805b261ecSmrg_X_EXPORT void
16905b261ecSmrgCopyISOLatin1Lowered(unsigned char *dest, unsigned char *source, int length)
17005b261ecSmrg{
17105b261ecSmrg    int i;
17205b261ecSmrg
17305b261ecSmrg    for (i = 0; i < length; i++, source++, dest++)
17405b261ecSmrg	*dest = ISOLatin1ToLower (*source);
17505b261ecSmrg    *dest = '\0';
17605b261ecSmrg}
17705b261ecSmrg
17805b261ecSmrgint
17905b261ecSmrgCompareISOLatin1Lowered(unsigned char *s1, int s1len,
18005b261ecSmrg			unsigned char *s2, int s2len)
18105b261ecSmrg{
18205b261ecSmrg    unsigned char   c1, c2;
18305b261ecSmrg
18405b261ecSmrg    for (;;)
18505b261ecSmrg    {
18605b261ecSmrg	/* note -- compare against zero so that -1 ignores len */
18705b261ecSmrg	c1 = s1len-- ? *s1++ : '\0';
18805b261ecSmrg	c2 = s2len-- ? *s2++ : '\0';
18905b261ecSmrg	if (!c1 ||
19005b261ecSmrg	    (c1 != c2 &&
19105b261ecSmrg	     (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2))))
19205b261ecSmrg	    break;
19305b261ecSmrg    }
19405b261ecSmrg    return (int) c1 - (int) c2;
19505b261ecSmrg}
19605b261ecSmrg
19705b261ecSmrg/*
19805b261ecSmrg * dixLookupWindow and dixLookupDrawable:
19905b261ecSmrg * Look up the window/drawable taking into account the client doing the
20005b261ecSmrg * lookup, the type of drawable desired, and the type of access desired.
20105b261ecSmrg * Return Success with *pDraw set if the window/drawable exists and the client
20205b261ecSmrg * is allowed access, else return an error code with *pDraw set to NULL.  The
20305b261ecSmrg * access mask values are defined in resource.h.  The type mask values are
20405b261ecSmrg * defined in pixmap.h, with zero equivalent to M_DRAWABLE.
20505b261ecSmrg */
20605b261ecSmrg_X_EXPORT int
20705b261ecSmrgdixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client,
20805b261ecSmrg		  Mask type, Mask access)
20905b261ecSmrg{
21005b261ecSmrg    DrawablePtr pTmp;
21105b261ecSmrg    RESTYPE rtype;
21205b261ecSmrg    *pDraw = NULL;
21305b261ecSmrg    client->errorValue = id;
21405b261ecSmrg
21505b261ecSmrg    if (id == INVALID)
21605b261ecSmrg	return BadDrawable;
21705b261ecSmrg
21805b261ecSmrg    if (id == client->lastDrawableID) {
21905b261ecSmrg	pTmp = client->lastDrawable;
22005b261ecSmrg
22105b261ecSmrg	/* an access check is required for cached drawables */
22205b261ecSmrg	rtype = (type & M_WINDOW) ? RT_WINDOW : RT_PIXMAP;
22305b261ecSmrg	if (!XaceHook(XACE_RESOURCE_ACCESS, client, id, rtype, access, pTmp))
22405b261ecSmrg	    return BadDrawable;
22505b261ecSmrg    } else
22605b261ecSmrg	pTmp = (DrawablePtr)SecurityLookupIDByClass(client, id, RC_DRAWABLE,
22705b261ecSmrg						   access);
22805b261ecSmrg    if (!pTmp)
22905b261ecSmrg	return BadDrawable;
23005b261ecSmrg    if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE)))
23105b261ecSmrg	return BadMatch;
23205b261ecSmrg
23305b261ecSmrg    if (type & M_DRAWABLE) {
23405b261ecSmrg	client->lastDrawable = pTmp;
23505b261ecSmrg	client->lastDrawableID = id;
23605b261ecSmrg	client->lastGCID = INVALID;
23705b261ecSmrg	client->lastGC = (GCPtr)NULL;
23805b261ecSmrg    }
23905b261ecSmrg    *pDraw = pTmp;
24005b261ecSmrg    return Success;
24105b261ecSmrg}
24205b261ecSmrg
24305b261ecSmrg_X_EXPORT int
24405b261ecSmrgdixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
24505b261ecSmrg{
24605b261ecSmrg    int rc;
24705b261ecSmrg    rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access);
24805b261ecSmrg    return (rc == BadDrawable) ? BadWindow : rc;
24905b261ecSmrg}
25005b261ecSmrg
25105b261ecSmrg_X_EXPORT int
25205b261ecSmrgdixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access)
25305b261ecSmrg{
25405b261ecSmrg    GCPtr pTmp = (GCPtr)SecurityLookupIDByType(client, id, RT_GC, access);
25505b261ecSmrg    if (pTmp) {
25605b261ecSmrg	*pGC = pTmp;
25705b261ecSmrg	return Success;
25805b261ecSmrg    }
25905b261ecSmrg    client->errorValue = id;
26005b261ecSmrg    *pGC = NULL;
26105b261ecSmrg    return BadGC;
26205b261ecSmrg}
26305b261ecSmrg
26405b261ecSmrg_X_EXPORT int
26505b261ecSmrgdixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access)
26605b261ecSmrg{
26705b261ecSmrg    pointer pRes = (pointer)SecurityLookupIDByClass(client, rid, RC_ANY,
26805b261ecSmrg						    access);
26905b261ecSmrg    int clientIndex = CLIENT_ID(rid);
27005b261ecSmrg    client->errorValue = rid;
27105b261ecSmrg
27205b261ecSmrg    if (clientIndex && pRes && clients[clientIndex] && !(rid & SERVER_BIT)) {
27305b261ecSmrg	*pClient = clients[clientIndex];
27405b261ecSmrg	return Success;
27505b261ecSmrg    }
27605b261ecSmrg    *pClient = NULL;
27705b261ecSmrg    return BadValue;
27805b261ecSmrg}
27905b261ecSmrg
28005b261ecSmrg/*
28105b261ecSmrg * These are deprecated compatibility functions and will be removed soon!
28205b261ecSmrg * Please use the new dixLookup*() functions above.
28305b261ecSmrg */
28405b261ecSmrg_X_EXPORT _X_DEPRECATED WindowPtr
28505b261ecSmrgSecurityLookupWindow(XID id, ClientPtr client, Mask access_mode)
28605b261ecSmrg{
28705b261ecSmrg    WindowPtr pWin;
28805b261ecSmrg    int i = dixLookupWindow(&pWin, id, client, access_mode);
28905b261ecSmrg    static int warn = 1;
29005b261ecSmrg    if (warn-- > 0)
29105b261ecSmrg	ErrorF("Warning: LookupWindow()/SecurityLookupWindow() "
29205b261ecSmrg	       "are deprecated.  Please convert your driver/module "
29305b261ecSmrg	       "to use dixLookupWindow().\n");
29405b261ecSmrg    return (i == Success) ? pWin : NULL;
29505b261ecSmrg}
29605b261ecSmrg
29705b261ecSmrg_X_EXPORT _X_DEPRECATED WindowPtr
29805b261ecSmrgLookupWindow(XID id, ClientPtr client)
29905b261ecSmrg{
30005b261ecSmrg    return SecurityLookupWindow(id, client, DixUnknownAccess);
30105b261ecSmrg}
30205b261ecSmrg
30305b261ecSmrg_X_EXPORT _X_DEPRECATED pointer
30405b261ecSmrgSecurityLookupDrawable(XID id, ClientPtr client, Mask access_mode)
30505b261ecSmrg{
30605b261ecSmrg    DrawablePtr pDraw;
30705b261ecSmrg    int i = dixLookupDrawable(&pDraw, id, client, M_DRAWABLE, access_mode);
30805b261ecSmrg    static int warn = 1;
30905b261ecSmrg    if (warn-- > 0)
31005b261ecSmrg	ErrorF("Warning: LookupDrawable()/SecurityLookupDrawable() "
31105b261ecSmrg	       "are deprecated.  Please convert your driver/module "
31205b261ecSmrg	       "to use dixLookupDrawable().\n");
31305b261ecSmrg    return (i == Success) ? pDraw : NULL;
31405b261ecSmrg}
31505b261ecSmrg
31605b261ecSmrg_X_EXPORT _X_DEPRECATED pointer
31705b261ecSmrgLookupDrawable(XID id, ClientPtr client)
31805b261ecSmrg{
31905b261ecSmrg    return SecurityLookupDrawable(id, client, DixUnknownAccess);
32005b261ecSmrg}
32105b261ecSmrg
32205b261ecSmrg_X_EXPORT _X_DEPRECATED ClientPtr
32305b261ecSmrgLookupClient(XID id, ClientPtr client)
32405b261ecSmrg{
32505b261ecSmrg    ClientPtr pClient;
32605b261ecSmrg    int i = dixLookupClient(&pClient, id, client, DixUnknownAccess);
32705b261ecSmrg    static int warn = 1;
32805b261ecSmrg    if (warn-- > 0)
32905b261ecSmrg	ErrorF("Warning: LookupClient() is deprecated.  Please convert your "
33005b261ecSmrg	       "driver/module to use dixLookupClient().\n");
33105b261ecSmrg    return (i == Success) ? pClient : NULL;
33205b261ecSmrg}
33305b261ecSmrg
33405b261ecSmrg/* end deprecated functions */
33505b261ecSmrg
33605b261ecSmrgint
33705b261ecSmrgAlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode,
33805b261ecSmrg                      Bool toRoot, Bool remap)
33905b261ecSmrg{
34005b261ecSmrg    int numnow;
34105b261ecSmrg    SaveSetElt *pTmp = NULL;
34205b261ecSmrg    int j;
34305b261ecSmrg
34405b261ecSmrg    numnow = client->numSaved;
34505b261ecSmrg    j = 0;
34605b261ecSmrg    if (numnow)
34705b261ecSmrg    {
34805b261ecSmrg	pTmp = client->saveSet;
34905b261ecSmrg	while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin))
35005b261ecSmrg	    j++;
35105b261ecSmrg    }
35205b261ecSmrg    if (mode == SetModeInsert)
35305b261ecSmrg    {
35405b261ecSmrg	if (j < numnow)         /* duplicate */
35505b261ecSmrg	   return(Success);
35605b261ecSmrg	numnow++;
35705b261ecSmrg	pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow);
35805b261ecSmrg	if (!pTmp)
35905b261ecSmrg	    return(BadAlloc);
36005b261ecSmrg	client->saveSet = pTmp;
36105b261ecSmrg       	client->numSaved = numnow;
36205b261ecSmrg	SaveSetAssignWindow(client->saveSet[numnow - 1], pWin);
36305b261ecSmrg	SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot);
36405b261ecSmrg	SaveSetAssignRemap(client->saveSet[numnow - 1], remap);
36505b261ecSmrg	return(Success);
36605b261ecSmrg    }
36705b261ecSmrg    else if ((mode == SetModeDelete) && (j < numnow))
36805b261ecSmrg    {
36905b261ecSmrg	while (j < numnow-1)
37005b261ecSmrg	{
37105b261ecSmrg           pTmp[j] = pTmp[j+1];
37205b261ecSmrg	   j++;
37305b261ecSmrg	}
37405b261ecSmrg	numnow--;
37505b261ecSmrg        if (numnow)
37605b261ecSmrg	{
37705b261ecSmrg	    pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow);
37805b261ecSmrg	    if (pTmp)
37905b261ecSmrg		client->saveSet = pTmp;
38005b261ecSmrg	}
38105b261ecSmrg        else
38205b261ecSmrg        {
38305b261ecSmrg            xfree(client->saveSet);
38405b261ecSmrg	    client->saveSet = (SaveSetElt *)NULL;
38505b261ecSmrg	}
38605b261ecSmrg	client->numSaved = numnow;
38705b261ecSmrg	return(Success);
38805b261ecSmrg    }
38905b261ecSmrg    return(Success);
39005b261ecSmrg}
39105b261ecSmrg
39205b261ecSmrgvoid
39305b261ecSmrgDeleteWindowFromAnySaveSet(WindowPtr pWin)
39405b261ecSmrg{
39505b261ecSmrg    int i;
39605b261ecSmrg    ClientPtr client;
39705b261ecSmrg
39805b261ecSmrg    for (i = 0; i< currentMaxClients; i++)
39905b261ecSmrg    {
40005b261ecSmrg	client = clients[i];
40105b261ecSmrg	if (client && client->numSaved)
40205b261ecSmrg	    (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE);
40305b261ecSmrg    }
40405b261ecSmrg}
40505b261ecSmrg
40605b261ecSmrg/* No-op Don't Do Anything : sometimes we need to be able to call a procedure
40705b261ecSmrg * that doesn't do anything.  For example, on screen with only static
40805b261ecSmrg * colormaps, if someone calls install colormap, it's easier to have a dummy
40905b261ecSmrg * procedure to call than to check if there's a procedure
41005b261ecSmrg */
41105b261ecSmrg_X_EXPORT void
41205b261ecSmrgNoopDDA(void)
41305b261ecSmrg{
41405b261ecSmrg}
41505b261ecSmrg
41605b261ecSmrgtypedef struct _BlockHandler {
41705b261ecSmrg    BlockHandlerProcPtr BlockHandler;
41805b261ecSmrg    WakeupHandlerProcPtr WakeupHandler;
41905b261ecSmrg    pointer blockData;
42005b261ecSmrg    Bool    deleted;
42105b261ecSmrg} BlockHandlerRec, *BlockHandlerPtr;
42205b261ecSmrg
42305b261ecSmrgstatic BlockHandlerPtr	handlers;
42405b261ecSmrgstatic int		numHandlers;
42505b261ecSmrgstatic int		sizeHandlers;
42605b261ecSmrgstatic Bool		inHandler;
42705b261ecSmrgstatic Bool		handlerDeleted;
42805b261ecSmrg
42905b261ecSmrg/**
43005b261ecSmrg *
43105b261ecSmrg *  \param pTimeout   DIX doesn't want to know how OS represents time
43205b261ecSmrg *  \param pReadMask  nor how it represents the det of descriptors
43305b261ecSmrg */
43405b261ecSmrgvoid
43505b261ecSmrgBlockHandler(pointer pTimeout, pointer pReadmask)
43605b261ecSmrg{
43705b261ecSmrg    int i, j;
43805b261ecSmrg
43905b261ecSmrg    ++inHandler;
44005b261ecSmrg    for (i = 0; i < screenInfo.numScreens; i++)
44105b261ecSmrg	(* screenInfo.screens[i]->BlockHandler)(i,
44205b261ecSmrg				screenInfo.screens[i]->blockData,
44305b261ecSmrg				pTimeout, pReadmask);
44405b261ecSmrg    for (i = 0; i < numHandlers; i++)
44505b261ecSmrg	(*handlers[i].BlockHandler) (handlers[i].blockData,
44605b261ecSmrg				     pTimeout, pReadmask);
44705b261ecSmrg    if (handlerDeleted)
44805b261ecSmrg    {
44905b261ecSmrg	for (i = 0; i < numHandlers;)
45005b261ecSmrg	    if (handlers[i].deleted)
45105b261ecSmrg	    {
45205b261ecSmrg	    	for (j = i; j < numHandlers - 1; j++)
45305b261ecSmrg		    handlers[j] = handlers[j+1];
45405b261ecSmrg	    	numHandlers--;
45505b261ecSmrg	    }
45605b261ecSmrg	    else
45705b261ecSmrg		i++;
45805b261ecSmrg	handlerDeleted = FALSE;
45905b261ecSmrg    }
46005b261ecSmrg    --inHandler;
46105b261ecSmrg}
46205b261ecSmrg
46305b261ecSmrg/**
46405b261ecSmrg *
46505b261ecSmrg *  \param result    32 bits of undefined result from the wait
46605b261ecSmrg *  \param pReadmask the resulting descriptor mask
46705b261ecSmrg */
46805b261ecSmrgvoid
46905b261ecSmrgWakeupHandler(int result, pointer pReadmask)
47005b261ecSmrg{
47105b261ecSmrg    int i, j;
47205b261ecSmrg
47305b261ecSmrg    ++inHandler;
47405b261ecSmrg    for (i = numHandlers - 1; i >= 0; i--)
47505b261ecSmrg	(*handlers[i].WakeupHandler) (handlers[i].blockData,
47605b261ecSmrg				      result, pReadmask);
47705b261ecSmrg    for (i = 0; i < screenInfo.numScreens; i++)
47805b261ecSmrg	(* screenInfo.screens[i]->WakeupHandler)(i,
47905b261ecSmrg				screenInfo.screens[i]->wakeupData,
48005b261ecSmrg				result, pReadmask);
48105b261ecSmrg    if (handlerDeleted)
48205b261ecSmrg    {
48305b261ecSmrg	for (i = 0; i < numHandlers;)
48405b261ecSmrg	    if (handlers[i].deleted)
48505b261ecSmrg	    {
48605b261ecSmrg	    	for (j = i; j < numHandlers - 1; j++)
48705b261ecSmrg		    handlers[j] = handlers[j+1];
48805b261ecSmrg	    	numHandlers--;
48905b261ecSmrg	    }
49005b261ecSmrg	    else
49105b261ecSmrg		i++;
49205b261ecSmrg	handlerDeleted = FALSE;
49305b261ecSmrg    }
49405b261ecSmrg    --inHandler;
49505b261ecSmrg}
49605b261ecSmrg
49705b261ecSmrg/**
49805b261ecSmrg * Reentrant with BlockHandler and WakeupHandler, except wakeup won't
49905b261ecSmrg * get called until next time
50005b261ecSmrg */
50105b261ecSmrg_X_EXPORT Bool
50205b261ecSmrgRegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
50305b261ecSmrg                                WakeupHandlerProcPtr wakeupHandler,
50405b261ecSmrg                                pointer blockData)
50505b261ecSmrg{
50605b261ecSmrg    BlockHandlerPtr new;
50705b261ecSmrg
50805b261ecSmrg    if (numHandlers >= sizeHandlers)
50905b261ecSmrg    {
51005b261ecSmrg    	new = (BlockHandlerPtr) xrealloc (handlers, (numHandlers + 1) *
51105b261ecSmrg				      	  sizeof (BlockHandlerRec));
51205b261ecSmrg    	if (!new)
51305b261ecSmrg	    return FALSE;
51405b261ecSmrg    	handlers = new;
51505b261ecSmrg	sizeHandlers = numHandlers + 1;
51605b261ecSmrg    }
51705b261ecSmrg    handlers[numHandlers].BlockHandler = blockHandler;
51805b261ecSmrg    handlers[numHandlers].WakeupHandler = wakeupHandler;
51905b261ecSmrg    handlers[numHandlers].blockData = blockData;
52005b261ecSmrg    handlers[numHandlers].deleted = FALSE;
52105b261ecSmrg    numHandlers = numHandlers + 1;
52205b261ecSmrg    return TRUE;
52305b261ecSmrg}
52405b261ecSmrg
52505b261ecSmrg_X_EXPORT void
52605b261ecSmrgRemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
52705b261ecSmrg                              WakeupHandlerProcPtr wakeupHandler,
52805b261ecSmrg                              pointer blockData)
52905b261ecSmrg{
53005b261ecSmrg    int	    i;
53105b261ecSmrg
53205b261ecSmrg    for (i = 0; i < numHandlers; i++)
53305b261ecSmrg	if (handlers[i].BlockHandler == blockHandler &&
53405b261ecSmrg	    handlers[i].WakeupHandler == wakeupHandler &&
53505b261ecSmrg	    handlers[i].blockData == blockData)
53605b261ecSmrg	{
53705b261ecSmrg	    if (inHandler)
53805b261ecSmrg	    {
53905b261ecSmrg		handlerDeleted = TRUE;
54005b261ecSmrg		handlers[i].deleted = TRUE;
54105b261ecSmrg	    }
54205b261ecSmrg	    else
54305b261ecSmrg	    {
54405b261ecSmrg	    	for (; i < numHandlers - 1; i++)
54505b261ecSmrg		    handlers[i] = handlers[i+1];
54605b261ecSmrg	    	numHandlers--;
54705b261ecSmrg	    }
54805b261ecSmrg	    break;
54905b261ecSmrg	}
55005b261ecSmrg}
55105b261ecSmrg
55205b261ecSmrgvoid
55305b261ecSmrgInitBlockAndWakeupHandlers (void)
55405b261ecSmrg{
55505b261ecSmrg    xfree (handlers);
55605b261ecSmrg    handlers = (BlockHandlerPtr) 0;
55705b261ecSmrg    numHandlers = 0;
55805b261ecSmrg    sizeHandlers = 0;
55905b261ecSmrg}
56005b261ecSmrg
56105b261ecSmrg/*
56205b261ecSmrg * A general work queue.  Perform some task before the server
56305b261ecSmrg * sleeps for input.
56405b261ecSmrg */
56505b261ecSmrg
56605b261ecSmrgWorkQueuePtr		workQueue;
56705b261ecSmrgstatic WorkQueuePtr	*workQueueLast = &workQueue;
56805b261ecSmrg
56905b261ecSmrgvoid
57005b261ecSmrgProcessWorkQueue(void)
57105b261ecSmrg{
57205b261ecSmrg    WorkQueuePtr    q, *p;
57305b261ecSmrg
57405b261ecSmrg    p = &workQueue;
57505b261ecSmrg    /*
57605b261ecSmrg     * Scan the work queue once, calling each function.  Those
57705b261ecSmrg     * which return TRUE are removed from the queue, otherwise
57805b261ecSmrg     * they will be called again.  This must be reentrant with
57905b261ecSmrg     * QueueWorkProc.
58005b261ecSmrg     */
58105b261ecSmrg    while ((q = *p))
58205b261ecSmrg    {
58305b261ecSmrg	if ((*q->function) (q->client, q->closure))
58405b261ecSmrg	{
58505b261ecSmrg	    /* remove q from the list */
58605b261ecSmrg	    *p = q->next;    /* don't fetch until after func called */
58705b261ecSmrg	    xfree (q);
58805b261ecSmrg	}
58905b261ecSmrg	else
59005b261ecSmrg	{
59105b261ecSmrg	    p = &q->next;    /* don't fetch until after func called */
59205b261ecSmrg	}
59305b261ecSmrg    }
59405b261ecSmrg    workQueueLast = p;
59505b261ecSmrg}
59605b261ecSmrg
59705b261ecSmrgvoid
59805b261ecSmrgProcessWorkQueueZombies(void)
59905b261ecSmrg{
60005b261ecSmrg    WorkQueuePtr    q, *p;
60105b261ecSmrg
60205b261ecSmrg    p = &workQueue;
60305b261ecSmrg    while ((q = *p))
60405b261ecSmrg    {
60505b261ecSmrg	if (q->client && q->client->clientGone)
60605b261ecSmrg	{
60705b261ecSmrg	    (void) (*q->function) (q->client, q->closure);
60805b261ecSmrg	    /* remove q from the list */
60905b261ecSmrg	    *p = q->next;    /* don't fetch until after func called */
61005b261ecSmrg	    xfree (q);
61105b261ecSmrg	}
61205b261ecSmrg	else
61305b261ecSmrg	{
61405b261ecSmrg	    p = &q->next;    /* don't fetch until after func called */
61505b261ecSmrg	}
61605b261ecSmrg    }
61705b261ecSmrg    workQueueLast = p;
61805b261ecSmrg}
61905b261ecSmrg
62005b261ecSmrg_X_EXPORT Bool
62105b261ecSmrgQueueWorkProc (
62205b261ecSmrg    Bool (*function)(ClientPtr /* pClient */, pointer /* closure */),
62305b261ecSmrg    ClientPtr client, pointer closure)
62405b261ecSmrg{
62505b261ecSmrg    WorkQueuePtr    q;
62605b261ecSmrg
62705b261ecSmrg    q = (WorkQueuePtr) xalloc (sizeof *q);
62805b261ecSmrg    if (!q)
62905b261ecSmrg	return FALSE;
63005b261ecSmrg    q->function = function;
63105b261ecSmrg    q->client = client;
63205b261ecSmrg    q->closure = closure;
63305b261ecSmrg    q->next = NULL;
63405b261ecSmrg    *workQueueLast = q;
63505b261ecSmrg    workQueueLast = &q->next;
63605b261ecSmrg    return TRUE;
63705b261ecSmrg}
63805b261ecSmrg
63905b261ecSmrg/*
64005b261ecSmrg * Manage a queue of sleeping clients, awakening them
64105b261ecSmrg * when requested, by using the OS functions IgnoreClient
64205b261ecSmrg * and AttendClient.  Note that this *ignores* the troubles
64305b261ecSmrg * with request data interleaving itself with events, but
64405b261ecSmrg * we'll leave that until a later time.
64505b261ecSmrg */
64605b261ecSmrg
64705b261ecSmrgtypedef struct _SleepQueue {
64805b261ecSmrg    struct _SleepQueue	*next;
64905b261ecSmrg    ClientPtr		client;
65005b261ecSmrg    ClientSleepProcPtr  function;
65105b261ecSmrg    pointer		closure;
65205b261ecSmrg} SleepQueueRec, *SleepQueuePtr;
65305b261ecSmrg
65405b261ecSmrgstatic SleepQueuePtr	sleepQueue = NULL;
65505b261ecSmrg
65605b261ecSmrg_X_EXPORT Bool
65705b261ecSmrgClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure)
65805b261ecSmrg{
65905b261ecSmrg    SleepQueuePtr   q;
66005b261ecSmrg
66105b261ecSmrg    q = (SleepQueuePtr) xalloc (sizeof *q);
66205b261ecSmrg    if (!q)
66305b261ecSmrg	return FALSE;
66405b261ecSmrg
66505b261ecSmrg    IgnoreClient (client);
66605b261ecSmrg    q->next = sleepQueue;
66705b261ecSmrg    q->client = client;
66805b261ecSmrg    q->function = function;
66905b261ecSmrg    q->closure = closure;
67005b261ecSmrg    sleepQueue = q;
67105b261ecSmrg    return TRUE;
67205b261ecSmrg}
67305b261ecSmrg
67405b261ecSmrgBool
67505b261ecSmrgClientSignal (ClientPtr client)
67605b261ecSmrg{
67705b261ecSmrg    SleepQueuePtr   q;
67805b261ecSmrg
67905b261ecSmrg    for (q = sleepQueue; q; q = q->next)
68005b261ecSmrg	if (q->client == client)
68105b261ecSmrg	{
68205b261ecSmrg	    return QueueWorkProc (q->function, q->client, q->closure);
68305b261ecSmrg	}
68405b261ecSmrg    return FALSE;
68505b261ecSmrg}
68605b261ecSmrg
68705b261ecSmrg_X_EXPORT void
68805b261ecSmrgClientWakeup (ClientPtr client)
68905b261ecSmrg{
69005b261ecSmrg    SleepQueuePtr   q, *prev;
69105b261ecSmrg
69205b261ecSmrg    prev = &sleepQueue;
69305b261ecSmrg    while ( (q = *prev) )
69405b261ecSmrg    {
69505b261ecSmrg	if (q->client == client)
69605b261ecSmrg	{
69705b261ecSmrg	    *prev = q->next;
69805b261ecSmrg	    xfree (q);
69905b261ecSmrg	    if (client->clientGone)
70005b261ecSmrg		/* Oops -- new zombie cleanup code ensures this only
70105b261ecSmrg		 * happens from inside CloseDownClient; don't want to
70205b261ecSmrg		 * recurse here...
70305b261ecSmrg		 */
70405b261ecSmrg		/* CloseDownClient(client) */;
70505b261ecSmrg	    else
70605b261ecSmrg		AttendClient (client);
70705b261ecSmrg	    break;
70805b261ecSmrg	}
70905b261ecSmrg	prev = &q->next;
71005b261ecSmrg    }
71105b261ecSmrg}
71205b261ecSmrg
71305b261ecSmrgBool
71405b261ecSmrgClientIsAsleep (ClientPtr client)
71505b261ecSmrg{
71605b261ecSmrg    SleepQueuePtr   q;
71705b261ecSmrg
71805b261ecSmrg    for (q = sleepQueue; q; q = q->next)
71905b261ecSmrg	if (q->client == client)
72005b261ecSmrg	    return TRUE;
72105b261ecSmrg    return FALSE;
72205b261ecSmrg}
72305b261ecSmrg
72405b261ecSmrg/*
72505b261ecSmrg *  Generic Callback Manager
72605b261ecSmrg */
72705b261ecSmrg
72805b261ecSmrg/* ===== Private Procedures ===== */
72905b261ecSmrg
73005b261ecSmrgstatic int numCallbackListsToCleanup = 0;
73105b261ecSmrgstatic CallbackListPtr **listsToCleanup = NULL;
73205b261ecSmrg
73305b261ecSmrgstatic Bool
73405b261ecSmrg_AddCallback(
73505b261ecSmrg    CallbackListPtr *pcbl,
73605b261ecSmrg    CallbackProcPtr callback,
73705b261ecSmrg    pointer         data)
73805b261ecSmrg{
73905b261ecSmrg    CallbackPtr     cbr;
74005b261ecSmrg
74105b261ecSmrg    cbr = (CallbackPtr) xalloc(sizeof(CallbackRec));
74205b261ecSmrg    if (!cbr)
74305b261ecSmrg	return FALSE;
74405b261ecSmrg    cbr->proc = callback;
74505b261ecSmrg    cbr->data = data;
74605b261ecSmrg    cbr->next = (*pcbl)->list;
74705b261ecSmrg    cbr->deleted = FALSE;
74805b261ecSmrg    (*pcbl)->list = cbr;
74905b261ecSmrg    return TRUE;
75005b261ecSmrg}
75105b261ecSmrg
75205b261ecSmrgstatic Bool
75305b261ecSmrg_DeleteCallback(
75405b261ecSmrg    CallbackListPtr *pcbl,
75505b261ecSmrg    CallbackProcPtr callback,
75605b261ecSmrg    pointer         data)
75705b261ecSmrg{
75805b261ecSmrg    CallbackListPtr cbl = *pcbl;
75905b261ecSmrg    CallbackPtr     cbr, pcbr;
76005b261ecSmrg
76105b261ecSmrg    for (pcbr = NULL, cbr = cbl->list;
76205b261ecSmrg	 cbr != NULL;
76305b261ecSmrg	 pcbr = cbr, cbr = cbr->next)
76405b261ecSmrg    {
76505b261ecSmrg	if ((cbr->proc == callback) && (cbr->data == data))
76605b261ecSmrg	    break;
76705b261ecSmrg    }
76805b261ecSmrg    if (cbr != NULL)
76905b261ecSmrg    {
77005b261ecSmrg	if (cbl->inCallback)
77105b261ecSmrg	{
77205b261ecSmrg	    ++(cbl->numDeleted);
77305b261ecSmrg	    cbr->deleted = TRUE;
77405b261ecSmrg	}
77505b261ecSmrg	else
77605b261ecSmrg	{
77705b261ecSmrg	    if (pcbr == NULL)
77805b261ecSmrg		cbl->list = cbr->next;
77905b261ecSmrg	    else
78005b261ecSmrg		pcbr->next = cbr->next;
78105b261ecSmrg	    xfree(cbr);
78205b261ecSmrg	}
78305b261ecSmrg	return TRUE;
78405b261ecSmrg    }
78505b261ecSmrg    return FALSE;
78605b261ecSmrg}
78705b261ecSmrg
78805b261ecSmrgstatic void
78905b261ecSmrg_CallCallbacks(
79005b261ecSmrg    CallbackListPtr    *pcbl,
79105b261ecSmrg    pointer	    call_data)
79205b261ecSmrg{
79305b261ecSmrg    CallbackListPtr cbl = *pcbl;
79405b261ecSmrg    CallbackPtr     cbr, pcbr;
79505b261ecSmrg
79605b261ecSmrg    ++(cbl->inCallback);
79705b261ecSmrg    for (cbr = cbl->list; cbr != NULL; cbr = cbr->next)
79805b261ecSmrg    {
79905b261ecSmrg	(*(cbr->proc)) (pcbl, cbr->data, call_data);
80005b261ecSmrg    }
80105b261ecSmrg    --(cbl->inCallback);
80205b261ecSmrg
80305b261ecSmrg    if (cbl->inCallback) return;
80405b261ecSmrg
80505b261ecSmrg    /* Was the entire list marked for deletion? */
80605b261ecSmrg
80705b261ecSmrg    if (cbl->deleted)
80805b261ecSmrg    {
80905b261ecSmrg	DeleteCallbackList(pcbl);
81005b261ecSmrg	return;
81105b261ecSmrg    }
81205b261ecSmrg
81305b261ecSmrg    /* Were some individual callbacks on the list marked for deletion?
81405b261ecSmrg     * If so, do the deletions.
81505b261ecSmrg     */
81605b261ecSmrg
81705b261ecSmrg    if (cbl->numDeleted)
81805b261ecSmrg    {
81905b261ecSmrg	for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; )
82005b261ecSmrg	{
82105b261ecSmrg	    if (cbr->deleted)
82205b261ecSmrg	    {
82305b261ecSmrg		if (pcbr)
82405b261ecSmrg		{
82505b261ecSmrg		    cbr = cbr->next;
82605b261ecSmrg		    xfree(pcbr->next);
82705b261ecSmrg		    pcbr->next = cbr;
82805b261ecSmrg		} else
82905b261ecSmrg		{
83005b261ecSmrg		    cbr = cbr->next;
83105b261ecSmrg		    xfree(cbl->list);
83205b261ecSmrg		    cbl->list = cbr;
83305b261ecSmrg		}
83405b261ecSmrg		cbl->numDeleted--;
83505b261ecSmrg	    }
83605b261ecSmrg	    else /* this one wasn't deleted */
83705b261ecSmrg	    {
83805b261ecSmrg		pcbr = cbr;
83905b261ecSmrg		cbr = cbr->next;
84005b261ecSmrg	    }
84105b261ecSmrg	}
84205b261ecSmrg    }
84305b261ecSmrg}
84405b261ecSmrg
84505b261ecSmrgstatic void
84605b261ecSmrg_DeleteCallbackList(
84705b261ecSmrg    CallbackListPtr    *pcbl)
84805b261ecSmrg{
84905b261ecSmrg    CallbackListPtr cbl = *pcbl;
85005b261ecSmrg    CallbackPtr     cbr, nextcbr;
85105b261ecSmrg    int i;
85205b261ecSmrg
85305b261ecSmrg    if (cbl->inCallback)
85405b261ecSmrg    {
85505b261ecSmrg	cbl->deleted = TRUE;
85605b261ecSmrg	return;
85705b261ecSmrg    }
85805b261ecSmrg
85905b261ecSmrg    for (i = 0; i < numCallbackListsToCleanup; i++)
86005b261ecSmrg    {
86105b261ecSmrg	if ((listsToCleanup[i] = pcbl) != 0)
86205b261ecSmrg	{
86305b261ecSmrg	    listsToCleanup[i] = NULL;
86405b261ecSmrg	    break;
86505b261ecSmrg	}
86605b261ecSmrg    }
86705b261ecSmrg
86805b261ecSmrg    for (cbr = cbl->list; cbr != NULL; cbr = nextcbr)
86905b261ecSmrg    {
87005b261ecSmrg	nextcbr = cbr->next;
87105b261ecSmrg	xfree(cbr);
87205b261ecSmrg    }
87305b261ecSmrg    xfree(cbl);
87405b261ecSmrg    *pcbl = NULL;
87505b261ecSmrg}
87605b261ecSmrg
87705b261ecSmrgstatic CallbackFuncsRec default_cbfuncs =
87805b261ecSmrg{
87905b261ecSmrg    _AddCallback,
88005b261ecSmrg    _DeleteCallback,
88105b261ecSmrg    _CallCallbacks,
88205b261ecSmrg    _DeleteCallbackList
88305b261ecSmrg};
88405b261ecSmrg
88505b261ecSmrgstatic Bool
88605b261ecSmrgCreateCallbackList(CallbackListPtr *pcbl, CallbackFuncsPtr cbfuncs)
88705b261ecSmrg{
88805b261ecSmrg    CallbackListPtr  cbl;
88905b261ecSmrg    int i;
89005b261ecSmrg
89105b261ecSmrg    if (!pcbl) return FALSE;
89205b261ecSmrg    cbl = (CallbackListPtr) xalloc(sizeof(CallbackListRec));
89305b261ecSmrg    if (!cbl) return FALSE;
89405b261ecSmrg    cbl->funcs = cbfuncs ? *cbfuncs : default_cbfuncs;
89505b261ecSmrg    cbl->inCallback = 0;
89605b261ecSmrg    cbl->deleted = FALSE;
89705b261ecSmrg    cbl->numDeleted = 0;
89805b261ecSmrg    cbl->list = NULL;
89905b261ecSmrg    *pcbl = cbl;
90005b261ecSmrg
90105b261ecSmrg    for (i = 0; i < numCallbackListsToCleanup; i++)
90205b261ecSmrg    {
90305b261ecSmrg	if (!listsToCleanup[i])
90405b261ecSmrg	{
90505b261ecSmrg	    listsToCleanup[i] = pcbl;
90605b261ecSmrg	    return TRUE;
90705b261ecSmrg	}
90805b261ecSmrg    }
90905b261ecSmrg
91005b261ecSmrg    listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup,
91105b261ecSmrg		sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1));
91205b261ecSmrg    listsToCleanup[numCallbackListsToCleanup] = pcbl;
91305b261ecSmrg    numCallbackListsToCleanup++;
91405b261ecSmrg    return TRUE;
91505b261ecSmrg}
91605b261ecSmrg
91705b261ecSmrg/* ===== Public Procedures ===== */
91805b261ecSmrg
91905b261ecSmrg_X_EXPORT Bool
92005b261ecSmrgAddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
92105b261ecSmrg{
92205b261ecSmrg    if (!pcbl) return FALSE;
92305b261ecSmrg    if (!*pcbl)
92405b261ecSmrg    {	/* list hasn't been created yet; go create it */
92505b261ecSmrg	if (!CreateCallbackList(pcbl, (CallbackFuncsPtr)NULL))
92605b261ecSmrg	    return FALSE;
92705b261ecSmrg    }
92805b261ecSmrg    return ((*(*pcbl)->funcs.AddCallback) (pcbl, callback, data));
92905b261ecSmrg}
93005b261ecSmrg
93105b261ecSmrg_X_EXPORT Bool
93205b261ecSmrgDeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
93305b261ecSmrg{
93405b261ecSmrg    if (!pcbl || !*pcbl) return FALSE;
93505b261ecSmrg    return ((*(*pcbl)->funcs.DeleteCallback) (pcbl, callback, data));
93605b261ecSmrg}
93705b261ecSmrg
93805b261ecSmrgvoid
93905b261ecSmrgCallCallbacks(CallbackListPtr *pcbl, pointer call_data)
94005b261ecSmrg{
94105b261ecSmrg    if (!pcbl || !*pcbl) return;
94205b261ecSmrg    (*(*pcbl)->funcs.CallCallbacks) (pcbl, call_data);
94305b261ecSmrg}
94405b261ecSmrg
94505b261ecSmrgvoid
94605b261ecSmrgDeleteCallbackList(CallbackListPtr *pcbl)
94705b261ecSmrg{
94805b261ecSmrg    if (!pcbl || !*pcbl) return;
94905b261ecSmrg    (*(*pcbl)->funcs.DeleteCallbackList) (pcbl);
95005b261ecSmrg}
95105b261ecSmrg
95205b261ecSmrgvoid
95305b261ecSmrgInitCallbackManager(void)
95405b261ecSmrg{
95505b261ecSmrg    int i;
95605b261ecSmrg
95705b261ecSmrg    for (i = 0; i < numCallbackListsToCleanup; i++)
95805b261ecSmrg    {
95905b261ecSmrg	DeleteCallbackList(listsToCleanup[i]);
96005b261ecSmrg    }
96105b261ecSmrg    if (listsToCleanup) xfree(listsToCleanup);
96205b261ecSmrg
96305b261ecSmrg    numCallbackListsToCleanup = 0;
96405b261ecSmrg    listsToCleanup = NULL;
96505b261ecSmrg}
966