From 49c7992dfc9c6b8a60baf1afbede4616e0265e7f Mon Sep 17 00:00:00 2001 From: marha Date: Sun, 9 May 2010 21:09:18 +0000 Subject: xserver git update 9/5/2010 --- xorg-server/dix/dixutils.c | 1786 ++++++++++++++++++++++---------------------- 1 file changed, 902 insertions(+), 884 deletions(-) (limited to 'xorg-server/dix/dixutils.c') diff --git a/xorg-server/dix/dixutils.c b/xorg-server/dix/dixutils.c index 8278d444b..4b84a446b 100644 --- a/xorg-server/dix/dixutils.c +++ b/xorg-server/dix/dixutils.c @@ -1,884 +1,902 @@ -/*********************************************************** - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - -(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved. - -Permission to use, copy, modify, distribute, and sublicense this software and its -documentation for any purpose and without fee is hereby granted, provided that -the above copyright notices appear in all copies and that both those copyright -notices and this permission notice appear in supporting documentation and that -the name of Adobe Systems Incorporated not be used in advertising or publicity -pertaining to distribution of the software without specific, written prior -permission. No trademark license to use the Adobe trademarks is hereby -granted. If the Adobe trademark "Display PostScript"(tm) is used to describe -this software, its functionality or for any other purpose, such use shall be -limited to a statement that this software works in conjunction with the Display -PostScript system. Proper trademark attribution to reflect Adobe's ownership -of the trademark shall be given whenever any such reference to the Display -PostScript system is made. - -ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY -PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE -DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- -INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU -OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT -LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER -SUPPORT FOR THE SOFTWARE. - -Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems -Incorporated which may be registered in certain jurisdictions. - -Author: Adobe Systems Incorporated - -*/ - - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include "misc.h" -#include "windowstr.h" -#include "dixstruct.h" -#include "pixmapstr.h" -#include "scrnintstr.h" -#define XK_LATIN1 -#include -#include "xace.h" - -/* - * CompareTimeStamps returns -1, 0, or +1 depending on if the first - * argument is less than, equal to or greater than the second argument. - */ - -int -CompareTimeStamps(TimeStamp a, TimeStamp b) -{ - if (a.months < b.months) - return EARLIER; - if (a.months > b.months) - return LATER; - if (a.milliseconds < b.milliseconds) - return EARLIER; - if (a.milliseconds > b.milliseconds) - return LATER; - return SAMETIME; -} - -/* - * convert client times to server TimeStamps - */ - -#define HALFMONTH ((unsigned long) 1<<31) -TimeStamp -ClientTimeToServerTime(CARD32 c) -{ - TimeStamp ts; - if (c == CurrentTime) - return currentTime; - ts.months = currentTime.months; - ts.milliseconds = c; - if (c > currentTime.milliseconds) - { - if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH) - ts.months -= 1; - } - else if (c < currentTime.milliseconds) - { - if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH) - ts.months += 1; - } - return ts; -} - -/* - * ISO Latin-1 case conversion routine - * - * this routine always null-terminates the result, so - * beware of too-small buffers - */ - -static unsigned char -ISOLatin1ToLower (unsigned char source) -{ - unsigned char dest; - if ((source >= XK_A) && (source <= XK_Z)) - dest = source + (XK_a - XK_A); - else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis)) - dest = source + (XK_agrave - XK_Agrave); - else if ((source >= XK_Ooblique) && (source <= XK_Thorn)) - dest = source + (XK_oslash - XK_Ooblique); - else - dest = source; - return dest; -} - - -int -CompareISOLatin1Lowered(unsigned char *s1, int s1len, - unsigned char *s2, int s2len) -{ - unsigned char c1, c2; - - for (;;) - { - /* note -- compare against zero so that -1 ignores len */ - c1 = s1len-- ? *s1++ : '\0'; - c2 = s2len-- ? *s2++ : '\0'; - if (!c1 || - (c1 != c2 && - (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2)))) - break; - } - return (int) c1 - (int) c2; -} - -/* - * dixLookupWindow and dixLookupDrawable: - * Look up the window/drawable taking into account the client doing the - * lookup, the type of drawable desired, and the type of access desired. - * Return Success with *pDraw set if the window/drawable exists and the client - * is allowed access, else return an error code with *pDraw set to NULL. The - * access mask values are defined in resource.h. The type mask values are - * defined in pixmap.h, with zero equivalent to M_DRAWABLE. - */ -int -dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client, - Mask type, Mask access) -{ - DrawablePtr pTmp; - int rc; - - *pDraw = NULL; - client->errorValue = id; - - if (id == INVALID) - return BadDrawable; - - rc = dixLookupResourceByClass((pointer *)&pTmp, id, RC_DRAWABLE, client, access); - - if (rc == BadValue) - return BadDrawable; - if (rc != Success) - return rc; - if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE))) - return BadMatch; - - *pDraw = pTmp; - return Success; -} - -int -dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access) -{ - int rc; - rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access); - return (rc == BadDrawable) ? BadWindow : rc; -} - -int -dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access) -{ - int rc; - rc = dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access); - return (rc == BadValue) ? BadGC : rc; -} - -int -dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access) -{ - pointer pRes; - int rc = BadValue, clientIndex = CLIENT_ID(rid); - - if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT)) - goto bad; - - rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess); - if (rc != Success) - goto bad; - - rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access); - if (rc != Success) - goto bad; - - *pClient = clients[clientIndex]; - return Success; -bad: - if(client) - client->errorValue = rid; - *pClient = NULL; - return rc; -} - -int -AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, - Bool toRoot, Bool map) -{ - int numnow; - SaveSetElt *pTmp = NULL; - int j; - - numnow = client->numSaved; - j = 0; - if (numnow) - { - pTmp = client->saveSet; - while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin)) - j++; - } - if (mode == SetModeInsert) - { - if (j < numnow) /* duplicate */ - return(Success); - numnow++; - pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); - if (!pTmp) - return(BadAlloc); - client->saveSet = pTmp; - client->numSaved = numnow; - SaveSetAssignWindow(client->saveSet[numnow - 1], pWin); - SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot); - SaveSetAssignMap(client->saveSet[numnow - 1], map); - return(Success); - } - else if ((mode == SetModeDelete) && (j < numnow)) - { - while (j < numnow-1) - { - pTmp[j] = pTmp[j+1]; - j++; - } - numnow--; - if (numnow) - { - pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); - if (pTmp) - client->saveSet = pTmp; - } - else - { - xfree(client->saveSet); - client->saveSet = (SaveSetElt *)NULL; - } - client->numSaved = numnow; - return(Success); - } - return(Success); -} - -void -DeleteWindowFromAnySaveSet(WindowPtr pWin) -{ - int i; - ClientPtr client; - - for (i = 0; i< currentMaxClients; i++) - { - client = clients[i]; - if (client && client->numSaved) - (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE); - } -} - -/* No-op Don't Do Anything : sometimes we need to be able to call a procedure - * that doesn't do anything. For example, on screen with only static - * colormaps, if someone calls install colormap, it's easier to have a dummy - * procedure to call than to check if there's a procedure - */ -void -NoopDDA(void) -{ -} - -typedef struct _BlockHandler { - BlockHandlerProcPtr BlockHandler; - WakeupHandlerProcPtr WakeupHandler; - pointer blockData; - Bool deleted; -} BlockHandlerRec, *BlockHandlerPtr; - -static BlockHandlerPtr handlers; -static int numHandlers; -static int sizeHandlers; -static Bool inHandler; -static Bool handlerDeleted; - -/** - * - * \param pTimeout DIX doesn't want to know how OS represents time - * \param pReadMask nor how it represents the det of descriptors - */ -void -BlockHandler(pointer pTimeout, pointer pReadmask) -{ - int i, j; - - ++inHandler; - for (i = 0; i < screenInfo.numScreens; i++) - (* screenInfo.screens[i]->BlockHandler)(i, - screenInfo.screens[i]->blockData, - pTimeout, pReadmask); - for (i = 0; i < numHandlers; i++) - (*handlers[i].BlockHandler) (handlers[i].blockData, - pTimeout, pReadmask); - if (handlerDeleted) - { - for (i = 0; i < numHandlers;) - if (handlers[i].deleted) - { - for (j = i; j < numHandlers - 1; j++) - handlers[j] = handlers[j+1]; - numHandlers--; - } - else - i++; - handlerDeleted = FALSE; - } - --inHandler; -} - -/** - * - * \param result 32 bits of undefined result from the wait - * \param pReadmask the resulting descriptor mask - */ -void -WakeupHandler(int result, pointer pReadmask) -{ - int i, j; - - ++inHandler; - for (i = numHandlers - 1; i >= 0; i--) - (*handlers[i].WakeupHandler) (handlers[i].blockData, - result, pReadmask); - for (i = 0; i < screenInfo.numScreens; i++) - (* screenInfo.screens[i]->WakeupHandler)(i, - screenInfo.screens[i]->wakeupData, - result, pReadmask); - if (handlerDeleted) - { - for (i = 0; i < numHandlers;) - if (handlers[i].deleted) - { - for (j = i; j < numHandlers - 1; j++) - handlers[j] = handlers[j+1]; - numHandlers--; - } - else - i++; - handlerDeleted = FALSE; - } - --inHandler; -} - -/** - * Reentrant with BlockHandler and WakeupHandler, except wakeup won't - * get called until next time - */ -Bool -RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, - WakeupHandlerProcPtr wakeupHandler, - pointer blockData) -{ - BlockHandlerPtr new; - - if (numHandlers >= sizeHandlers) - { - new = (BlockHandlerPtr) xrealloc (handlers, (numHandlers + 1) * - sizeof (BlockHandlerRec)); - if (!new) - return FALSE; - handlers = new; - sizeHandlers = numHandlers + 1; - } - handlers[numHandlers].BlockHandler = blockHandler; - handlers[numHandlers].WakeupHandler = wakeupHandler; - handlers[numHandlers].blockData = blockData; - handlers[numHandlers].deleted = FALSE; - numHandlers = numHandlers + 1; - return TRUE; -} - -void -RemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, - WakeupHandlerProcPtr wakeupHandler, - pointer blockData) -{ - int i; - - for (i = 0; i < numHandlers; i++) - if (handlers[i].BlockHandler == blockHandler && - handlers[i].WakeupHandler == wakeupHandler && - handlers[i].blockData == blockData) - { - if (inHandler) - { - handlerDeleted = TRUE; - handlers[i].deleted = TRUE; - } - else - { - for (; i < numHandlers - 1; i++) - handlers[i] = handlers[i+1]; - numHandlers--; - } - break; - } -} - -void -InitBlockAndWakeupHandlers (void) -{ - xfree (handlers); - handlers = (BlockHandlerPtr) 0; - numHandlers = 0; - sizeHandlers = 0; -} - -/* - * A general work queue. Perform some task before the server - * sleeps for input. - */ - -WorkQueuePtr workQueue; -static WorkQueuePtr *workQueueLast = &workQueue; - -void -ProcessWorkQueue(void) -{ - WorkQueuePtr q, *p; - - p = &workQueue; - /* - * Scan the work queue once, calling each function. Those - * which return TRUE are removed from the queue, otherwise - * they will be called again. This must be reentrant with - * QueueWorkProc. - */ - while ((q = *p)) - { - if ((*q->function) (q->client, q->closure)) - { - /* remove q from the list */ - *p = q->next; /* don't fetch until after func called */ - xfree (q); - } - else - { - p = &q->next; /* don't fetch until after func called */ - } - } - workQueueLast = p; -} - -void -ProcessWorkQueueZombies(void) -{ - WorkQueuePtr q, *p; - - p = &workQueue; - while ((q = *p)) - { - if (q->client && q->client->clientGone) - { - (void) (*q->function) (q->client, q->closure); - /* remove q from the list */ - *p = q->next; /* don't fetch until after func called */ - xfree (q); - } - else - { - p = &q->next; /* don't fetch until after func called */ - } - } - workQueueLast = p; -} - -Bool -QueueWorkProc ( - Bool (*function)(ClientPtr /* pClient */, pointer /* closure */), - ClientPtr client, pointer closure) -{ - WorkQueuePtr q; - - q = xalloc (sizeof *q); - if (!q) - return FALSE; - q->function = function; - q->client = client; - q->closure = closure; - q->next = NULL; - *workQueueLast = q; - workQueueLast = &q->next; - return TRUE; -} - -/* - * Manage a queue of sleeping clients, awakening them - * when requested, by using the OS functions IgnoreClient - * and AttendClient. Note that this *ignores* the troubles - * with request data interleaving itself with events, but - * we'll leave that until a later time. - */ - -typedef struct _SleepQueue { - struct _SleepQueue *next; - ClientPtr client; - ClientSleepProcPtr function; - pointer closure; -} SleepQueueRec, *SleepQueuePtr; - -static SleepQueuePtr sleepQueue = NULL; - -Bool -ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure) -{ - SleepQueuePtr q; - - q = xalloc (sizeof *q); - if (!q) - return FALSE; - - IgnoreClient (client); - q->next = sleepQueue; - q->client = client; - q->function = function; - q->closure = closure; - sleepQueue = q; - return TRUE; -} - -Bool -ClientSignal (ClientPtr client) -{ - SleepQueuePtr q; - - for (q = sleepQueue; q; q = q->next) - if (q->client == client) - { - return QueueWorkProc (q->function, q->client, q->closure); - } - return FALSE; -} - -void -ClientWakeup (ClientPtr client) -{ - SleepQueuePtr q, *prev; - - prev = &sleepQueue; - while ( (q = *prev) ) - { - if (q->client == client) - { - *prev = q->next; - xfree (q); - if (client->clientGone) - /* Oops -- new zombie cleanup code ensures this only - * happens from inside CloseDownClient; don't want to - * recurse here... - */ - /* CloseDownClient(client) */; - else - AttendClient (client); - break; - } - prev = &q->next; - } -} - -Bool -ClientIsAsleep (ClientPtr client) -{ - SleepQueuePtr q; - - for (q = sleepQueue; q; q = q->next) - if (q->client == client) - return TRUE; - return FALSE; -} - -/* - * Generic Callback Manager - */ - -/* ===== Private Procedures ===== */ - -static int numCallbackListsToCleanup = 0; -static CallbackListPtr **listsToCleanup = NULL; - -static Bool -_AddCallback( - CallbackListPtr *pcbl, - CallbackProcPtr callback, - pointer data) -{ - CallbackPtr cbr; - - cbr = xalloc(sizeof(CallbackRec)); - if (!cbr) - return FALSE; - cbr->proc = callback; - cbr->data = data; - cbr->next = (*pcbl)->list; - cbr->deleted = FALSE; - (*pcbl)->list = cbr; - return TRUE; -} - -static Bool -_DeleteCallback( - CallbackListPtr *pcbl, - CallbackProcPtr callback, - pointer data) -{ - CallbackListPtr cbl = *pcbl; - CallbackPtr cbr, pcbr; - - for (pcbr = NULL, cbr = cbl->list; - cbr != NULL; - pcbr = cbr, cbr = cbr->next) - { - if ((cbr->proc == callback) && (cbr->data == data)) - break; - } - if (cbr != NULL) - { - if (cbl->inCallback) - { - ++(cbl->numDeleted); - cbr->deleted = TRUE; - } - else - { - if (pcbr == NULL) - cbl->list = cbr->next; - else - pcbr->next = cbr->next; - xfree(cbr); - } - return TRUE; - } - return FALSE; -} - -static void -_CallCallbacks( - CallbackListPtr *pcbl, - pointer call_data) -{ - CallbackListPtr cbl = *pcbl; - CallbackPtr cbr, pcbr; - - ++(cbl->inCallback); - for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) - { - (*(cbr->proc)) (pcbl, cbr->data, call_data); - } - --(cbl->inCallback); - - if (cbl->inCallback) return; - - /* Was the entire list marked for deletion? */ - - if (cbl->deleted) - { - DeleteCallbackList(pcbl); - return; - } - - /* Were some individual callbacks on the list marked for deletion? - * If so, do the deletions. - */ - - if (cbl->numDeleted) - { - for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; ) - { - if (cbr->deleted) - { - if (pcbr) - { - cbr = cbr->next; - xfree(pcbr->next); - pcbr->next = cbr; - } else - { - cbr = cbr->next; - xfree(cbl->list); - cbl->list = cbr; - } - cbl->numDeleted--; - } - else /* this one wasn't deleted */ - { - pcbr = cbr; - cbr = cbr->next; - } - } - } -} - -static void -_DeleteCallbackList( - CallbackListPtr *pcbl) -{ - CallbackListPtr cbl = *pcbl; - CallbackPtr cbr, nextcbr; - int i; - - if (cbl->inCallback) - { - cbl->deleted = TRUE; - return; - } - - for (i = 0; i < numCallbackListsToCleanup; i++) - { - if (listsToCleanup[i] == pcbl) - { - listsToCleanup[i] = NULL; - break; - } - } - - for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) - { - nextcbr = cbr->next; - xfree(cbr); - } - xfree(cbl); - *pcbl = NULL; -} - -static Bool -CreateCallbackList(CallbackListPtr *pcbl) -{ - CallbackListPtr cbl; - int i; - - if (!pcbl) return FALSE; - cbl = xalloc(sizeof(CallbackListRec)); - if (!cbl) return FALSE; - cbl->inCallback = 0; - cbl->deleted = FALSE; - cbl->numDeleted = 0; - cbl->list = NULL; - *pcbl = cbl; - - for (i = 0; i < numCallbackListsToCleanup; i++) - { - if (!listsToCleanup[i]) - { - listsToCleanup[i] = pcbl; - return TRUE; - } - } - - listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup, - sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1)); - listsToCleanup[numCallbackListsToCleanup] = pcbl; - numCallbackListsToCleanup++; - return TRUE; -} - -/* ===== Public Procedures ===== */ - -Bool -AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) -{ - if (!pcbl) return FALSE; - if (!*pcbl) - { /* list hasn't been created yet; go create it */ - if (!CreateCallbackList(pcbl)) - return FALSE; - } - return _AddCallback(pcbl, callback, data); -} - -Bool -DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) -{ - if (!pcbl || !*pcbl) return FALSE; - return _DeleteCallback(pcbl, callback, data); -} - -void -CallCallbacks(CallbackListPtr *pcbl, pointer call_data) -{ - if (!pcbl || !*pcbl) return; - _CallCallbacks(pcbl, call_data); -} - -void -DeleteCallbackList(CallbackListPtr *pcbl) -{ - if (!pcbl || !*pcbl) return; - _DeleteCallbackList(pcbl); -} - -void -InitCallbackManager(void) -{ - int i; - - for (i = 0; i < numCallbackListsToCleanup; i++) - { - DeleteCallbackList(listsToCleanup[i]); - } - if (listsToCleanup) xfree(listsToCleanup); - - numCallbackListsToCleanup = 0; - listsToCleanup = NULL; -} +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + +(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved. + +Permission to use, copy, modify, distribute, and sublicense this software and its +documentation for any purpose and without fee is hereby granted, provided that +the above copyright notices appear in all copies and that both those copyright +notices and this permission notice appear in supporting documentation and that +the name of Adobe Systems Incorporated not be used in advertising or publicity +pertaining to distribution of the software without specific, written prior +permission. No trademark license to use the Adobe trademarks is hereby +granted. If the Adobe trademark "Display PostScript"(tm) is used to describe +this software, its functionality or for any other purpose, such use shall be +limited to a statement that this software works in conjunction with the Display +PostScript system. Proper trademark attribution to reflect Adobe's ownership +of the trademark shall be given whenever any such reference to the Display +PostScript system is made. + +ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY +PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- +INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU +OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT +LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER +SUPPORT FOR THE SOFTWARE. + +Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems +Incorporated which may be registered in certain jurisdictions. + +Author: Adobe Systems Incorporated + +*/ + + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "windowstr.h" +#include "dixstruct.h" +#include "pixmapstr.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#define XK_LATIN1 +#include +#include "xace.h" + +/* + * CompareTimeStamps returns -1, 0, or +1 depending on if the first + * argument is less than, equal to or greater than the second argument. + */ + +int +CompareTimeStamps(TimeStamp a, TimeStamp b) +{ + if (a.months < b.months) + return EARLIER; + if (a.months > b.months) + return LATER; + if (a.milliseconds < b.milliseconds) + return EARLIER; + if (a.milliseconds > b.milliseconds) + return LATER; + return SAMETIME; +} + +/* + * convert client times to server TimeStamps + */ + +#define HALFMONTH ((unsigned long) 1<<31) +TimeStamp +ClientTimeToServerTime(CARD32 c) +{ + TimeStamp ts; + if (c == CurrentTime) + return currentTime; + ts.months = currentTime.months; + ts.milliseconds = c; + if (c > currentTime.milliseconds) + { + if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH) + ts.months -= 1; + } + else if (c < currentTime.milliseconds) + { + if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH) + ts.months += 1; + } + return ts; +} + +/* + * ISO Latin-1 case conversion routine + * + * this routine always null-terminates the result, so + * beware of too-small buffers + */ + +static unsigned char +ISOLatin1ToLower (unsigned char source) +{ + unsigned char dest; + if ((source >= XK_A) && (source <= XK_Z)) + dest = source + (XK_a - XK_A); + else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis)) + dest = source + (XK_agrave - XK_Agrave); + else if ((source >= XK_Ooblique) && (source <= XK_Thorn)) + dest = source + (XK_oslash - XK_Ooblique); + else + dest = source; + return dest; +} + + +int +CompareISOLatin1Lowered(unsigned char *s1, int s1len, + unsigned char *s2, int s2len) +{ + unsigned char c1, c2; + + for (;;) + { + /* note -- compare against zero so that -1 ignores len */ + c1 = s1len-- ? *s1++ : '\0'; + c2 = s2len-- ? *s2++ : '\0'; + if (!c1 || + (c1 != c2 && + (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2)))) + break; + } + return (int) c1 - (int) c2; +} + +/* + * dixLookupWindow and dixLookupDrawable: + * Look up the window/drawable taking into account the client doing the + * lookup, the type of drawable desired, and the type of access desired. + * Return Success with *pDraw set if the window/drawable exists and the client + * is allowed access, else return an error code with *pDraw set to NULL. The + * access mask values are defined in resource.h. The type mask values are + * defined in pixmap.h, with zero equivalent to M_DRAWABLE. + */ +int +dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client, + Mask type, Mask access) +{ + DrawablePtr pTmp; + int rc; + + *pDraw = NULL; + client->errorValue = id; + + if (id == INVALID) + return BadDrawable; + + rc = dixLookupResourceByClass((pointer *)&pTmp, id, RC_DRAWABLE, client, access); + + if (rc == BadValue) + return BadDrawable; + if (rc != Success) + return rc; + if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE))) + return BadMatch; + + *pDraw = pTmp; + return Success; +} + +int +dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access) +{ + int rc; + rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access); + return (rc == BadDrawable) ? BadWindow : rc; +} + +int +dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access) +{ + int rc; + rc = dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access); + return (rc == BadValue) ? BadGC : rc; +} + +int +dixLookupFontable(FontPtr *pFont, XID id, ClientPtr client, Mask access) +{ + int rc; + GC *pGC; + client->errorValue = id; /* EITHER font or gc */ + rc = dixLookupResourceByType((pointer *) pFont, id, RT_FONT, client, access); + if (rc != BadValue) + return rc; + rc = dixLookupResourceByType((pointer *) &pGC, id, RT_GC, client, access); + if (rc == BadValue) + return BadFont; + if (rc == Success) + *pFont = pGC->font; + return rc; +} + +int +dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access) +{ + pointer pRes; + int rc = BadValue, clientIndex = CLIENT_ID(rid); + + if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT)) + goto bad; + + rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess); + if (rc != Success) + goto bad; + + rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access); + if (rc != Success) + goto bad; + + *pClient = clients[clientIndex]; + return Success; +bad: + if(client) + client->errorValue = rid; + *pClient = NULL; + return rc; +} + +int +AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, + Bool toRoot, Bool map) +{ + int numnow; + SaveSetElt *pTmp = NULL; + int j; + + numnow = client->numSaved; + j = 0; + if (numnow) + { + pTmp = client->saveSet; + while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin)) + j++; + } + if (mode == SetModeInsert) + { + if (j < numnow) /* duplicate */ + return(Success); + numnow++; + pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); + if (!pTmp) + return(BadAlloc); + client->saveSet = pTmp; + client->numSaved = numnow; + SaveSetAssignWindow(client->saveSet[numnow - 1], pWin); + SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot); + SaveSetAssignMap(client->saveSet[numnow - 1], map); + return(Success); + } + else if ((mode == SetModeDelete) && (j < numnow)) + { + while (j < numnow-1) + { + pTmp[j] = pTmp[j+1]; + j++; + } + numnow--; + if (numnow) + { + pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); + if (pTmp) + client->saveSet = pTmp; + } + else + { + xfree(client->saveSet); + client->saveSet = (SaveSetElt *)NULL; + } + client->numSaved = numnow; + return(Success); + } + return(Success); +} + +void +DeleteWindowFromAnySaveSet(WindowPtr pWin) +{ + int i; + ClientPtr client; + + for (i = 0; i< currentMaxClients; i++) + { + client = clients[i]; + if (client && client->numSaved) + (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE); + } +} + +/* No-op Don't Do Anything : sometimes we need to be able to call a procedure + * that doesn't do anything. For example, on screen with only static + * colormaps, if someone calls install colormap, it's easier to have a dummy + * procedure to call than to check if there's a procedure + */ +void +NoopDDA(void) +{ +} + +typedef struct _BlockHandler { + BlockHandlerProcPtr BlockHandler; + WakeupHandlerProcPtr WakeupHandler; + pointer blockData; + Bool deleted; +} BlockHandlerRec, *BlockHandlerPtr; + +static BlockHandlerPtr handlers; +static int numHandlers; +static int sizeHandlers; +static Bool inHandler; +static Bool handlerDeleted; + +/** + * + * \param pTimeout DIX doesn't want to know how OS represents time + * \param pReadMask nor how it represents the det of descriptors + */ +void +BlockHandler(pointer pTimeout, pointer pReadmask) +{ + int i, j; + + ++inHandler; + for (i = 0; i < screenInfo.numScreens; i++) + (* screenInfo.screens[i]->BlockHandler)(i, + screenInfo.screens[i]->blockData, + pTimeout, pReadmask); + for (i = 0; i < numHandlers; i++) + (*handlers[i].BlockHandler) (handlers[i].blockData, + pTimeout, pReadmask); + if (handlerDeleted) + { + for (i = 0; i < numHandlers;) + if (handlers[i].deleted) + { + for (j = i; j < numHandlers - 1; j++) + handlers[j] = handlers[j+1]; + numHandlers--; + } + else + i++; + handlerDeleted = FALSE; + } + --inHandler; +} + +/** + * + * \param result 32 bits of undefined result from the wait + * \param pReadmask the resulting descriptor mask + */ +void +WakeupHandler(int result, pointer pReadmask) +{ + int i, j; + + ++inHandler; + for (i = numHandlers - 1; i >= 0; i--) + (*handlers[i].WakeupHandler) (handlers[i].blockData, + result, pReadmask); + for (i = 0; i < screenInfo.numScreens; i++) + (* screenInfo.screens[i]->WakeupHandler)(i, + screenInfo.screens[i]->wakeupData, + result, pReadmask); + if (handlerDeleted) + { + for (i = 0; i < numHandlers;) + if (handlers[i].deleted) + { + for (j = i; j < numHandlers - 1; j++) + handlers[j] = handlers[j+1]; + numHandlers--; + } + else + i++; + handlerDeleted = FALSE; + } + --inHandler; +} + +/** + * Reentrant with BlockHandler and WakeupHandler, except wakeup won't + * get called until next time + */ +Bool +RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, + WakeupHandlerProcPtr wakeupHandler, + pointer blockData) +{ + BlockHandlerPtr new; + + if (numHandlers >= sizeHandlers) + { + new = (BlockHandlerPtr) xrealloc (handlers, (numHandlers + 1) * + sizeof (BlockHandlerRec)); + if (!new) + return FALSE; + handlers = new; + sizeHandlers = numHandlers + 1; + } + handlers[numHandlers].BlockHandler = blockHandler; + handlers[numHandlers].WakeupHandler = wakeupHandler; + handlers[numHandlers].blockData = blockData; + handlers[numHandlers].deleted = FALSE; + numHandlers = numHandlers + 1; + return TRUE; +} + +void +RemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, + WakeupHandlerProcPtr wakeupHandler, + pointer blockData) +{ + int i; + + for (i = 0; i < numHandlers; i++) + if (handlers[i].BlockHandler == blockHandler && + handlers[i].WakeupHandler == wakeupHandler && + handlers[i].blockData == blockData) + { + if (inHandler) + { + handlerDeleted = TRUE; + handlers[i].deleted = TRUE; + } + else + { + for (; i < numHandlers - 1; i++) + handlers[i] = handlers[i+1]; + numHandlers--; + } + break; + } +} + +void +InitBlockAndWakeupHandlers (void) +{ + xfree (handlers); + handlers = (BlockHandlerPtr) 0; + numHandlers = 0; + sizeHandlers = 0; +} + +/* + * A general work queue. Perform some task before the server + * sleeps for input. + */ + +WorkQueuePtr workQueue; +static WorkQueuePtr *workQueueLast = &workQueue; + +void +ProcessWorkQueue(void) +{ + WorkQueuePtr q, *p; + + p = &workQueue; + /* + * Scan the work queue once, calling each function. Those + * which return TRUE are removed from the queue, otherwise + * they will be called again. This must be reentrant with + * QueueWorkProc. + */ + while ((q = *p)) + { + if ((*q->function) (q->client, q->closure)) + { + /* remove q from the list */ + *p = q->next; /* don't fetch until after func called */ + xfree (q); + } + else + { + p = &q->next; /* don't fetch until after func called */ + } + } + workQueueLast = p; +} + +void +ProcessWorkQueueZombies(void) +{ + WorkQueuePtr q, *p; + + p = &workQueue; + while ((q = *p)) + { + if (q->client && q->client->clientGone) + { + (void) (*q->function) (q->client, q->closure); + /* remove q from the list */ + *p = q->next; /* don't fetch until after func called */ + xfree (q); + } + else + { + p = &q->next; /* don't fetch until after func called */ + } + } + workQueueLast = p; +} + +Bool +QueueWorkProc ( + Bool (*function)(ClientPtr /* pClient */, pointer /* closure */), + ClientPtr client, pointer closure) +{ + WorkQueuePtr q; + + q = xalloc (sizeof *q); + if (!q) + return FALSE; + q->function = function; + q->client = client; + q->closure = closure; + q->next = NULL; + *workQueueLast = q; + workQueueLast = &q->next; + return TRUE; +} + +/* + * Manage a queue of sleeping clients, awakening them + * when requested, by using the OS functions IgnoreClient + * and AttendClient. Note that this *ignores* the troubles + * with request data interleaving itself with events, but + * we'll leave that until a later time. + */ + +typedef struct _SleepQueue { + struct _SleepQueue *next; + ClientPtr client; + ClientSleepProcPtr function; + pointer closure; +} SleepQueueRec, *SleepQueuePtr; + +static SleepQueuePtr sleepQueue = NULL; + +Bool +ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure) +{ + SleepQueuePtr q; + + q = xalloc (sizeof *q); + if (!q) + return FALSE; + + IgnoreClient (client); + q->next = sleepQueue; + q->client = client; + q->function = function; + q->closure = closure; + sleepQueue = q; + return TRUE; +} + +Bool +ClientSignal (ClientPtr client) +{ + SleepQueuePtr q; + + for (q = sleepQueue; q; q = q->next) + if (q->client == client) + { + return QueueWorkProc (q->function, q->client, q->closure); + } + return FALSE; +} + +void +ClientWakeup (ClientPtr client) +{ + SleepQueuePtr q, *prev; + + prev = &sleepQueue; + while ( (q = *prev) ) + { + if (q->client == client) + { + *prev = q->next; + xfree (q); + if (client->clientGone) + /* Oops -- new zombie cleanup code ensures this only + * happens from inside CloseDownClient; don't want to + * recurse here... + */ + /* CloseDownClient(client) */; + else + AttendClient (client); + break; + } + prev = &q->next; + } +} + +Bool +ClientIsAsleep (ClientPtr client) +{ + SleepQueuePtr q; + + for (q = sleepQueue; q; q = q->next) + if (q->client == client) + return TRUE; + return FALSE; +} + +/* + * Generic Callback Manager + */ + +/* ===== Private Procedures ===== */ + +static int numCallbackListsToCleanup = 0; +static CallbackListPtr **listsToCleanup = NULL; + +static Bool +_AddCallback( + CallbackListPtr *pcbl, + CallbackProcPtr callback, + pointer data) +{ + CallbackPtr cbr; + + cbr = xalloc(sizeof(CallbackRec)); + if (!cbr) + return FALSE; + cbr->proc = callback; + cbr->data = data; + cbr->next = (*pcbl)->list; + cbr->deleted = FALSE; + (*pcbl)->list = cbr; + return TRUE; +} + +static Bool +_DeleteCallback( + CallbackListPtr *pcbl, + CallbackProcPtr callback, + pointer data) +{ + CallbackListPtr cbl = *pcbl; + CallbackPtr cbr, pcbr; + + for (pcbr = NULL, cbr = cbl->list; + cbr != NULL; + pcbr = cbr, cbr = cbr->next) + { + if ((cbr->proc == callback) && (cbr->data == data)) + break; + } + if (cbr != NULL) + { + if (cbl->inCallback) + { + ++(cbl->numDeleted); + cbr->deleted = TRUE; + } + else + { + if (pcbr == NULL) + cbl->list = cbr->next; + else + pcbr->next = cbr->next; + xfree(cbr); + } + return TRUE; + } + return FALSE; +} + +static void +_CallCallbacks( + CallbackListPtr *pcbl, + pointer call_data) +{ + CallbackListPtr cbl = *pcbl; + CallbackPtr cbr, pcbr; + + ++(cbl->inCallback); + for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) + { + (*(cbr->proc)) (pcbl, cbr->data, call_data); + } + --(cbl->inCallback); + + if (cbl->inCallback) return; + + /* Was the entire list marked for deletion? */ + + if (cbl->deleted) + { + DeleteCallbackList(pcbl); + return; + } + + /* Were some individual callbacks on the list marked for deletion? + * If so, do the deletions. + */ + + if (cbl->numDeleted) + { + for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; ) + { + if (cbr->deleted) + { + if (pcbr) + { + cbr = cbr->next; + xfree(pcbr->next); + pcbr->next = cbr; + } else + { + cbr = cbr->next; + xfree(cbl->list); + cbl->list = cbr; + } + cbl->numDeleted--; + } + else /* this one wasn't deleted */ + { + pcbr = cbr; + cbr = cbr->next; + } + } + } +} + +static void +_DeleteCallbackList( + CallbackListPtr *pcbl) +{ + CallbackListPtr cbl = *pcbl; + CallbackPtr cbr, nextcbr; + int i; + + if (cbl->inCallback) + { + cbl->deleted = TRUE; + return; + } + + for (i = 0; i < numCallbackListsToCleanup; i++) + { + if (listsToCleanup[i] == pcbl) + { + listsToCleanup[i] = NULL; + break; + } + } + + for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) + { + nextcbr = cbr->next; + xfree(cbr); + } + xfree(cbl); + *pcbl = NULL; +} + +static Bool +CreateCallbackList(CallbackListPtr *pcbl) +{ + CallbackListPtr cbl; + int i; + + if (!pcbl) return FALSE; + cbl = xalloc(sizeof(CallbackListRec)); + if (!cbl) return FALSE; + cbl->inCallback = 0; + cbl->deleted = FALSE; + cbl->numDeleted = 0; + cbl->list = NULL; + *pcbl = cbl; + + for (i = 0; i < numCallbackListsToCleanup; i++) + { + if (!listsToCleanup[i]) + { + listsToCleanup[i] = pcbl; + return TRUE; + } + } + + listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup, + sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1)); + listsToCleanup[numCallbackListsToCleanup] = pcbl; + numCallbackListsToCleanup++; + return TRUE; +} + +/* ===== Public Procedures ===== */ + +Bool +AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) +{ + if (!pcbl) return FALSE; + if (!*pcbl) + { /* list hasn't been created yet; go create it */ + if (!CreateCallbackList(pcbl)) + return FALSE; + } + return _AddCallback(pcbl, callback, data); +} + +Bool +DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) +{ + if (!pcbl || !*pcbl) return FALSE; + return _DeleteCallback(pcbl, callback, data); +} + +void +CallCallbacks(CallbackListPtr *pcbl, pointer call_data) +{ + if (!pcbl || !*pcbl) return; + _CallCallbacks(pcbl, call_data); +} + +void +DeleteCallbackList(CallbackListPtr *pcbl) +{ + if (!pcbl || !*pcbl) return; + _DeleteCallbackList(pcbl); +} + +void +InitCallbackManager(void) +{ + int i; + + for (i = 0; i < numCallbackListsToCleanup; i++) + { + DeleteCallbackList(listsToCleanup[i]); + } + if (listsToCleanup) xfree(listsToCleanup); + + numCallbackListsToCleanup = 0; + listsToCleanup = NULL; +} -- cgit v1.2.3