diff options
Diffstat (limited to 'xorg-server/dix')
-rw-r--r-- | xorg-server/dix/dixutils.c | 1788 | ||||
-rw-r--r-- | xorg-server/dix/getevents.c | 25 | ||||
-rw-r--r-- | xorg-server/dix/grabs.c | 1226 | ||||
-rw-r--r-- | xorg-server/dix/window.c | 141 |
4 files changed, 1696 insertions, 1484 deletions
diff --git a/xorg-server/dix/dixutils.c b/xorg-server/dix/dixutils.c index c23c87e9a..1e3134663 100644 --- a/xorg-server/dix/dixutils.c +++ b/xorg-server/dix/dixutils.c @@ -1,893 +1,895 @@ -/***********************************************************
-
-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 <dix-config.h>
-#endif
-
-#include <X11/X.h>
-#include <X11/Xmd.h>
-#include "misc.h"
-#include "windowstr.h"
-#include "dixstruct.h"
-#include "pixmapstr.h"
-#include "gcstruct.h"
-#include "scrnintstr.h"
-#define XK_LATIN1
-#include <X11/keysymdef.h>
-#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)
-{
- return dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access);
-}
-
-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 != BadFont)
- return rc;
- rc = dixLookupResourceByType((pointer *) &pGC, id, RT_GC, client, access);
- if (rc == BadGC)
- 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 *)realloc(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 *)realloc(client->saveSet, sizeof(*pTmp) * numnow);
- if (pTmp)
- client->saveSet = pTmp;
- }
- else
- {
- free(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) realloc(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)
-{
- free(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 */
- free(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 */
- free(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 = malloc(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 = malloc(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;
- free(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 = malloc(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;
- free(cbr);
- }
- return TRUE;
- }
- return FALSE;
-}
-
-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;
- free(pcbr->next);
- pcbr->next = cbr;
- } else
- {
- cbr = cbr->next;
- free(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;
- free(cbr);
- }
- free(cbl);
- *pcbl = NULL;
-}
-
-static Bool
-CreateCallbackList(CallbackListPtr *pcbl)
-{
- CallbackListPtr cbl;
- int i;
-
- if (!pcbl) return FALSE;
- cbl = malloc(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
-DeleteCallbackList(CallbackListPtr *pcbl)
-{
- if (!pcbl || !*pcbl) return;
- _DeleteCallbackList(pcbl);
-}
-
-void
-InitCallbackManager(void)
-{
- int i;
-
- for (i = 0; i < numCallbackListsToCleanup; i++)
- {
- DeleteCallbackList(listsToCleanup[i]);
- }
- free(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 <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include "misc.h" +#include "windowstr.h" +#include "dixstruct.h" +#include "pixmapstr.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#define XK_LATIN1 +#include <X11/keysymdef.h> +#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) +{ + return dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access); +} + +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 != BadFont) + return rc; + rc = dixLookupResourceByType((pointer *) &pGC, id, RT_GC, client, access); + if (rc == BadGC) + 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 *)realloc(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 *)realloc(client->saveSet, sizeof(*pTmp) * numnow); + if (pTmp) + client->saveSet = pTmp; + } + else + { + free(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++) + if (!handlers[i].deleted) + (*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--) + if (!handlers[i].deleted) + (*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) realloc(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) +{ + free(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 */ + free(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 */ + free(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 = malloc(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 = malloc(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; + free(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 = malloc(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; + free(cbr); + } + return TRUE; + } + return FALSE; +} + +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; + free(pcbr->next); + pcbr->next = cbr; + } else + { + cbr = cbr->next; + free(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; + free(cbr); + } + free(cbl); + *pcbl = NULL; +} + +static Bool +CreateCallbackList(CallbackListPtr *pcbl) +{ + CallbackListPtr cbl; + int i; + + if (!pcbl) return FALSE; + cbl = malloc(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 +DeleteCallbackList(CallbackListPtr *pcbl) +{ + if (!pcbl || !*pcbl) return; + _DeleteCallbackList(pcbl); +} + +void +InitCallbackManager(void) +{ + int i; + + for (i = 0; i < numCallbackListsToCleanup; i++) + { + DeleteCallbackList(listsToCleanup[i]); + } + free(listsToCleanup); + + numCallbackListsToCleanup = 0; + listsToCleanup = NULL; +} diff --git a/xorg-server/dix/getevents.c b/xorg-server/dix/getevents.c index c935c971c..a12462a4a 100644 --- a/xorg-server/dix/getevents.c +++ b/xorg-server/dix/getevents.c @@ -320,6 +320,8 @@ updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev) * position of the pointer */ pDev->last.valuators[0] = master->last.valuators[0]; pDev->last.valuators[1] = master->last.valuators[1]; + pDev->last.remainder[0] = master->last.remainder[0]; + pDev->last.remainder[1] = master->last.remainder[1]; if (!pDev->valuator) return; @@ -339,14 +341,19 @@ updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev) if ((lastSlave = master->last.slave) && lastSlave->valuator) { for (i = 2; i < pDev->valuator->numAxes; i++) { if (i >= lastSlave->valuator->numAxes) + { pDev->last.valuators[i] = 0; + pDev->last.remainder[i] = 0; + } else + { pDev->last.valuators[i] = rescaleValuatorAxis(pDev->last.valuators[i], pDev->last.remainder[i], &pDev->last.remainder[i], lastSlave->valuator->axes + i, pDev->valuator->axes + i, 0); + } } } @@ -1164,14 +1171,17 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); - raw = &events->raw_event; - events++; - num_events++; - valuator_mask_copy(&mask, mask_in); - init_raw(pDev, raw, ms, type, buttons); - set_raw_valuators(raw, &mask, raw->valuators.data_raw); + if ((flags & POINTER_NORAW) == 0) + { + raw = &events->raw_event; + events++; + num_events++; + + init_raw(pDev, raw, ms, type, buttons); + set_raw_valuators(raw, &mask, raw->valuators.data_raw); + } if (flags & POINTER_ABSOLUTE) { @@ -1210,7 +1220,8 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons moveRelative(pDev, &x, &y, &mask); } - set_raw_valuators(raw, &mask, raw->valuators.data); + if ((flags & POINTER_NORAW) == 0) + set_raw_valuators(raw, &mask, raw->valuators.data); positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative, &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac); diff --git a/xorg-server/dix/grabs.c b/xorg-server/dix/grabs.c index a14181108..85ca9eee0 100644 --- a/xorg-server/dix/grabs.c +++ b/xorg-server/dix/grabs.c @@ -1,557 +1,669 @@ -/*
-
-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.
-
-*/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <X11/X.h>
-#include "misc.h"
-#include <X11/Xproto.h>
-#include <X11/extensions/XI2.h>
-#include "windowstr.h"
-#include "inputstr.h"
-#include "cursorstr.h"
-#include "dixgrabs.h"
-#include "xace.h"
-#include "exevents.h"
-
-#define BITMASK(i) (((Mask)1) << ((i) & 31))
-#define MASKIDX(i) ((i) >> 5)
-#define MASKWORD(buf, i) buf[MASKIDX(i)]
-#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
-#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
-#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
-
-GrabPtr
-CreateGrab(
- int client,
- DeviceIntPtr device,
- DeviceIntPtr modDevice,
- WindowPtr window,
- GrabType grabtype,
- GrabMask *mask,
- GrabParameters *param,
- int type,
- KeyCode keybut, /* key or button */
- WindowPtr confineTo,
- CursorPtr cursor)
-{
- GrabPtr grab;
-
- grab = calloc(1, sizeof(GrabRec));
- if (!grab)
- return (GrabPtr)NULL;
- grab->resource = FakeClientID(client);
- grab->device = device;
- grab->window = window;
- grab->eventMask = mask->core; /* same for XI */
- grab->deviceMask = 0;
- grab->ownerEvents = param->ownerEvents;
- grab->keyboardMode = param->this_device_mode;
- grab->pointerMode = param->other_devices_mode;
- grab->modifiersDetail.exact = param->modifiers;
- grab->modifiersDetail.pMask = NULL;
- grab->modifierDevice = modDevice;
- grab->type = type;
- grab->grabtype = grabtype;
- grab->detail.exact = keybut;
- grab->detail.pMask = NULL;
- grab->confineTo = confineTo;
- grab->cursor = cursor;
- grab->next = NULL;
-
- if (grabtype == GRABTYPE_XI2)
- memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask));
- if (cursor)
- cursor->refcnt++;
- return grab;
-
-}
-
-static void
-FreeGrab(GrabPtr pGrab)
-{
- free(pGrab->modifiersDetail.pMask);
- free(pGrab->detail.pMask);
-
- if (pGrab->cursor)
- FreeCursor(pGrab->cursor, (Cursor)0);
-
- free(pGrab);
-}
-
-int
-DeletePassiveGrab(pointer value, XID id)
-{
- GrabPtr g, prev;
- GrabPtr pGrab = (GrabPtr)value;
-
- /* it is OK if the grab isn't found */
- prev = 0;
- for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next)
- {
- if (pGrab == g)
- {
- if (prev)
- prev->next = g->next;
- else
- if (!(pGrab->window->optional->passiveGrabs = g->next))
- CheckWindowOptionalNeed (pGrab->window);
- break;
- }
- prev = g;
- }
- FreeGrab(pGrab);
- return Success;
-}
-
-static Mask *
-DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail)
-{
- Mask *mask;
- int i;
-
- mask = malloc(sizeof(Mask) * MasksPerDetailMask);
- if (mask)
- {
- if (pDetailMask)
- for (i = 0; i < MasksPerDetailMask; i++)
- mask[i]= pDetailMask[i];
- else
- for (i = 0; i < MasksPerDetailMask; i++)
- mask[i]= ~0L;
- BITCLEAR(mask, detail);
- }
- return mask;
-}
-
-static Bool
-IsInGrabMask(
- DetailRec firstDetail,
- DetailRec secondDetail,
- unsigned int exception)
-{
- if (firstDetail.exact == exception)
- {
- if (firstDetail.pMask == NULL)
- return TRUE;
-
- /* (at present) never called with two non-null pMasks */
- if (secondDetail.exact == exception)
- return FALSE;
-
- if (GETBIT(firstDetail.pMask, secondDetail.exact))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static Bool
-IdenticalExactDetails(
- unsigned int firstExact,
- unsigned int secondExact,
- unsigned int exception)
-{
- if ((firstExact == exception) || (secondExact == exception))
- return FALSE;
-
- if (firstExact == secondExact)
- return TRUE;
-
- return FALSE;
-}
-
-static Bool
-DetailSupersedesSecond(
- DetailRec firstDetail,
- DetailRec secondDetail,
- unsigned int exception)
-{
- if (IsInGrabMask(firstDetail, secondDetail, exception))
- return TRUE;
-
- if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact,
- exception))
- return TRUE;
-
- return FALSE;
-}
-
-static Bool
-GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
-{
- unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyModifier :
- (unsigned int)AnyModifier;
- if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
- pSecondGrab->modifiersDetail,
- any_modifier))
- return FALSE;
-
- if (DetailSupersedesSecond(pFirstGrab->detail,
- pSecondGrab->detail, (unsigned int)AnyKey))
- return TRUE;
-
- return FALSE;
-}
-
-/**
- * Compares two grabs and returns TRUE if the first grab matches the second
- * grab.
- *
- * A match is when
- * - the devices set for the grab are equal (this is optional).
- * - the event types for both grabs are equal.
- * - XXX
- *
- * @param ignoreDevice TRUE if the device settings on the grabs are to be
- * ignored.
- * @return TRUE if the grabs match or FALSE otherwise.
- */
-Bool
-GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
-{
- unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyModifier :
- (unsigned int)AnyModifier;
-
- if (pFirstGrab->grabtype != pSecondGrab->grabtype)
- return FALSE;
-
- if (pFirstGrab->grabtype == GRABTYPE_XI2)
- {
- if (pFirstGrab->device == inputInfo.all_devices ||
- pSecondGrab->device == inputInfo.all_devices)
- {
- /* do nothing */
- } else if (pFirstGrab->device == inputInfo.all_master_devices)
- {
- if (pSecondGrab->device != inputInfo.all_master_devices &&
- !IsMaster(pSecondGrab->device))
- return FALSE;
- } else if (pSecondGrab->device == inputInfo.all_master_devices)
- {
- if (pFirstGrab->device != inputInfo.all_master_devices &&
- !IsMaster(pFirstGrab->device))
- return FALSE;
- } else if (pSecondGrab->device != pFirstGrab->device)
- return FALSE;
- } else if (!ignoreDevice &&
- ((pFirstGrab->device != pSecondGrab->device) ||
- (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
- return FALSE;
-
- if (pFirstGrab->type != pSecondGrab->type)
- return FALSE;
-
- if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
- GrabSupersedesSecond(pSecondGrab, pFirstGrab))
- return TRUE;
-
- if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
- (unsigned int)AnyKey)
- &&
- DetailSupersedesSecond(pFirstGrab->modifiersDetail,
- pSecondGrab->modifiersDetail,
- any_modifier))
- return TRUE;
-
- if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
- (unsigned int)AnyKey)
- &&
- DetailSupersedesSecond(pSecondGrab->modifiersDetail,
- pFirstGrab->modifiersDetail,
- any_modifier))
- return TRUE;
-
- return FALSE;
-}
-
-static Bool
-GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
-{
- unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyModifier :
- (unsigned int)AnyModifier;
-
- if (pFirstGrab->grabtype != pSecondGrab->grabtype)
- return FALSE;
-
- if (pFirstGrab->device != pSecondGrab->device ||
- (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
- (pFirstGrab->type != pSecondGrab->type))
- return FALSE;
-
- if (!(DetailSupersedesSecond(pFirstGrab->detail,
- pSecondGrab->detail,
- (unsigned int)AnyKey) &&
- DetailSupersedesSecond(pSecondGrab->detail,
- pFirstGrab->detail,
- (unsigned int)AnyKey)))
- return FALSE;
-
-
- if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
- pSecondGrab->modifiersDetail,
- any_modifier) &&
- DetailSupersedesSecond(pSecondGrab->modifiersDetail,
- pFirstGrab->modifiersDetail,
- any_modifier)))
- return FALSE;
-
- return TRUE;
-}
-
-
-/**
- * Prepend the new grab to the list of passive grabs on the window.
- * Any previously existing grab that matches the new grab will be removed.
- * Adding a new grab that would override another client's grab will result in
- * a BadAccess.
- *
- * @return Success or X error code on failure.
- */
-int
-AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
-{
- GrabPtr grab;
- Mask access_mode = DixGrabAccess;
- int rc;
-
- for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
- {
- if (GrabMatchesSecond(pGrab, grab, FALSE))
- {
- if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource))
- {
- FreeGrab(pGrab);
- return BadAccess;
- }
- }
- }
-
- if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync)
- access_mode |= DixFreezeAccess;
- rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
- if (rc != Success)
- return rc;
-
- /* Remove all grabs that match the new one exactly */
- for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
- {
- if (GrabsAreIdentical(pGrab, grab))
- {
- DeletePassiveGrabFromList(grab);
- break;
- }
- }
-
- if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window))
- {
- FreeGrab(pGrab);
- return BadAlloc;
- }
-
- pGrab->next = pGrab->window->optional->passiveGrabs;
- pGrab->window->optional->passiveGrabs = pGrab;
- if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab))
- return Success;
- return BadAlloc;
-}
-
-/* the following is kinda complicated, because we need to be able to back out
- * if any allocation fails
- */
-
-Bool
-DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
-{
- GrabPtr grab;
- GrabPtr *deletes, *adds;
- Mask ***updates, **details;
- int i, ndels, nadds, nups;
- Bool ok;
- unsigned int any_modifier;
- unsigned int any_key;
-
-#define UPDATE(mask,exact) \
- if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
- ok = FALSE; \
- else \
- updates[nups++] = &(mask)
-
- i = 0;
- for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
- i++;
- if (!i)
- return TRUE;
- deletes = malloc(i * sizeof(GrabPtr));
- adds = malloc(i * sizeof(GrabPtr));
- updates = malloc(i * sizeof(Mask **));
- details = malloc(i * sizeof(Mask *));
- if (!deletes || !adds || !updates || !details)
- {
- free(details);
- free(updates);
- free(adds);
- free(deletes);
- return FALSE;
- }
-
- any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyModifier : (unsigned int)AnyModifier;
- any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
- (unsigned int)XIAnyKeycode : (unsigned int)AnyKey;
- ndels = nadds = nups = 0;
- ok = TRUE;
- for (grab = wPassiveGrabs(pMinuendGrab->window);
- grab && ok;
- grab = grab->next)
- {
- if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) ||
- !GrabMatchesSecond(grab, pMinuendGrab,
- (grab->grabtype == GRABTYPE_CORE)))
- continue;
- if (GrabSupersedesSecond(pMinuendGrab, grab))
- {
- deletes[ndels++] = grab;
- }
- else if ((grab->detail.exact == any_key)
- && (grab->modifiersDetail.exact != any_modifier))
- {
- UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
- }
- else if ((grab->modifiersDetail.exact == any_modifier)
- && (grab->detail.exact != any_key))
- {
- UPDATE(grab->modifiersDetail.pMask,
- pMinuendGrab->modifiersDetail.exact);
- }
- else if ((pMinuendGrab->detail.exact != any_key)
- && (pMinuendGrab->modifiersDetail.exact != any_modifier))
- {
- GrabPtr pNewGrab;
- GrabParameters param;
-
- UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
-
- memset(¶m, 0, sizeof(param));
- param.ownerEvents = grab->ownerEvents;
- param.this_device_mode = grab->keyboardMode;
- param.other_devices_mode = grab->pointerMode;
- param.modifiers = any_modifier;
-
- pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
- grab->modifierDevice, grab->window,
- grab->grabtype,
- (GrabMask*)&grab->eventMask,
- ¶m, (int)grab->type,
- pMinuendGrab->detail.exact,
- grab->confineTo, grab->cursor);
- if (!pNewGrab)
- ok = FALSE;
- else if (!(pNewGrab->modifiersDetail.pMask =
- DeleteDetailFromMask(grab->modifiersDetail.pMask,
- pMinuendGrab->modifiersDetail.exact))
- ||
- (!pNewGrab->window->optional &&
- !MakeWindowOptional(pNewGrab->window)))
- {
- FreeGrab(pNewGrab);
- ok = FALSE;
- }
- else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
- (pointer)pNewGrab))
- ok = FALSE;
- else
- adds[nadds++] = pNewGrab;
- }
- else if (pMinuendGrab->detail.exact == any_key)
- {
- UPDATE(grab->modifiersDetail.pMask,
- pMinuendGrab->modifiersDetail.exact);
- }
- else
- {
- UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
- }
- }
-
- if (!ok)
- {
- for (i = 0; i < nadds; i++)
- FreeResource(adds[i]->resource, RT_NONE);
- for (i = 0; i < nups; i++)
- free(details[i]);
- }
- else
- {
- for (i = 0; i < ndels; i++)
- FreeResource(deletes[i]->resource, RT_NONE);
- for (i = 0; i < nadds; i++)
- {
- grab = adds[i];
- grab->next = grab->window->optional->passiveGrabs;
- grab->window->optional->passiveGrabs = grab;
- }
- for (i = 0; i < nups; i++)
- {
- free(*updates[i]);
- *updates[i] = details[i];
- }
- }
- free(details);
- free(updates);
- free(adds);
- free(deletes);
- return ok;
-
-#undef UPDATE
-}
+/* + +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. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "misc.h" +#include <X11/Xproto.h> +#include <X11/extensions/XI2.h> +#include "windowstr.h" +#include "inputstr.h" +#include "cursorstr.h" +#include "dixgrabs.h" +#include "xace.h" +#include "exevents.h" + +#define BITMASK(i) (((Mask)1) << ((i) & 31)) +#define MASKIDX(i) ((i) >> 5) +#define MASKWORD(buf, i) buf[MASKIDX(i)] +#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) +#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) +#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) + +void +PrintDeviceGrabInfo(DeviceIntPtr dev) +{ + ClientPtr client; + LocalClientCredRec *lcc; + int i, j; + GrabInfoPtr devGrab = &dev->deviceGrab; + GrabPtr grab = devGrab->grab; + + ErrorF("Active grab 0x%lx (%s) on device '%s' (%d):", + (unsigned long) grab->resource, + (grab->grabtype == GRABTYPE_XI2) ? "xi2" : + ((grab->grabtype == GRABTYPE_CORE) ? "core" : "xi1"), + dev->name, dev->id); + + client = clients[CLIENT_ID(grab->resource)]; + if (client && GetLocalClientCreds(client, &lcc) != -1) + { + ErrorF(" client pid %ld uid %ld gid %ld\n", + (lcc->fieldsSet & LCC_PID_SET) ? (long) lcc->pid : 0, + (lcc->fieldsSet & LCC_UID_SET) ? (long) lcc->euid : 0, + (lcc->fieldsSet & LCC_GID_SET) ? (long) lcc->egid : 0); + FreeLocalClientCreds(lcc); + } + else + { + ErrorF(" (no client information available)\n"); + } + + /* XXX is this even correct? */ + if (devGrab->sync.other) + ErrorF(" grab ID 0x%lx from paired device\n", + (unsigned long) devGrab->sync.other->resource); + + ErrorF(" at %ld (from %s grab)%s (device %s, state %d)\n", + (unsigned long) devGrab->grabTime.milliseconds, + devGrab->fromPassiveGrab ? "passive" : "active", + devGrab->implicitGrab ? " (implicit)" : "", + devGrab->sync.frozen ? "frozen" : "thawed", + devGrab->sync.state); + + if (grab->grabtype == GRABTYPE_CORE) + { + ErrorF(" core event mask 0x%lx\n", + (unsigned long) grab->eventMask); + } + else if (grab->grabtype == GRABTYPE_XI) + { + ErrorF(" xi1 event mask 0x%lx\n", + devGrab->implicitGrab ? (unsigned long) grab->deviceMask : + (unsigned long) grab->eventMask); + } + else if (grab->grabtype == GRABTYPE_XI2) + { + for (i = 0; i < EMASKSIZE; i++) + { + int print; + print = 0; + for (j = 0; j < XI2MASKSIZE; j++) + { + if (grab->xi2mask[i][j]) + { + print = 1; + break; + } + } + if (!print) + continue; + ErrorF(" xi2 event mask for device %d: 0x", dev->id); + for (j = 0; j < XI2MASKSIZE; j++) + ErrorF("%x", grab->xi2mask[i][j]); + ErrorF("\n"); + } + } + + if (devGrab->fromPassiveGrab) + { + ErrorF(" passive grab type %d, detail 0x%x, " + "activating key %d\n", grab->type, grab->detail.exact, + devGrab->activatingKey); + } + + ErrorF(" owner-events %s, kb %d ptr %d, confine %lx, cursor 0x%lx\n", + grab->ownerEvents ? "true" : "false", + grab->keyboardMode, grab->pointerMode, + grab->confineTo ? (unsigned long) grab->confineTo->drawable.id : 0, + grab->cursor ? (unsigned long) grab->cursor->id : 0); +} + +void +UngrabAllDevices(Bool kill_client) +{ + DeviceIntPtr dev; + ClientPtr client; + + ErrorF("Ungrabbing all devices%s; grabs listed below:\n", + kill_client ? " and killing their owners" : ""); + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!dev->deviceGrab.grab) + continue; + PrintDeviceGrabInfo(dev); + client = clients[CLIENT_ID(dev->deviceGrab.grab->resource)]; + if (!client || client->clientGone) + dev->deviceGrab.DeactivateGrab(dev); + CloseDownClient(client); + } + + ErrorF("End list of ungrabbed devices\n"); +} + +GrabPtr +CreateGrab( + int client, + DeviceIntPtr device, + DeviceIntPtr modDevice, + WindowPtr window, + GrabType grabtype, + GrabMask *mask, + GrabParameters *param, + int type, + KeyCode keybut, /* key or button */ + WindowPtr confineTo, + CursorPtr cursor) +{ + GrabPtr grab; + + grab = calloc(1, sizeof(GrabRec)); + if (!grab) + return (GrabPtr)NULL; + grab->resource = FakeClientID(client); + grab->device = device; + grab->window = window; + grab->eventMask = mask->core; /* same for XI */ + grab->deviceMask = 0; + grab->ownerEvents = param->ownerEvents; + grab->keyboardMode = param->this_device_mode; + grab->pointerMode = param->other_devices_mode; + grab->modifiersDetail.exact = param->modifiers; + grab->modifiersDetail.pMask = NULL; + grab->modifierDevice = modDevice; + grab->type = type; + grab->grabtype = grabtype; + grab->detail.exact = keybut; + grab->detail.pMask = NULL; + grab->confineTo = confineTo; + grab->cursor = cursor; + grab->next = NULL; + + if (grabtype == GRABTYPE_XI2) + memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask)); + if (cursor) + cursor->refcnt++; + return grab; + +} + +static void +FreeGrab(GrabPtr pGrab) +{ + free(pGrab->modifiersDetail.pMask); + free(pGrab->detail.pMask); + + if (pGrab->cursor) + FreeCursor(pGrab->cursor, (Cursor)0); + + free(pGrab); +} + +int +DeletePassiveGrab(pointer value, XID id) +{ + GrabPtr g, prev; + GrabPtr pGrab = (GrabPtr)value; + + /* it is OK if the grab isn't found */ + prev = 0; + for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next) + { + if (pGrab == g) + { + if (prev) + prev->next = g->next; + else + if (!(pGrab->window->optional->passiveGrabs = g->next)) + CheckWindowOptionalNeed (pGrab->window); + break; + } + prev = g; + } + FreeGrab(pGrab); + return Success; +} + +static Mask * +DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail) +{ + Mask *mask; + int i; + + mask = malloc(sizeof(Mask) * MasksPerDetailMask); + if (mask) + { + if (pDetailMask) + for (i = 0; i < MasksPerDetailMask; i++) + mask[i]= pDetailMask[i]; + else + for (i = 0; i < MasksPerDetailMask; i++) + mask[i]= ~0L; + BITCLEAR(mask, detail); + } + return mask; +} + +static Bool +IsInGrabMask( + DetailRec firstDetail, + DetailRec secondDetail, + unsigned int exception) +{ + if (firstDetail.exact == exception) + { + if (firstDetail.pMask == NULL) + return TRUE; + + /* (at present) never called with two non-null pMasks */ + if (secondDetail.exact == exception) + return FALSE; + + if (GETBIT(firstDetail.pMask, secondDetail.exact)) + return TRUE; + } + + return FALSE; +} + +static Bool +IdenticalExactDetails( + unsigned int firstExact, + unsigned int secondExact, + unsigned int exception) +{ + if ((firstExact == exception) || (secondExact == exception)) + return FALSE; + + if (firstExact == secondExact) + return TRUE; + + return FALSE; +} + +static Bool +DetailSupersedesSecond( + DetailRec firstDetail, + DetailRec secondDetail, + unsigned int exception) +{ + if (IsInGrabMask(firstDetail, secondDetail, exception)) + return TRUE; + + if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, + exception)) + return TRUE; + + return FALSE; +} + +static Bool +GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) +{ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; + if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + any_modifier)) + return FALSE; + + if (DetailSupersedesSecond(pFirstGrab->detail, + pSecondGrab->detail, (unsigned int)AnyKey)) + return TRUE; + + return FALSE; +} + +/** + * Compares two grabs and returns TRUE if the first grab matches the second + * grab. + * + * A match is when + * - the devices set for the grab are equal (this is optional). + * - the event types for both grabs are equal. + * - XXX + * + * @param ignoreDevice TRUE if the device settings on the grabs are to be + * ignored. + * @return TRUE if the grabs match or FALSE otherwise. + */ +Bool +GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice) +{ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; + + if (pFirstGrab->grabtype != pSecondGrab->grabtype) + return FALSE; + + if (pFirstGrab->grabtype == GRABTYPE_XI2) + { + if (pFirstGrab->device == inputInfo.all_devices || + pSecondGrab->device == inputInfo.all_devices) + { + /* do nothing */ + } else if (pFirstGrab->device == inputInfo.all_master_devices) + { + if (pSecondGrab->device != inputInfo.all_master_devices && + !IsMaster(pSecondGrab->device)) + return FALSE; + } else if (pSecondGrab->device == inputInfo.all_master_devices) + { + if (pFirstGrab->device != inputInfo.all_master_devices && + !IsMaster(pFirstGrab->device)) + return FALSE; + } else if (pSecondGrab->device != pFirstGrab->device) + return FALSE; + } else if (!ignoreDevice && + ((pFirstGrab->device != pSecondGrab->device) || + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) + return FALSE; + + if (pFirstGrab->type != pSecondGrab->type) + return FALSE; + + if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || + GrabSupersedesSecond(pSecondGrab, pFirstGrab)) + return TRUE; + + if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail, + (unsigned int)AnyKey) + && + DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + any_modifier)) + return TRUE; + + if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail, + (unsigned int)AnyKey) + && + DetailSupersedesSecond(pSecondGrab->modifiersDetail, + pFirstGrab->modifiersDetail, + any_modifier)) + return TRUE; + + return FALSE; +} + +static Bool +GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab) +{ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; + + if (pFirstGrab->grabtype != pSecondGrab->grabtype) + return FALSE; + + if (pFirstGrab->device != pSecondGrab->device || + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || + (pFirstGrab->type != pSecondGrab->type)) + return FALSE; + + if (!(DetailSupersedesSecond(pFirstGrab->detail, + pSecondGrab->detail, + (unsigned int)AnyKey) && + DetailSupersedesSecond(pSecondGrab->detail, + pFirstGrab->detail, + (unsigned int)AnyKey))) + return FALSE; + + + if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + any_modifier) && + DetailSupersedesSecond(pSecondGrab->modifiersDetail, + pFirstGrab->modifiersDetail, + any_modifier))) + return FALSE; + + return TRUE; +} + + +/** + * Prepend the new grab to the list of passive grabs on the window. + * Any previously existing grab that matches the new grab will be removed. + * Adding a new grab that would override another client's grab will result in + * a BadAccess. + * + * @return Success or X error code on failure. + */ +int +AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab) +{ + GrabPtr grab; + Mask access_mode = DixGrabAccess; + int rc; + + for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) + { + if (GrabMatchesSecond(pGrab, grab, FALSE)) + { + if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) + { + FreeGrab(pGrab); + return BadAccess; + } + } + } + + if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode); + if (rc != Success) + return rc; + + /* Remove all grabs that match the new one exactly */ + for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) + { + if (GrabsAreIdentical(pGrab, grab)) + { + DeletePassiveGrabFromList(grab); + break; + } + } + + if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window)) + { + FreeGrab(pGrab); + return BadAlloc; + } + + pGrab->next = pGrab->window->optional->passiveGrabs; + pGrab->window->optional->passiveGrabs = pGrab; + if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab)) + return Success; + return BadAlloc; +} + +/* the following is kinda complicated, because we need to be able to back out + * if any allocation fails + */ + +Bool +DeletePassiveGrabFromList(GrabPtr pMinuendGrab) +{ + GrabPtr grab; + GrabPtr *deletes, *adds; + Mask ***updates, **details; + int i, ndels, nadds, nups; + Bool ok; + unsigned int any_modifier; + unsigned int any_key; + +#define UPDATE(mask,exact) \ + if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \ + ok = FALSE; \ + else \ + updates[nups++] = &(mask) + + i = 0; + for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next) + i++; + if (!i) + return TRUE; + deletes = malloc(i * sizeof(GrabPtr)); + adds = malloc(i * sizeof(GrabPtr)); + updates = malloc(i * sizeof(Mask **)); + details = malloc(i * sizeof(Mask *)); + if (!deletes || !adds || !updates || !details) + { + free(details); + free(updates); + free(adds); + free(deletes); + return FALSE; + } + + any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : (unsigned int)AnyModifier; + any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyKeycode : (unsigned int)AnyKey; + ndels = nadds = nups = 0; + ok = TRUE; + for (grab = wPassiveGrabs(pMinuendGrab->window); + grab && ok; + grab = grab->next) + { + if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) || + !GrabMatchesSecond(grab, pMinuendGrab, + (grab->grabtype == GRABTYPE_CORE))) + continue; + if (GrabSupersedesSecond(pMinuendGrab, grab)) + { + deletes[ndels++] = grab; + } + else if ((grab->detail.exact == any_key) + && (grab->modifiersDetail.exact != any_modifier)) + { + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + } + else if ((grab->modifiersDetail.exact == any_modifier) + && (grab->detail.exact != any_key)) + { + UPDATE(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail.exact); + } + else if ((pMinuendGrab->detail.exact != any_key) + && (pMinuendGrab->modifiersDetail.exact != any_modifier)) + { + GrabPtr pNewGrab; + GrabParameters param; + + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + + memset(¶m, 0, sizeof(param)); + param.ownerEvents = grab->ownerEvents; + param.this_device_mode = grab->keyboardMode; + param.other_devices_mode = grab->pointerMode; + param.modifiers = any_modifier; + + pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device, + grab->modifierDevice, grab->window, + grab->grabtype, + (GrabMask*)&grab->eventMask, + ¶m, (int)grab->type, + pMinuendGrab->detail.exact, + grab->confineTo, grab->cursor); + if (!pNewGrab) + ok = FALSE; + else if (!(pNewGrab->modifiersDetail.pMask = + DeleteDetailFromMask(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail.exact)) + || + (!pNewGrab->window->optional && + !MakeWindowOptional(pNewGrab->window))) + { + FreeGrab(pNewGrab); + ok = FALSE; + } + else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB, + (pointer)pNewGrab)) + ok = FALSE; + else + adds[nadds++] = pNewGrab; + } + else if (pMinuendGrab->detail.exact == any_key) + { + UPDATE(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail.exact); + } + else + { + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + } + } + + if (!ok) + { + for (i = 0; i < nadds; i++) + FreeResource(adds[i]->resource, RT_NONE); + for (i = 0; i < nups; i++) + free(details[i]); + } + else + { + for (i = 0; i < ndels; i++) + FreeResource(deletes[i]->resource, RT_NONE); + for (i = 0; i < nadds; i++) + { + grab = adds[i]; + grab->next = grab->window->optional->passiveGrabs; + grab->window->optional->passiveGrabs = grab; + } + for (i = 0; i < nups; i++) + { + free(*updates[i]); + *updates[i] = details[i]; + } + } + free(details); + free(updates); + free(adds); + free(deletes); + return ok; + +#undef UPDATE +} diff --git a/xorg-server/dix/window.c b/xorg-server/dix/window.c index 5defe5849..556509ac3 100644 --- a/xorg-server/dix/window.c +++ b/xorg-server/dix/window.c @@ -108,6 +108,7 @@ Equipment Corporation. #include "regionstr.h" #include "validate.h" #include "windowstr.h" +#include "propertyst.h" #include "input.h" #include "inputstr.h" #include "resource.h" @@ -124,10 +125,13 @@ Equipment Corporation. #include "dixevents.h" #include "globals.h" #include "mi.h" /* miPaintWindow */ +#include "compint.h" #include "privates.h" #include "xace.h" +#include <X11/Xatom.h> /* must come after server includes */ + /****** * Window stuff for server * @@ -176,46 +180,129 @@ static Bool TileScreenSaver(ScreenPtr pScreen, int kind); #define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent)) -#ifdef DEBUG -/****** - * PrintWindowTree - * For debugging only - ******/ +static const char *overlay_win_name = "<composite overlay>"; -static void -PrintChildren(WindowPtr p1, int indent) +static const char * +get_window_name(WindowPtr pWin) { - WindowPtr p2; - int i; +#define WINDOW_NAME_BUF_LEN 512 + PropertyPtr prop; + CompScreenPtr comp_screen = GetCompScreen(pWin->drawable.pScreen); + static char buf[WINDOW_NAME_BUF_LEN]; + int len; + + if (comp_screen && pWin == comp_screen->pOverlayWin) + return overlay_win_name; - while (p1) + for (prop = wUserProps(pWin); prop; prop = prop->next) { - p2 = p1->firstChild; - ErrorF("[dix] "); - for (i=0; i<indent; i++) ErrorF(" "); - ErrorF("%lx\n", p1->drawable.id); - RegionPrint(&p1->clipList); - PrintChildren(p2, indent+4); - p1 = p1->nextSib; + if (prop->propertyName == XA_WM_NAME && prop->type == XA_STRING && + prop->data) + { + len = min(prop->size, WINDOW_NAME_BUF_LEN - 1); + memcpy(buf, prop->data, len); + buf[len] = '\0'; + return buf; + } } + + return NULL; +#undef WINDOW_NAME_BUF_LEN } -static void -PrintWindowTree(void) +static void log_window_info(WindowPtr pWin, int depth) { int i; - WindowPtr pWin, p1; + const char *win_name, *visibility; + BoxPtr rects; + ScreenPtr pScreen = pWin->drawable.pScreen; + + for (i = 0; i < (depth << 2); i++) + ErrorF(" "); + + win_name = get_window_name(pWin); + ErrorF("win 0x%.8x (%s), [%d, %d] to [%d, %d]", + pWin->drawable.id, + win_name ? win_name : "no name", + pWin->drawable.x, pWin->drawable.y, + pWin->drawable.x + pWin->drawable.width, + pWin->drawable.y + pWin->drawable.height); + + if (pWin->overrideRedirect) + ErrorF(" (override redirect)"); + if (pWin->redirectDraw) + ErrorF(" (%s compositing: pixmap %x)", + (pWin->redirectDraw == RedirectDrawAutomatic) ? + "automatic" : "manual", + pScreen->GetWindowPixmap(pWin)->drawable.id); + + switch (pWin->visibility) + { + case VisibilityUnobscured: + visibility = "unobscured"; + break; + case VisibilityPartiallyObscured: + visibility = "partially obscured"; + break; + case VisibilityFullyObscured: + visibility = "fully obscured"; + break; + case VisibilityNotViewable: + visibility = "unviewable"; + break; + } + ErrorF(", %s", visibility); + + if (REGION_NOTEMPTY(pScreen, &pWin->clipList)) + { + ErrorF(", clip list:"); + rects = REGION_RECTS(&pWin->clipList); + for (i = 0; i < REGION_NUM_RECTS(&pWin->clipList); i++) + ErrorF(" [(%d, %d) to (%d, %d)]", + rects[i].x1, rects[i].y1, + rects[i].x2, rects[i].y2); + ErrorF("; extents [(%d, %d) to (%d, %d)]", + pWin->clipList.extents.x1, pWin->clipList.extents.y1, + pWin->clipList.extents.x2, pWin->clipList.extents.y2); + } + + ErrorF("\n"); +} + +void +PrintWindowTree(void) +{ + int scrnum, depth; + ScreenPtr pScreen; + WindowPtr pWin; - for (i=0; i<screenInfo.numScreens; i++) + for (scrnum = 0; scrnum < screenInfo.numScreens; scrnum++) { - ErrorF("[dix] WINDOW %d\n", i); - pWin = screenInfo.screens[i]->root; - RegionPrint(&pWin->clipList); - p1 = pWin->firstChild; - PrintChildren(p1, 4); + pScreen = screenInfo.screens[scrnum]; + ErrorF("[dix] Dumping windows for screen %d (pixmap %x):\n", scrnum, + pScreen->GetScreenPixmap(pScreen)->drawable.id); + pWin = pScreen->root; + depth = 1; + while (pWin) + { + log_window_info(pWin, depth); + if (pWin->firstChild) + { + pWin = pWin->firstChild; + depth++; + continue; + } + while (pWin && !pWin->nextSib) + { + pWin = pWin->parent; + depth--; + } + if (!pWin) + break; + pWin = pWin->nextSib; + } } } -#endif int TraverseTree(WindowPtr pWin, VisitWindowProcPtr func, pointer data) |