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