dixutils.c revision 6747b715
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"
956747b715Smrg#include "gcstruct.h"
9605b261ecSmrg#include "scrnintstr.h"
9705b261ecSmrg#define  XK_LATIN1
9805b261ecSmrg#include <X11/keysymdef.h>
9905b261ecSmrg#include "xace.h"
10005b261ecSmrg
10105b261ecSmrg/*
10205b261ecSmrg * CompareTimeStamps returns -1, 0, or +1 depending on if the first
10305b261ecSmrg * argument is less than, equal to or greater than the second argument.
10405b261ecSmrg */
10505b261ecSmrg
1066747b715Smrgint
10705b261ecSmrgCompareTimeStamps(TimeStamp a, TimeStamp b)
10805b261ecSmrg{
10905b261ecSmrg    if (a.months < b.months)
11005b261ecSmrg	return EARLIER;
11105b261ecSmrg    if (a.months > b.months)
11205b261ecSmrg	return LATER;
11305b261ecSmrg    if (a.milliseconds < b.milliseconds)
11405b261ecSmrg	return EARLIER;
11505b261ecSmrg    if (a.milliseconds > b.milliseconds)
11605b261ecSmrg	return LATER;
11705b261ecSmrg    return SAMETIME;
11805b261ecSmrg}
11905b261ecSmrg
12005b261ecSmrg/*
12105b261ecSmrg * convert client times to server TimeStamps
12205b261ecSmrg */
12305b261ecSmrg
12405b261ecSmrg#define HALFMONTH ((unsigned long) 1<<31)
1256747b715SmrgTimeStamp
12605b261ecSmrgClientTimeToServerTime(CARD32 c)
12705b261ecSmrg{
12805b261ecSmrg    TimeStamp ts;
12905b261ecSmrg    if (c == CurrentTime)
13005b261ecSmrg	return currentTime;
13105b261ecSmrg    ts.months = currentTime.months;
13205b261ecSmrg    ts.milliseconds = c;
13305b261ecSmrg    if (c > currentTime.milliseconds)
13405b261ecSmrg    {
13505b261ecSmrg	if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH)
13605b261ecSmrg	    ts.months -= 1;
13705b261ecSmrg    }
13805b261ecSmrg    else if (c < currentTime.milliseconds)
13905b261ecSmrg    {
14005b261ecSmrg	if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH)
14105b261ecSmrg	    ts.months += 1;
14205b261ecSmrg    }
14305b261ecSmrg    return ts;
14405b261ecSmrg}
14505b261ecSmrg
14605b261ecSmrg/*
14705b261ecSmrg * ISO Latin-1 case conversion routine
14805b261ecSmrg *
14905b261ecSmrg * this routine always null-terminates the result, so
15005b261ecSmrg * beware of too-small buffers
15105b261ecSmrg */
15205b261ecSmrg
15305b261ecSmrgstatic unsigned char
15405b261ecSmrgISOLatin1ToLower (unsigned char source)
15505b261ecSmrg{
15605b261ecSmrg    unsigned char   dest;
15705b261ecSmrg    if ((source >= XK_A) && (source <= XK_Z))
15805b261ecSmrg       dest = source + (XK_a - XK_A);
15905b261ecSmrg    else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis))
16005b261ecSmrg       dest = source + (XK_agrave - XK_Agrave);
16105b261ecSmrg    else if ((source >= XK_Ooblique) && (source <= XK_Thorn))
16205b261ecSmrg       dest = source + (XK_oslash - XK_Ooblique);
16305b261ecSmrg    else
16405b261ecSmrg       dest = source;
16505b261ecSmrg    return dest;
16605b261ecSmrg}
16705b261ecSmrg
16805b261ecSmrg
16905b261ecSmrgint
17005b261ecSmrgCompareISOLatin1Lowered(unsigned char *s1, int s1len,
17105b261ecSmrg			unsigned char *s2, int s2len)
17205b261ecSmrg{
17305b261ecSmrg    unsigned char   c1, c2;
17405b261ecSmrg
17505b261ecSmrg    for (;;)
17605b261ecSmrg    {
17705b261ecSmrg	/* note -- compare against zero so that -1 ignores len */
17805b261ecSmrg	c1 = s1len-- ? *s1++ : '\0';
17905b261ecSmrg	c2 = s2len-- ? *s2++ : '\0';
18005b261ecSmrg	if (!c1 ||
18105b261ecSmrg	    (c1 != c2 &&
18205b261ecSmrg	     (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2))))
18305b261ecSmrg	    break;
18405b261ecSmrg    }
18505b261ecSmrg    return (int) c1 - (int) c2;
18605b261ecSmrg}
18705b261ecSmrg
18805b261ecSmrg/*
18905b261ecSmrg * dixLookupWindow and dixLookupDrawable:
19005b261ecSmrg * Look up the window/drawable taking into account the client doing the
19105b261ecSmrg * lookup, the type of drawable desired, and the type of access desired.
19205b261ecSmrg * Return Success with *pDraw set if the window/drawable exists and the client
19305b261ecSmrg * is allowed access, else return an error code with *pDraw set to NULL.  The
19405b261ecSmrg * access mask values are defined in resource.h.  The type mask values are
19505b261ecSmrg * defined in pixmap.h, with zero equivalent to M_DRAWABLE.
19605b261ecSmrg */
1976747b715Smrgint
19805b261ecSmrgdixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client,
19905b261ecSmrg		  Mask type, Mask access)
20005b261ecSmrg{
20105b261ecSmrg    DrawablePtr pTmp;
2024642e01fSmrg    int rc;
2034642e01fSmrg
20405b261ecSmrg    *pDraw = NULL;
20505b261ecSmrg    client->errorValue = id;
20605b261ecSmrg
20705b261ecSmrg    if (id == INVALID)
20805b261ecSmrg	return BadDrawable;
20905b261ecSmrg
210b86d567bSmrg    rc = dixLookupResourceByClass((pointer *)&pTmp, id, RC_DRAWABLE, client, access);
2114642e01fSmrg
2124642e01fSmrg    if (rc == BadValue)
21305b261ecSmrg	return BadDrawable;
2144642e01fSmrg    if (rc != Success)
2154642e01fSmrg	return rc;
21605b261ecSmrg    if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE)))
21705b261ecSmrg	return BadMatch;
21805b261ecSmrg
21905b261ecSmrg    *pDraw = pTmp;
22005b261ecSmrg    return Success;
22105b261ecSmrg}
22205b261ecSmrg
2236747b715Smrgint
22405b261ecSmrgdixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
22505b261ecSmrg{
22605b261ecSmrg    int rc;
22705b261ecSmrg    rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access);
22805b261ecSmrg    return (rc == BadDrawable) ? BadWindow : rc;
22905b261ecSmrg}
23005b261ecSmrg
2316747b715Smrgint
23205b261ecSmrgdixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access)
23305b261ecSmrg{
2346747b715Smrg    return dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access);
23505b261ecSmrg}
23605b261ecSmrg
2376747b715Smrgint
2386747b715SmrgdixLookupFontable(FontPtr *pFont, XID id, ClientPtr client, Mask access)
2396747b715Smrg{
2406747b715Smrg    int rc;
2416747b715Smrg    GC *pGC;
2426747b715Smrg    client->errorValue = id;		/* EITHER font or gc */
2436747b715Smrg    rc = dixLookupResourceByType((pointer *) pFont, id, RT_FONT, client, access);
2446747b715Smrg    if (rc != BadFont)
2456747b715Smrg	return rc;
2466747b715Smrg    rc = dixLookupResourceByType((pointer *) &pGC, id, RT_GC, client, access);
2476747b715Smrg    if (rc == BadGC)
2486747b715Smrg	return BadFont;
2496747b715Smrg    if (rc == Success)
2506747b715Smrg	*pFont = pGC->font;
2516747b715Smrg    return rc;
2526747b715Smrg}
2536747b715Smrg
2546747b715Smrgint
25505b261ecSmrgdixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access)
25605b261ecSmrg{
2574642e01fSmrg    pointer pRes;
2584642e01fSmrg    int rc = BadValue, clientIndex = CLIENT_ID(rid);
25905b261ecSmrg
2604642e01fSmrg    if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT))
2614642e01fSmrg	goto bad;
26205b261ecSmrg
263b86d567bSmrg    rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess);
2644642e01fSmrg    if (rc != Success)
2654642e01fSmrg	goto bad;
26605b261ecSmrg
2674642e01fSmrg    rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access);
2684642e01fSmrg    if (rc != Success)
2694642e01fSmrg	goto bad;
27005b261ecSmrg
2714642e01fSmrg    *pClient = clients[clientIndex];
2724642e01fSmrg    return Success;
2734642e01fSmrgbad:
2744642e01fSmrg    if(client)
2754642e01fSmrg        client->errorValue = rid;
2764642e01fSmrg    *pClient = NULL;
2774642e01fSmrg    return rc;
27805b261ecSmrg}
27905b261ecSmrg
28005b261ecSmrgint
28105b261ecSmrgAlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode,
2824642e01fSmrg                      Bool toRoot, Bool map)
28305b261ecSmrg{
28405b261ecSmrg    int numnow;
28505b261ecSmrg    SaveSetElt *pTmp = NULL;
28605b261ecSmrg    int j;
28705b261ecSmrg
28805b261ecSmrg    numnow = client->numSaved;
28905b261ecSmrg    j = 0;
29005b261ecSmrg    if (numnow)
29105b261ecSmrg    {
29205b261ecSmrg	pTmp = client->saveSet;
29305b261ecSmrg	while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin))
29405b261ecSmrg	    j++;
29505b261ecSmrg    }
29605b261ecSmrg    if (mode == SetModeInsert)
29705b261ecSmrg    {
29805b261ecSmrg	if (j < numnow)         /* duplicate */
2996747b715Smrg	   return Success;
30005b261ecSmrg	numnow++;
3016747b715Smrg	pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow);
30205b261ecSmrg	if (!pTmp)
3036747b715Smrg	    return BadAlloc;
30405b261ecSmrg	client->saveSet = pTmp;
30505b261ecSmrg       	client->numSaved = numnow;
30605b261ecSmrg	SaveSetAssignWindow(client->saveSet[numnow - 1], pWin);
30705b261ecSmrg	SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot);
3084642e01fSmrg	SaveSetAssignMap(client->saveSet[numnow - 1], map);
3096747b715Smrg	return Success;
31005b261ecSmrg    }
31105b261ecSmrg    else if ((mode == SetModeDelete) && (j < numnow))
31205b261ecSmrg    {
31305b261ecSmrg	while (j < numnow-1)
31405b261ecSmrg	{
31505b261ecSmrg           pTmp[j] = pTmp[j+1];
31605b261ecSmrg	   j++;
31705b261ecSmrg	}
31805b261ecSmrg	numnow--;
31905b261ecSmrg        if (numnow)
32005b261ecSmrg	{
3216747b715Smrg	    pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow);
32205b261ecSmrg	    if (pTmp)
32305b261ecSmrg		client->saveSet = pTmp;
32405b261ecSmrg	}
32505b261ecSmrg        else
32605b261ecSmrg        {
3276747b715Smrg            free(client->saveSet);
32805b261ecSmrg	    client->saveSet = (SaveSetElt *)NULL;
32905b261ecSmrg	}
33005b261ecSmrg	client->numSaved = numnow;
3316747b715Smrg	return Success;
33205b261ecSmrg    }
3336747b715Smrg    return Success;
33405b261ecSmrg}
33505b261ecSmrg
33605b261ecSmrgvoid
33705b261ecSmrgDeleteWindowFromAnySaveSet(WindowPtr pWin)
33805b261ecSmrg{
33905b261ecSmrg    int i;
34005b261ecSmrg    ClientPtr client;
34105b261ecSmrg
34205b261ecSmrg    for (i = 0; i< currentMaxClients; i++)
34305b261ecSmrg    {
34405b261ecSmrg	client = clients[i];
34505b261ecSmrg	if (client && client->numSaved)
34605b261ecSmrg	    (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE);
34705b261ecSmrg    }
34805b261ecSmrg}
34905b261ecSmrg
35005b261ecSmrg/* No-op Don't Do Anything : sometimes we need to be able to call a procedure
35105b261ecSmrg * that doesn't do anything.  For example, on screen with only static
35205b261ecSmrg * colormaps, if someone calls install colormap, it's easier to have a dummy
35305b261ecSmrg * procedure to call than to check if there's a procedure
35405b261ecSmrg */
3556747b715Smrgvoid
35605b261ecSmrgNoopDDA(void)
35705b261ecSmrg{
35805b261ecSmrg}
35905b261ecSmrg
36005b261ecSmrgtypedef struct _BlockHandler {
36105b261ecSmrg    BlockHandlerProcPtr BlockHandler;
36205b261ecSmrg    WakeupHandlerProcPtr WakeupHandler;
36305b261ecSmrg    pointer blockData;
36405b261ecSmrg    Bool    deleted;
36505b261ecSmrg} BlockHandlerRec, *BlockHandlerPtr;
36605b261ecSmrg
36705b261ecSmrgstatic BlockHandlerPtr	handlers;
36805b261ecSmrgstatic int		numHandlers;
36905b261ecSmrgstatic int		sizeHandlers;
37005b261ecSmrgstatic Bool		inHandler;
37105b261ecSmrgstatic Bool		handlerDeleted;
37205b261ecSmrg
37305b261ecSmrg/**
37405b261ecSmrg *
37505b261ecSmrg *  \param pTimeout   DIX doesn't want to know how OS represents time
37605b261ecSmrg *  \param pReadMask  nor how it represents the det of descriptors
37705b261ecSmrg */
37805b261ecSmrgvoid
37905b261ecSmrgBlockHandler(pointer pTimeout, pointer pReadmask)
38005b261ecSmrg{
38105b261ecSmrg    int i, j;
38205b261ecSmrg
38305b261ecSmrg    ++inHandler;
38405b261ecSmrg    for (i = 0; i < screenInfo.numScreens; i++)
38505b261ecSmrg	(* screenInfo.screens[i]->BlockHandler)(i,
38605b261ecSmrg				screenInfo.screens[i]->blockData,
38705b261ecSmrg				pTimeout, pReadmask);
38805b261ecSmrg    for (i = 0; i < numHandlers; i++)
38905b261ecSmrg	(*handlers[i].BlockHandler) (handlers[i].blockData,
39005b261ecSmrg				     pTimeout, pReadmask);
39105b261ecSmrg    if (handlerDeleted)
39205b261ecSmrg    {
39305b261ecSmrg	for (i = 0; i < numHandlers;)
39405b261ecSmrg	    if (handlers[i].deleted)
39505b261ecSmrg	    {
39605b261ecSmrg	    	for (j = i; j < numHandlers - 1; j++)
39705b261ecSmrg		    handlers[j] = handlers[j+1];
39805b261ecSmrg	    	numHandlers--;
39905b261ecSmrg	    }
40005b261ecSmrg	    else
40105b261ecSmrg		i++;
40205b261ecSmrg	handlerDeleted = FALSE;
40305b261ecSmrg    }
40405b261ecSmrg    --inHandler;
40505b261ecSmrg}
40605b261ecSmrg
40705b261ecSmrg/**
40805b261ecSmrg *
40905b261ecSmrg *  \param result    32 bits of undefined result from the wait
41005b261ecSmrg *  \param pReadmask the resulting descriptor mask
41105b261ecSmrg */
41205b261ecSmrgvoid
41305b261ecSmrgWakeupHandler(int result, pointer pReadmask)
41405b261ecSmrg{
41505b261ecSmrg    int i, j;
41605b261ecSmrg
41705b261ecSmrg    ++inHandler;
41805b261ecSmrg    for (i = numHandlers - 1; i >= 0; i--)
41905b261ecSmrg	(*handlers[i].WakeupHandler) (handlers[i].blockData,
42005b261ecSmrg				      result, pReadmask);
42105b261ecSmrg    for (i = 0; i < screenInfo.numScreens; i++)
42205b261ecSmrg	(* screenInfo.screens[i]->WakeupHandler)(i,
42305b261ecSmrg				screenInfo.screens[i]->wakeupData,
42405b261ecSmrg				result, pReadmask);
42505b261ecSmrg    if (handlerDeleted)
42605b261ecSmrg    {
42705b261ecSmrg	for (i = 0; i < numHandlers;)
42805b261ecSmrg	    if (handlers[i].deleted)
42905b261ecSmrg	    {
43005b261ecSmrg	    	for (j = i; j < numHandlers - 1; j++)
43105b261ecSmrg		    handlers[j] = handlers[j+1];
43205b261ecSmrg	    	numHandlers--;
43305b261ecSmrg	    }
43405b261ecSmrg	    else
43505b261ecSmrg		i++;
43605b261ecSmrg	handlerDeleted = FALSE;
43705b261ecSmrg    }
43805b261ecSmrg    --inHandler;
43905b261ecSmrg}
44005b261ecSmrg
44105b261ecSmrg/**
44205b261ecSmrg * Reentrant with BlockHandler and WakeupHandler, except wakeup won't
44305b261ecSmrg * get called until next time
44405b261ecSmrg */
4456747b715SmrgBool
44605b261ecSmrgRegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
44705b261ecSmrg                                WakeupHandlerProcPtr wakeupHandler,
44805b261ecSmrg                                pointer blockData)
44905b261ecSmrg{
45005b261ecSmrg    BlockHandlerPtr new;
45105b261ecSmrg
45205b261ecSmrg    if (numHandlers >= sizeHandlers)
45305b261ecSmrg    {
4546747b715Smrg        new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) *
45505b261ecSmrg				      	  sizeof (BlockHandlerRec));
45605b261ecSmrg    	if (!new)
45705b261ecSmrg	    return FALSE;
45805b261ecSmrg    	handlers = new;
45905b261ecSmrg	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
47005b261ecSmrgRemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
47105b261ecSmrg                              WakeupHandlerProcPtr wakeupHandler,
47205b261ecSmrg                              pointer blockData)
47305b261ecSmrg{
47405b261ecSmrg    int	    i;
47505b261ecSmrg
47605b261ecSmrg    for (i = 0; i < numHandlers; i++)
47705b261ecSmrg	if (handlers[i].BlockHandler == blockHandler &&
47805b261ecSmrg	    handlers[i].WakeupHandler == wakeupHandler &&
47905b261ecSmrg	    handlers[i].blockData == blockData)
48005b261ecSmrg	{
48105b261ecSmrg	    if (inHandler)
48205b261ecSmrg	    {
48305b261ecSmrg		handlerDeleted = TRUE;
48405b261ecSmrg		handlers[i].deleted = TRUE;
48505b261ecSmrg	    }
48605b261ecSmrg	    else
48705b261ecSmrg	    {
48805b261ecSmrg	    	for (; i < numHandlers - 1; i++)
48905b261ecSmrg		    handlers[i] = handlers[i+1];
49005b261ecSmrg	    	numHandlers--;
49105b261ecSmrg	    }
49205b261ecSmrg	    break;
49305b261ecSmrg	}
49405b261ecSmrg}
49505b261ecSmrg
49605b261ecSmrgvoid
49705b261ecSmrgInitBlockAndWakeupHandlers (void)
49805b261ecSmrg{
4996747b715Smrg    free(handlers);
50005b261ecSmrg    handlers = (BlockHandlerPtr) 0;
50105b261ecSmrg    numHandlers = 0;
50205b261ecSmrg    sizeHandlers = 0;
50305b261ecSmrg}
50405b261ecSmrg
50505b261ecSmrg/*
50605b261ecSmrg * A general work queue.  Perform some task before the server
50705b261ecSmrg * sleeps for input.
50805b261ecSmrg */
50905b261ecSmrg
51005b261ecSmrgWorkQueuePtr		workQueue;
51105b261ecSmrgstatic WorkQueuePtr	*workQueueLast = &workQueue;
51205b261ecSmrg
51305b261ecSmrgvoid
51405b261ecSmrgProcessWorkQueue(void)
51505b261ecSmrg{
51605b261ecSmrg    WorkQueuePtr    q, *p;
51705b261ecSmrg
51805b261ecSmrg    p = &workQueue;
51905b261ecSmrg    /*
52005b261ecSmrg     * Scan the work queue once, calling each function.  Those
52105b261ecSmrg     * which return TRUE are removed from the queue, otherwise
52205b261ecSmrg     * they will be called again.  This must be reentrant with
52305b261ecSmrg     * QueueWorkProc.
52405b261ecSmrg     */
52505b261ecSmrg    while ((q = *p))
52605b261ecSmrg    {
52705b261ecSmrg	if ((*q->function) (q->client, q->closure))
52805b261ecSmrg	{
52905b261ecSmrg	    /* remove q from the list */
53005b261ecSmrg	    *p = q->next;    /* don't fetch until after func called */
5316747b715Smrg	    free(q);
53205b261ecSmrg	}
53305b261ecSmrg	else
53405b261ecSmrg	{
53505b261ecSmrg	    p = &q->next;    /* don't fetch until after func called */
53605b261ecSmrg	}
53705b261ecSmrg    }
53805b261ecSmrg    workQueueLast = p;
53905b261ecSmrg}
54005b261ecSmrg
54105b261ecSmrgvoid
54205b261ecSmrgProcessWorkQueueZombies(void)
54305b261ecSmrg{
54405b261ecSmrg    WorkQueuePtr    q, *p;
54505b261ecSmrg
54605b261ecSmrg    p = &workQueue;
54705b261ecSmrg    while ((q = *p))
54805b261ecSmrg    {
54905b261ecSmrg	if (q->client && q->client->clientGone)
55005b261ecSmrg	{
55105b261ecSmrg	    (void) (*q->function) (q->client, q->closure);
55205b261ecSmrg	    /* remove q from the list */
55305b261ecSmrg	    *p = q->next;    /* don't fetch until after func called */
5546747b715Smrg	    free(q);
55505b261ecSmrg	}
55605b261ecSmrg	else
55705b261ecSmrg	{
55805b261ecSmrg	    p = &q->next;    /* don't fetch until after func called */
55905b261ecSmrg	}
56005b261ecSmrg    }
56105b261ecSmrg    workQueueLast = p;
56205b261ecSmrg}
56305b261ecSmrg
5646747b715SmrgBool
56505b261ecSmrgQueueWorkProc (
56605b261ecSmrg    Bool (*function)(ClientPtr /* pClient */, pointer /* closure */),
56705b261ecSmrg    ClientPtr client, pointer closure)
56805b261ecSmrg{
56905b261ecSmrg    WorkQueuePtr    q;
57005b261ecSmrg
5716747b715Smrg    q = malloc(sizeof *q);
57205b261ecSmrg    if (!q)
57305b261ecSmrg	return FALSE;
57405b261ecSmrg    q->function = function;
57505b261ecSmrg    q->client = client;
57605b261ecSmrg    q->closure = closure;
57705b261ecSmrg    q->next = NULL;
57805b261ecSmrg    *workQueueLast = q;
57905b261ecSmrg    workQueueLast = &q->next;
58005b261ecSmrg    return TRUE;
58105b261ecSmrg}
58205b261ecSmrg
58305b261ecSmrg/*
58405b261ecSmrg * Manage a queue of sleeping clients, awakening them
58505b261ecSmrg * when requested, by using the OS functions IgnoreClient
58605b261ecSmrg * and AttendClient.  Note that this *ignores* the troubles
58705b261ecSmrg * with request data interleaving itself with events, but
58805b261ecSmrg * we'll leave that until a later time.
58905b261ecSmrg */
59005b261ecSmrg
59105b261ecSmrgtypedef struct _SleepQueue {
59205b261ecSmrg    struct _SleepQueue	*next;
59305b261ecSmrg    ClientPtr		client;
59405b261ecSmrg    ClientSleepProcPtr  function;
59505b261ecSmrg    pointer		closure;
59605b261ecSmrg} SleepQueueRec, *SleepQueuePtr;
59705b261ecSmrg
59805b261ecSmrgstatic SleepQueuePtr	sleepQueue = NULL;
59905b261ecSmrg
6006747b715SmrgBool
60105b261ecSmrgClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure)
60205b261ecSmrg{
60305b261ecSmrg    SleepQueuePtr   q;
60405b261ecSmrg
6056747b715Smrg    q = malloc(sizeof *q);
60605b261ecSmrg    if (!q)
60705b261ecSmrg	return FALSE;
60805b261ecSmrg
60905b261ecSmrg    IgnoreClient (client);
61005b261ecSmrg    q->next = sleepQueue;
61105b261ecSmrg    q->client = client;
61205b261ecSmrg    q->function = function;
61305b261ecSmrg    q->closure = closure;
61405b261ecSmrg    sleepQueue = q;
61505b261ecSmrg    return TRUE;
61605b261ecSmrg}
61705b261ecSmrg
61805b261ecSmrgBool
61905b261ecSmrgClientSignal (ClientPtr client)
62005b261ecSmrg{
62105b261ecSmrg    SleepQueuePtr   q;
62205b261ecSmrg
62305b261ecSmrg    for (q = sleepQueue; q; q = q->next)
62405b261ecSmrg	if (q->client == client)
62505b261ecSmrg	{
62605b261ecSmrg	    return QueueWorkProc (q->function, q->client, q->closure);
62705b261ecSmrg	}
62805b261ecSmrg    return FALSE;
62905b261ecSmrg}
63005b261ecSmrg
6316747b715Smrgvoid
63205b261ecSmrgClientWakeup (ClientPtr client)
63305b261ecSmrg{
63405b261ecSmrg    SleepQueuePtr   q, *prev;
63505b261ecSmrg
63605b261ecSmrg    prev = &sleepQueue;
63705b261ecSmrg    while ( (q = *prev) )
63805b261ecSmrg    {
63905b261ecSmrg	if (q->client == client)
64005b261ecSmrg	{
64105b261ecSmrg	    *prev = q->next;
6426747b715Smrg	    free(q);
64305b261ecSmrg	    if (client->clientGone)
64405b261ecSmrg		/* Oops -- new zombie cleanup code ensures this only
64505b261ecSmrg		 * happens from inside CloseDownClient; don't want to
64605b261ecSmrg		 * recurse here...
64705b261ecSmrg		 */
64805b261ecSmrg		/* CloseDownClient(client) */;
64905b261ecSmrg	    else
65005b261ecSmrg		AttendClient (client);
65105b261ecSmrg	    break;
65205b261ecSmrg	}
65305b261ecSmrg	prev = &q->next;
65405b261ecSmrg    }
65505b261ecSmrg}
65605b261ecSmrg
65705b261ecSmrgBool
65805b261ecSmrgClientIsAsleep (ClientPtr client)
65905b261ecSmrg{
66005b261ecSmrg    SleepQueuePtr   q;
66105b261ecSmrg
66205b261ecSmrg    for (q = sleepQueue; q; q = q->next)
66305b261ecSmrg	if (q->client == client)
66405b261ecSmrg	    return TRUE;
66505b261ecSmrg    return FALSE;
66605b261ecSmrg}
66705b261ecSmrg
66805b261ecSmrg/*
66905b261ecSmrg *  Generic Callback Manager
67005b261ecSmrg */
67105b261ecSmrg
67205b261ecSmrg/* ===== Private Procedures ===== */
67305b261ecSmrg
67405b261ecSmrgstatic int numCallbackListsToCleanup = 0;
67505b261ecSmrgstatic CallbackListPtr **listsToCleanup = NULL;
67605b261ecSmrg
6776747b715Smrgstatic Bool
67805b261ecSmrg_AddCallback(
67905b261ecSmrg    CallbackListPtr *pcbl,
68005b261ecSmrg    CallbackProcPtr callback,
68105b261ecSmrg    pointer         data)
68205b261ecSmrg{
68305b261ecSmrg    CallbackPtr     cbr;
68405b261ecSmrg
6856747b715Smrg    cbr = malloc(sizeof(CallbackRec));
68605b261ecSmrg    if (!cbr)
68705b261ecSmrg	return FALSE;
68805b261ecSmrg    cbr->proc = callback;
68905b261ecSmrg    cbr->data = data;
69005b261ecSmrg    cbr->next = (*pcbl)->list;
69105b261ecSmrg    cbr->deleted = FALSE;
69205b261ecSmrg    (*pcbl)->list = cbr;
69305b261ecSmrg    return TRUE;
69405b261ecSmrg}
69505b261ecSmrg
69605b261ecSmrgstatic Bool
69705b261ecSmrg_DeleteCallback(
69805b261ecSmrg    CallbackListPtr *pcbl,
69905b261ecSmrg    CallbackProcPtr callback,
70005b261ecSmrg    pointer         data)
70105b261ecSmrg{
70205b261ecSmrg    CallbackListPtr cbl = *pcbl;
70305b261ecSmrg    CallbackPtr     cbr, pcbr;
70405b261ecSmrg
70505b261ecSmrg    for (pcbr = NULL, cbr = cbl->list;
70605b261ecSmrg	 cbr != NULL;
70705b261ecSmrg	 pcbr = cbr, cbr = cbr->next)
70805b261ecSmrg    {
70905b261ecSmrg	if ((cbr->proc == callback) && (cbr->data == data))
71005b261ecSmrg	    break;
71105b261ecSmrg    }
71205b261ecSmrg    if (cbr != NULL)
71305b261ecSmrg    {
71405b261ecSmrg	if (cbl->inCallback)
71505b261ecSmrg	{
71605b261ecSmrg	    ++(cbl->numDeleted);
71705b261ecSmrg	    cbr->deleted = TRUE;
71805b261ecSmrg	}
71905b261ecSmrg	else
72005b261ecSmrg	{
72105b261ecSmrg	    if (pcbr == NULL)
72205b261ecSmrg		cbl->list = cbr->next;
72305b261ecSmrg	    else
72405b261ecSmrg		pcbr->next = cbr->next;
7256747b715Smrg	    free(cbr);
72605b261ecSmrg	}
72705b261ecSmrg	return TRUE;
72805b261ecSmrg    }
72905b261ecSmrg    return FALSE;
73005b261ecSmrg}
73105b261ecSmrg
73205b261ecSmrgstatic void
73305b261ecSmrg_CallCallbacks(
73405b261ecSmrg    CallbackListPtr    *pcbl,
73505b261ecSmrg    pointer	    call_data)
73605b261ecSmrg{
73705b261ecSmrg    CallbackListPtr cbl = *pcbl;
73805b261ecSmrg    CallbackPtr     cbr, pcbr;
73905b261ecSmrg
74005b261ecSmrg    ++(cbl->inCallback);
74105b261ecSmrg    for (cbr = cbl->list; cbr != NULL; cbr = cbr->next)
74205b261ecSmrg    {
74305b261ecSmrg	(*(cbr->proc)) (pcbl, cbr->data, call_data);
74405b261ecSmrg    }
74505b261ecSmrg    --(cbl->inCallback);
74605b261ecSmrg
74705b261ecSmrg    if (cbl->inCallback) return;
74805b261ecSmrg
74905b261ecSmrg    /* Was the entire list marked for deletion? */
75005b261ecSmrg
75105b261ecSmrg    if (cbl->deleted)
75205b261ecSmrg    {
75305b261ecSmrg	DeleteCallbackList(pcbl);
75405b261ecSmrg	return;
75505b261ecSmrg    }
75605b261ecSmrg
75705b261ecSmrg    /* Were some individual callbacks on the list marked for deletion?
75805b261ecSmrg     * If so, do the deletions.
75905b261ecSmrg     */
76005b261ecSmrg
76105b261ecSmrg    if (cbl->numDeleted)
76205b261ecSmrg    {
76305b261ecSmrg	for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; )
76405b261ecSmrg	{
76505b261ecSmrg	    if (cbr->deleted)
76605b261ecSmrg	    {
76705b261ecSmrg		if (pcbr)
76805b261ecSmrg		{
76905b261ecSmrg		    cbr = cbr->next;
7706747b715Smrg		    free(pcbr->next);
77105b261ecSmrg		    pcbr->next = cbr;
77205b261ecSmrg		} else
77305b261ecSmrg		{
77405b261ecSmrg		    cbr = cbr->next;
7756747b715Smrg		    free(cbl->list);
77605b261ecSmrg		    cbl->list = cbr;
77705b261ecSmrg		}
77805b261ecSmrg		cbl->numDeleted--;
77905b261ecSmrg	    }
78005b261ecSmrg	    else /* this one wasn't deleted */
78105b261ecSmrg	    {
78205b261ecSmrg		pcbr = cbr;
78305b261ecSmrg		cbr = cbr->next;
78405b261ecSmrg	    }
78505b261ecSmrg	}
78605b261ecSmrg    }
78705b261ecSmrg}
78805b261ecSmrg
78905b261ecSmrgstatic void
79005b261ecSmrg_DeleteCallbackList(
79105b261ecSmrg    CallbackListPtr    *pcbl)
79205b261ecSmrg{
79305b261ecSmrg    CallbackListPtr cbl = *pcbl;
79405b261ecSmrg    CallbackPtr     cbr, nextcbr;
79505b261ecSmrg    int i;
79605b261ecSmrg
79705b261ecSmrg    if (cbl->inCallback)
79805b261ecSmrg    {
79905b261ecSmrg	cbl->deleted = TRUE;
80005b261ecSmrg	return;
80105b261ecSmrg    }
80205b261ecSmrg
80305b261ecSmrg    for (i = 0; i < numCallbackListsToCleanup; i++)
80405b261ecSmrg    {
8054642e01fSmrg	if (listsToCleanup[i] == pcbl)
80605b261ecSmrg	{
80705b261ecSmrg	    listsToCleanup[i] = NULL;
80805b261ecSmrg	    break;
80905b261ecSmrg	}
81005b261ecSmrg    }
81105b261ecSmrg
81205b261ecSmrg    for (cbr = cbl->list; cbr != NULL; cbr = nextcbr)
81305b261ecSmrg    {
81405b261ecSmrg	nextcbr = cbr->next;
8156747b715Smrg	free(cbr);
81605b261ecSmrg    }
8176747b715Smrg    free(cbl);
81805b261ecSmrg    *pcbl = NULL;
81905b261ecSmrg}
82005b261ecSmrg
82105b261ecSmrgstatic Bool
8224642e01fSmrgCreateCallbackList(CallbackListPtr *pcbl)
82305b261ecSmrg{
82405b261ecSmrg    CallbackListPtr  cbl;
82505b261ecSmrg    int i;
82605b261ecSmrg
82705b261ecSmrg    if (!pcbl) return FALSE;
8286747b715Smrg    cbl = malloc(sizeof(CallbackListRec));
82905b261ecSmrg    if (!cbl) return FALSE;
83005b261ecSmrg    cbl->inCallback = 0;
83105b261ecSmrg    cbl->deleted = FALSE;
83205b261ecSmrg    cbl->numDeleted = 0;
83305b261ecSmrg    cbl->list = NULL;
83405b261ecSmrg    *pcbl = cbl;
83505b261ecSmrg
83605b261ecSmrg    for (i = 0; i < numCallbackListsToCleanup; i++)
83705b261ecSmrg    {
83805b261ecSmrg	if (!listsToCleanup[i])
83905b261ecSmrg	{
84005b261ecSmrg	    listsToCleanup[i] = pcbl;
84105b261ecSmrg	    return TRUE;
84205b261ecSmrg	}
84305b261ecSmrg    }
84405b261ecSmrg
84505b261ecSmrg    listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup,
84605b261ecSmrg		sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1));
84705b261ecSmrg    listsToCleanup[numCallbackListsToCleanup] = pcbl;
84805b261ecSmrg    numCallbackListsToCleanup++;
84905b261ecSmrg    return TRUE;
85005b261ecSmrg}
85105b261ecSmrg
85205b261ecSmrg/* ===== Public Procedures ===== */
85305b261ecSmrg
8546747b715SmrgBool
85505b261ecSmrgAddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
85605b261ecSmrg{
85705b261ecSmrg    if (!pcbl) return FALSE;
85805b261ecSmrg    if (!*pcbl)
85905b261ecSmrg    {	/* list hasn't been created yet; go create it */
8604642e01fSmrg	if (!CreateCallbackList(pcbl))
86105b261ecSmrg	    return FALSE;
86205b261ecSmrg    }
8634642e01fSmrg    return _AddCallback(pcbl, callback, data);
86405b261ecSmrg}
86505b261ecSmrg
8666747b715SmrgBool
86705b261ecSmrgDeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
86805b261ecSmrg{
86905b261ecSmrg    if (!pcbl || !*pcbl) return FALSE;
8704642e01fSmrg    return _DeleteCallback(pcbl, callback, data);
87105b261ecSmrg}
87205b261ecSmrg
8736747b715Smrgvoid
87405b261ecSmrgCallCallbacks(CallbackListPtr *pcbl, pointer call_data)
87505b261ecSmrg{
87605b261ecSmrg    if (!pcbl || !*pcbl) return;
8774642e01fSmrg    _CallCallbacks(pcbl, call_data);
87805b261ecSmrg}
87905b261ecSmrg
88005b261ecSmrgvoid
88105b261ecSmrgDeleteCallbackList(CallbackListPtr *pcbl)
88205b261ecSmrg{
88305b261ecSmrg    if (!pcbl || !*pcbl) return;
8844642e01fSmrg    _DeleteCallbackList(pcbl);
88505b261ecSmrg}
88605b261ecSmrg
8876747b715Smrgvoid
88805b261ecSmrgInitCallbackManager(void)
88905b261ecSmrg{
89005b261ecSmrg    int i;
89105b261ecSmrg
89205b261ecSmrg    for (i = 0; i < numCallbackListsToCleanup; i++)
89305b261ecSmrg    {
89405b261ecSmrg	DeleteCallbackList(listsToCleanup[i]);
89505b261ecSmrg    }
8966747b715Smrg    free(listsToCleanup);
89705b261ecSmrg
89805b261ecSmrg    numCallbackListsToCleanup = 0;
89905b261ecSmrg    listsToCleanup = NULL;
90005b261ecSmrg}
901