aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/xfixes/cursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/xfixes/cursor.c')
-rw-r--r--xorg-server/xfixes/cursor.c2531
1 files changed, 1464 insertions, 1067 deletions
diff --git a/xorg-server/xfixes/cursor.c b/xorg-server/xfixes/cursor.c
index a039d581d..4eaae2784 100644
--- a/xorg-server/xfixes/cursor.c
+++ b/xorg-server/xfixes/cursor.c
@@ -1,1067 +1,1464 @@
-/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- * Copyright © 2002 Keith Packard
- *
- * 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, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD 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>
-#else
-#define XFIXES
-#endif
-
-#include "xfixesint.h"
-#include "scrnintstr.h"
-#include "cursorstr.h"
-#include "dixevents.h"
-#include "servermd.h"
-#include "inputstr.h"
-#include "windowstr.h"
-#include "xace.h"
-
-static RESTYPE CursorClientType;
-static RESTYPE CursorHideCountType;
-static RESTYPE CursorWindowType;
-static CursorPtr CursorCurrent[MAXDEVICES];
-
-static DevPrivateKeyRec CursorScreenPrivateKeyRec;
-#define CursorScreenPrivateKey (&CursorScreenPrivateKeyRec)
-
-static void deleteCursorHideCountsForScreen (ScreenPtr pScreen);
-
-#define VERIFY_CURSOR(pCursor, cursor, client, access) \
- do { \
- int err; \
- err = dixLookupResourceByType((pointer *) &pCursor, cursor, \
- RT_CURSOR, client, access); \
- if (err != Success) { \
- client->errorValue = cursor; \
- return err; \
- } \
- } while (0)
-
-/*
- * There is a global list of windows selecting for cursor events
- */
-
-typedef struct _CursorEvent *CursorEventPtr;
-
-typedef struct _CursorEvent {
- CursorEventPtr next;
- CARD32 eventMask;
- ClientPtr pClient;
- WindowPtr pWindow;
- XID clientResource;
-} CursorEventRec;
-
-static CursorEventPtr cursorEvents;
-
-/*
- * Each screen has a list of clients which have requested
- * that the cursor be hid, and the number of times each
- * client has requested.
-*/
-
-typedef struct _CursorHideCountRec *CursorHideCountPtr;
-
-typedef struct _CursorHideCountRec {
- CursorHideCountPtr pNext;
- ClientPtr pClient;
- ScreenPtr pScreen;
- int hideCount;
- XID resource;
-} CursorHideCountRec;
-
-/*
- * Wrap DisplayCursor to catch cursor change events
- */
-
-typedef struct _CursorScreen {
- DisplayCursorProcPtr DisplayCursor;
- CloseScreenProcPtr CloseScreen;
- CursorHideCountPtr pCursorHideCounts;
-} CursorScreenRec, *CursorScreenPtr;
-
-#define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey))
-#define GetCursorScreenIfSet(s) GetCursorScreen(s)
-#define SetCursorScreen(s,p) dixSetPrivate(&(s)->devPrivates, CursorScreenPrivateKey, p)
-#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func)
-#define Unwrap(as,s,elt,backup) (((backup) = (s)->elt), (s)->elt = (as)->elt)
-
-/* The cursor doesn't show up until the first XDefineCursor() */
-static Bool CursorVisible = FALSE;
-
-Bool EnableCursor = TRUE;
-
-static Bool
-CursorDisplayCursor (DeviceIntPtr pDev,
- ScreenPtr pScreen,
- CursorPtr pCursor)
-{
- CursorScreenPtr cs = GetCursorScreen(pScreen);
- Bool ret;
- DisplayCursorProcPtr backupProc;
-
- Unwrap (cs, pScreen, DisplayCursor, backupProc);
-
- /*
- * Have to check ConnectionInfo to distinguish client requests from
- * initial root window setup. Not a great way to do it, I admit.
- */
- if (ConnectionInfo)
- CursorVisible = EnableCursor;
-
- if (cs->pCursorHideCounts != NULL || !CursorVisible) {
- ret = (*pScreen->DisplayCursor) (pDev, pScreen, NullCursor);
- } else {
- ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor);
- }
-
- if (pCursor != CursorCurrent[pDev->id])
- {
- CursorEventPtr e;
-
- CursorCurrent[pDev->id] = pCursor;
- for (e = cursorEvents; e; e = e->next)
- {
- if ((e->eventMask & XFixesDisplayCursorNotifyMask))
- {
- xXFixesCursorNotifyEvent ev;
- ev.type = XFixesEventBase + XFixesCursorNotify;
- ev.subtype = XFixesDisplayCursorNotify;
- ev.window = e->pWindow->drawable.id;
- ev.cursorSerial = pCursor->serialNumber;
- ev.timestamp = currentTime.milliseconds;
- ev.name = pCursor->name;
- WriteEventsToClient (e->pClient, 1, (xEvent *) &ev);
- }
- }
- }
- Wrap (cs, pScreen, DisplayCursor, backupProc);
-
- return ret;
-}
-
-static Bool
-CursorCloseScreen (int index, ScreenPtr pScreen)
-{
- CursorScreenPtr cs = GetCursorScreen (pScreen);
- Bool ret;
- CloseScreenProcPtr close_proc;
- DisplayCursorProcPtr display_proc;
-
- Unwrap (cs, pScreen, CloseScreen, close_proc);
- Unwrap (cs, pScreen, DisplayCursor, display_proc);
- deleteCursorHideCountsForScreen(pScreen);
- ret = (*pScreen->CloseScreen) (index, pScreen);
- free(cs);
- return ret;
-}
-
-#define CursorAllEvents (XFixesDisplayCursorNotifyMask)
-
-static int
-XFixesSelectCursorInput (ClientPtr pClient,
- WindowPtr pWindow,
- CARD32 eventMask)
-{
- CursorEventPtr *prev, e;
- pointer val;
- int rc;
-
- for (prev = &cursorEvents; (e = *prev); prev = &e->next)
- {
- if (e->pClient == pClient &&
- e->pWindow == pWindow)
- {
- break;
- }
- }
- if (!eventMask)
- {
- if (e)
- {
- FreeResource (e->clientResource, 0);
- }
- return Success;
- }
- if (!e)
- {
- e = (CursorEventPtr) malloc(sizeof (CursorEventRec));
- if (!e)
- return BadAlloc;
-
- e->next = 0;
- e->pClient = pClient;
- e->pWindow = pWindow;
- e->clientResource = FakeClientID(pClient->index);
-
- /*
- * Add a resource hanging from the window to
- * catch window destroy
- */
- rc = dixLookupResourceByType( &val, pWindow->drawable.id,
- CursorWindowType, serverClient,
- DixGetAttrAccess);
- if (rc != Success)
- if (!AddResource (pWindow->drawable.id, CursorWindowType,
- (pointer) pWindow))
- {
- free(e);
- return BadAlloc;
- }
-
- if (!AddResource (e->clientResource, CursorClientType, (pointer) e))
- return BadAlloc;
-
- *prev = e;
- }
- e->eventMask = eventMask;
- return Success;
-}
-
-int
-ProcXFixesSelectCursorInput (ClientPtr client)
-{
- REQUEST (xXFixesSelectCursorInputReq);
- WindowPtr pWin;
- int rc;
-
- REQUEST_SIZE_MATCH (xXFixesSelectCursorInputReq);
- rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
- if (rc != Success)
- return rc;
- if (stuff->eventMask & ~CursorAllEvents)
- {
- client->errorValue = stuff->eventMask;
- return BadValue;
- }
- return XFixesSelectCursorInput (client, pWin, stuff->eventMask);
-}
-
-static int
-GetBit (unsigned char *line, int x)
-{
- unsigned char mask;
-
- if (screenInfo.bitmapBitOrder == LSBFirst)
- mask = (1 << (x & 7));
- else
- mask = (0x80 >> (x & 7));
- /* XXX assumes byte order is host byte order */
- line += (x >> 3);
- if (*line & mask)
- return 1;
- return 0;
-}
-
-int
-SProcXFixesSelectCursorInput (ClientPtr client)
-{
- register int n;
- REQUEST(xXFixesSelectCursorInputReq);
-
- swaps(&stuff->length, n);
- swapl(&stuff->window, n);
- swapl(&stuff->eventMask, n);
- return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
-}
-
-void
-SXFixesCursorNotifyEvent (xXFixesCursorNotifyEvent *from,
- xXFixesCursorNotifyEvent *to)
-{
- to->type = from->type;
- cpswaps (from->sequenceNumber, to->sequenceNumber);
- cpswapl (from->window, to->window);
- cpswapl (from->cursorSerial, to->cursorSerial);
- cpswapl (from->timestamp, to->timestamp);
- cpswapl (from->name, to->name);
-}
-
-static void
-CopyCursorToImage (CursorPtr pCursor, CARD32 *image)
-{
- int width = pCursor->bits->width;
- int height = pCursor->bits->height;
- int npixels = width * height;
-
-#ifdef ARGB_CURSOR
- if (pCursor->bits->argb)
- memcpy (image, pCursor->bits->argb, npixels * sizeof (CARD32));
- else
-#endif
- {
- unsigned char *srcLine = pCursor->bits->source;
- unsigned char *mskLine = pCursor->bits->mask;
- int stride = BitmapBytePad (width);
- int x, y;
- CARD32 fg, bg;
-
- fg = (0xff000000 |
- ((pCursor->foreRed & 0xff00) << 8) |
- (pCursor->foreGreen & 0xff00) |
- (pCursor->foreBlue >> 8));
- bg = (0xff000000 |
- ((pCursor->backRed & 0xff00) << 8) |
- (pCursor->backGreen & 0xff00) |
- (pCursor->backBlue >> 8));
- for (y = 0; y < height; y++)
- {
- for (x = 0; x < width; x++)
- {
- if (GetBit (mskLine, x))
- {
- if (GetBit (srcLine, x))
- *image++ = fg;
- else
- *image++ = bg;
- }
- else
- *image++ = 0;
- }
- srcLine += stride;
- mskLine += stride;
- }
- }
-}
-
-int
-ProcXFixesGetCursorImage (ClientPtr client)
-{
-/* REQUEST(xXFixesGetCursorImageReq); */
- xXFixesGetCursorImageReply *rep;
- CursorPtr pCursor;
- CARD32 *image;
- int npixels, width, height, rc, x, y;
-
- REQUEST_SIZE_MATCH(xXFixesGetCursorImageReq);
- pCursor = CursorCurrent[PickPointer(client)->id];
- if (!pCursor)
- return BadCursor;
- rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR,
- pCursor, RT_NONE, NULL, DixReadAccess);
- if (rc != Success)
- return rc;
- GetSpritePosition (PickPointer(client), &x, &y);
- width = pCursor->bits->width;
- height = pCursor->bits->height;
- npixels = width * height;
- rep = malloc(sizeof (xXFixesGetCursorImageReply) +
- npixels * sizeof (CARD32));
- if (!rep)
- return BadAlloc;
-
- rep->type = X_Reply;
- rep->sequenceNumber = client->sequence;
- rep->length = npixels;
- rep->width = width;
- rep->height = height;
- rep->x = x;
- rep->y = y;
- rep->xhot = pCursor->bits->xhot;
- rep->yhot = pCursor->bits->yhot;
- rep->cursorSerial = pCursor->serialNumber;
-
- image = (CARD32 *) (rep + 1);
- CopyCursorToImage (pCursor, image);
- if (client->swapped)
- {
- int n;
- swaps (&rep->sequenceNumber, n);
- swapl (&rep->length, n);
- swaps (&rep->x, n);
- swaps (&rep->y, n);
- swaps (&rep->width, n);
- swaps (&rep->height, n);
- swaps (&rep->xhot, n);
- swaps (&rep->yhot, n);
- swapl (&rep->cursorSerial, n);
- SwapLongs (image, npixels);
- }
- WriteToClient(client, sizeof (xXFixesGetCursorImageReply) +
- (npixels << 2), (char *) rep);
- free(rep);
- return Success;
-}
-
-int
-SProcXFixesGetCursorImage (ClientPtr client)
-{
- int n;
- REQUEST(xXFixesGetCursorImageReq);
- swaps (&stuff->length, n);
- return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
-}
-
-int
-ProcXFixesSetCursorName (ClientPtr client)
-{
- CursorPtr pCursor;
- char *tchar;
- REQUEST(xXFixesSetCursorNameReq);
- Atom atom;
-
- REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq);
- VERIFY_CURSOR(pCursor, stuff->cursor, client, DixSetAttrAccess);
- tchar = (char *) &stuff[1];
- atom = MakeAtom (tchar, stuff->nbytes, TRUE);
- if (atom == BAD_RESOURCE)
- return BadAlloc;
-
- pCursor->name = atom;
- return Success;
-}
-
-int
-SProcXFixesSetCursorName (ClientPtr client)
-{
- int n;
- REQUEST(xXFixesSetCursorNameReq);
-
- swaps (&stuff->length, n);
- REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq);
- swapl (&stuff->cursor, n);
- swaps (&stuff->nbytes, n);
- return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
-}
-
-int
-ProcXFixesGetCursorName (ClientPtr client)
-{
- CursorPtr pCursor;
- xXFixesGetCursorNameReply reply;
- REQUEST(xXFixesGetCursorNameReq);
- const char *str;
- int len;
-
- REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq);
- VERIFY_CURSOR(pCursor, stuff->cursor, client, DixGetAttrAccess);
- if (pCursor->name)
- str = NameForAtom (pCursor->name);
- else
- str = "";
- len = strlen (str);
-
- reply.type = X_Reply;
- reply.length = bytes_to_int32(len);
- reply.sequenceNumber = client->sequence;
- reply.atom = pCursor->name;
- reply.nbytes = len;
- if (client->swapped)
- {
- int n;
- swaps (&reply.sequenceNumber, n);
- swapl (&reply.length, n);
- swapl (&reply.atom, n);
- swaps (&reply.nbytes, n);
- }
- WriteReplyToClient(client, sizeof(xXFixesGetCursorNameReply), &reply);
- WriteToClient(client, len, str);
-
- return Success;
-}
-
-int
-SProcXFixesGetCursorName (ClientPtr client)
-{
- int n;
- REQUEST(xXFixesGetCursorNameReq);
-
- swaps (&stuff->length, n);
- REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq);
- swapl (&stuff->cursor, n);
- return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
-}
-
-int
-ProcXFixesGetCursorImageAndName (ClientPtr client)
-{
-/* REQUEST(xXFixesGetCursorImageAndNameReq); */
- xXFixesGetCursorImageAndNameReply *rep;
- CursorPtr pCursor;
- CARD32 *image;
- int npixels;
- const char *name;
- int nbytes, nbytesRound;
- int width, height;
- int rc, x, y;
-
- REQUEST_SIZE_MATCH(xXFixesGetCursorImageAndNameReq);
- pCursor = CursorCurrent[PickPointer(client)->id];
- if (!pCursor)
- return BadCursor;
- rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR,
- pCursor, RT_NONE, NULL, DixReadAccess|DixGetAttrAccess);
- if (rc != Success)
- return rc;
- GetSpritePosition (PickPointer(client), &x, &y);
- width = pCursor->bits->width;
- height = pCursor->bits->height;
- npixels = width * height;
- name = pCursor->name ? NameForAtom (pCursor->name) : "";
- nbytes = strlen (name);
- nbytesRound = pad_to_int32(nbytes);
- rep = malloc(sizeof (xXFixesGetCursorImageAndNameReply) +
- npixels * sizeof (CARD32) + nbytesRound);
- if (!rep)
- return BadAlloc;
-
- rep->type = X_Reply;
- rep->sequenceNumber = client->sequence;
- rep->length = npixels + bytes_to_int32(nbytesRound);
- rep->width = width;
- rep->height = height;
- rep->x = x;
- rep->y = y;
- rep->xhot = pCursor->bits->xhot;
- rep->yhot = pCursor->bits->yhot;
- rep->cursorSerial = pCursor->serialNumber;
- rep->cursorName = pCursor->name;
- rep->nbytes = nbytes;
-
- image = (CARD32 *) (rep + 1);
- CopyCursorToImage (pCursor, image);
- memcpy ((image + npixels), name, nbytes);
- if (client->swapped)
- {
- int n;
- swaps (&rep->sequenceNumber, n);
- swapl (&rep->length, n);
- swaps (&rep->x, n);
- swaps (&rep->y, n);
- swaps (&rep->width, n);
- swaps (&rep->height, n);
- swaps (&rep->xhot, n);
- swaps (&rep->yhot, n);
- swapl (&rep->cursorSerial, n);
- swapl (&rep->cursorName, n);
- swaps (&rep->nbytes, n);
- SwapLongs (image, npixels);
- }
- WriteToClient(client, sizeof (xXFixesGetCursorImageAndNameReply) +
- (npixels << 2) + nbytesRound, (char *) rep);
- free(rep);
- return Success;
-}
-
-int
-SProcXFixesGetCursorImageAndName (ClientPtr client)
-{
- int n;
- REQUEST(xXFixesGetCursorImageAndNameReq);
- swaps (&stuff->length, n);
- return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
-}
-
-/*
- * Find every cursor reference in the system, ask testCursor
- * whether it should be replaced with a reference to pCursor.
- */
-
-typedef Bool (*TestCursorFunc) (CursorPtr pOld, pointer closure);
-
-typedef struct {
- RESTYPE type;
- TestCursorFunc testCursor;
- CursorPtr pNew;
- pointer closure;
-} ReplaceCursorLookupRec, *ReplaceCursorLookupPtr;
-
-static const RESTYPE CursorRestypes[] = {
- RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR
-};
-
-#define NUM_CURSOR_RESTYPES (sizeof (CursorRestypes) / sizeof (CursorRestypes[0]))
-
-static Bool
-ReplaceCursorLookup (pointer value, XID id, pointer closure)
-{
- ReplaceCursorLookupPtr rcl = (ReplaceCursorLookupPtr) closure;
- WindowPtr pWin;
- GrabPtr pGrab;
- CursorPtr pCursor = 0, *pCursorRef = 0;
- XID cursor = 0;
-
- switch (rcl->type) {
- case RT_WINDOW:
- pWin = (WindowPtr) value;
- if (pWin->optional)
- {
- pCursorRef = &pWin->optional->cursor;
- pCursor = *pCursorRef;
- }
- break;
- case RT_PASSIVEGRAB:
- pGrab = (GrabPtr) value;
- pCursorRef = &pGrab->cursor;
- pCursor = *pCursorRef;
- break;
- case RT_CURSOR:
- pCursorRef = 0;
- pCursor = (CursorPtr) value;
- cursor = id;
- break;
- }
- if (pCursor && pCursor != rcl->pNew)
- {
- if ((*rcl->testCursor) (pCursor, rcl->closure))
- {
- rcl->pNew->refcnt++;
- /* either redirect reference or update resource database */
- if (pCursorRef)
- *pCursorRef = rcl->pNew;
- else
- ChangeResourceValue (id, RT_CURSOR, rcl->pNew);
- FreeCursor (pCursor, cursor);
- }
- }
- return FALSE; /* keep walking */
-}
-
-static void
-ReplaceCursor (CursorPtr pCursor,
- TestCursorFunc testCursor,
- pointer closure)
-{
- int clientIndex;
- int resIndex;
- ReplaceCursorLookupRec rcl;
-
- /*
- * Cursors exist only in the resource database, windows and grabs.
- * All of these are always pointed at by the resource database. Walk
- * the whole thing looking for cursors
- */
- rcl.testCursor = testCursor;
- rcl.pNew = pCursor;
- rcl.closure = closure;
-
- /* for each client */
- for (clientIndex = 0; clientIndex < currentMaxClients; clientIndex++)
- {
- if (!clients[clientIndex])
- continue;
- for (resIndex = 0; resIndex < NUM_CURSOR_RESTYPES; resIndex++)
- {
- rcl.type = CursorRestypes[resIndex];
- /*
- * This function walks the entire client resource database
- */
- LookupClientResourceComplex (clients[clientIndex],
- rcl.type,
- ReplaceCursorLookup,
- (pointer) &rcl);
- }
- }
- /* this "knows" that WindowHasNewCursor doesn't depend on it's argument */
- WindowHasNewCursor (screenInfo.screens[0]->root);
-}
-
-static Bool
-TestForCursor (CursorPtr pCursor, pointer closure)
-{
- return (pCursor == (CursorPtr) closure);
-}
-
-int
-ProcXFixesChangeCursor (ClientPtr client)
-{
- CursorPtr pSource, pDestination;
- REQUEST(xXFixesChangeCursorReq);
-
- REQUEST_SIZE_MATCH(xXFixesChangeCursorReq);
- VERIFY_CURSOR (pSource, stuff->source, client,
- DixReadAccess|DixGetAttrAccess);
- VERIFY_CURSOR (pDestination, stuff->destination, client,
- DixWriteAccess|DixSetAttrAccess);
-
- ReplaceCursor (pSource, TestForCursor, (pointer) pDestination);
- return Success;
-}
-
-int
-SProcXFixesChangeCursor (ClientPtr client)
-{
- int n;
- REQUEST(xXFixesChangeCursorReq);
-
- swaps (&stuff->length, n);
- REQUEST_SIZE_MATCH(xXFixesChangeCursorReq);
- swapl (&stuff->source, n);
- swapl (&stuff->destination, n);
- return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
-}
-
-static Bool
-TestForCursorName (CursorPtr pCursor, pointer closure)
-{
- Atom *pName = closure;
- return pCursor->name == *pName;
-}
-
-int
-ProcXFixesChangeCursorByName (ClientPtr client)
-{
- CursorPtr pSource;
- Atom name;
- char *tchar;
- REQUEST(xXFixesChangeCursorByNameReq);
-
- REQUEST_FIXED_SIZE(xXFixesChangeCursorByNameReq, stuff->nbytes);
- VERIFY_CURSOR(pSource, stuff->source, client,
- DixReadAccess|DixGetAttrAccess);
- tchar = (char *) &stuff[1];
- name = MakeAtom (tchar, stuff->nbytes, FALSE);
- if (name)
- ReplaceCursor (pSource, TestForCursorName, &name);
- return Success;
-}
-
-int
-SProcXFixesChangeCursorByName (ClientPtr client)
-{
- int n;
- REQUEST(xXFixesChangeCursorByNameReq);
-
- swaps (&stuff->length, n);
- REQUEST_AT_LEAST_SIZE (xXFixesChangeCursorByNameReq);
- swapl (&stuff->source, n);
- swaps (&stuff->nbytes, n);
- return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
-}
-
-/*
- * Routines for manipulating the per-screen hide counts list.
- * This list indicates which clients have requested cursor hiding
- * for that screen.
- */
-
-/* Return the screen's hide-counts list element for the given client */
-static CursorHideCountPtr
-findCursorHideCount (ClientPtr pClient, ScreenPtr pScreen)
-{
- CursorScreenPtr cs = GetCursorScreen(pScreen);
- CursorHideCountPtr pChc;
-
- for (pChc = cs->pCursorHideCounts; pChc != NULL; pChc = pChc->pNext) {
- if (pChc->pClient == pClient) {
- return pChc;
- }
- }
-
- return NULL;
-}
-
-static int
-createCursorHideCount (ClientPtr pClient, ScreenPtr pScreen)
-{
- CursorScreenPtr cs = GetCursorScreen(pScreen);
- CursorHideCountPtr pChc;
-
- pChc = (CursorHideCountPtr) malloc(sizeof(CursorHideCountRec));
- if (pChc == NULL) {
- return BadAlloc;
- }
- pChc->pClient = pClient;
- pChc->pScreen = pScreen;
- pChc->hideCount = 1;
- pChc->resource = FakeClientID(pClient->index);
- pChc->pNext = cs->pCursorHideCounts;
- cs->pCursorHideCounts = pChc;
-
- /*
- * Create a resource for this element so it can be deleted
- * when the client goes away.
- */
- if (!AddResource (pChc->resource, CursorHideCountType,
- (pointer) pChc)) {
- free(pChc);
- return BadAlloc;
- }
-
- return Success;
-}
-
-/*
- * Delete the given hide-counts list element from its screen list.
- */
-static void
-deleteCursorHideCount (CursorHideCountPtr pChcToDel, ScreenPtr pScreen)
-{
- CursorScreenPtr cs = GetCursorScreen(pScreen);
- CursorHideCountPtr pChc, pNext;
- CursorHideCountPtr pChcLast = NULL;
-
- pChc = cs->pCursorHideCounts;
- while (pChc != NULL) {
- pNext = pChc->pNext;
- if (pChc == pChcToDel) {
- free(pChc);
- if (pChcLast == NULL) {
- cs->pCursorHideCounts = pNext;
- } else {
- pChcLast->pNext = pNext;
- }
- return;
- }
- pChcLast = pChc;
- pChc = pNext;
- }
-}
-
-/*
- * Delete all the hide-counts list elements for this screen.
- */
-static void
-deleteCursorHideCountsForScreen (ScreenPtr pScreen)
-{
- CursorScreenPtr cs = GetCursorScreen(pScreen);
- CursorHideCountPtr pChc, pTmp;
-
- pChc = cs->pCursorHideCounts;
- while (pChc != NULL) {
- pTmp = pChc->pNext;
- FreeResource(pChc->resource, 0);
- pChc = pTmp;
- }
- cs->pCursorHideCounts = NULL;
-}
-
-int
-ProcXFixesHideCursor (ClientPtr client)
-{
- WindowPtr pWin;
- CursorHideCountPtr pChc;
- REQUEST(xXFixesHideCursorReq);
- int ret;
-
- REQUEST_SIZE_MATCH (xXFixesHideCursorReq);
-
- ret = dixLookupResourceByType((pointer *)&pWin, stuff->window, RT_WINDOW,
- client, DixGetAttrAccess);
- if (ret != Success) {
- client->errorValue = stuff->window;
- return ret;
- }
-
- /*
- * Has client hidden the cursor before on this screen?
- * If so, just increment the count.
- */
-
- pChc = findCursorHideCount(client, pWin->drawable.pScreen);
- if (pChc != NULL) {
- pChc->hideCount++;
- return Success;
- }
-
- /*
- * This is the first time this client has hid the cursor
- * for this screen.
- */
- ret = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen,
- DixHideAccess);
- if (ret != Success)
- return ret;
-
- ret = createCursorHideCount(client, pWin->drawable.pScreen);
-
- if (ret == Success) {
- DeviceIntPtr dev;
- for (dev = inputInfo.devices; dev; dev = dev->next)
- {
- if (IsMaster(dev) && IsPointerDevice(dev))
- CursorDisplayCursor(dev, pWin->drawable.pScreen, CursorCurrent[dev->id]);
- }
- }
-
- return ret;
-}
-
-int
-SProcXFixesHideCursor (ClientPtr client)
-{
- int n;
- REQUEST(xXFixesHideCursorReq);
-
- swaps (&stuff->length, n);
- REQUEST_SIZE_MATCH (xXFixesHideCursorReq);
- swapl (&stuff->window, n);
- return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
-}
-
-int
-ProcXFixesShowCursor (ClientPtr client)
-{
- WindowPtr pWin;
- CursorHideCountPtr pChc;
- int rc;
- REQUEST(xXFixesShowCursorReq);
-
- REQUEST_SIZE_MATCH (xXFixesShowCursorReq);
-
- rc = dixLookupResourceByType((pointer *)&pWin, stuff->window, RT_WINDOW,
- client, DixGetAttrAccess);
- if (rc != Success) {
- client->errorValue = stuff->window;
- return rc;
- }
-
- /*
- * Has client hidden the cursor on this screen?
- * If not, generate an error.
- */
- pChc = findCursorHideCount(client, pWin->drawable.pScreen);
- if (pChc == NULL) {
- return BadMatch;
- }
-
- rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen,
- DixShowAccess);
- if (rc != Success)
- return rc;
-
- pChc->hideCount--;
- if (pChc->hideCount <= 0) {
- FreeResource(pChc->resource, 0);
- }
-
- return Success;
-}
-
-int
-SProcXFixesShowCursor (ClientPtr client)
-{
- int n;
- REQUEST(xXFixesShowCursorReq);
-
- swaps (&stuff->length, n);
- REQUEST_SIZE_MATCH (xXFixesShowCursorReq);
- swapl (&stuff->window, n);
- return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
-}
-
-static int
-CursorFreeClient (pointer data, XID id)
-{
- CursorEventPtr old = (CursorEventPtr) data;
- CursorEventPtr *prev, e;
-
- for (prev = &cursorEvents; (e = *prev); prev = &e->next)
- {
- if (e == old)
- {
- *prev = e->next;
- free(e);
- break;
- }
- }
- return 1;
-}
-
-static int
-CursorFreeHideCount (pointer data, XID id)
-{
- CursorHideCountPtr pChc = (CursorHideCountPtr) data;
- ScreenPtr pScreen = pChc->pScreen;
- DeviceIntPtr dev;
-
- deleteCursorHideCount(pChc, pChc->pScreen);
- for (dev = inputInfo.devices; dev; dev = dev->next)
- {
- if (IsMaster(dev) && IsPointerDevice(dev))
- CursorDisplayCursor(dev, pScreen, CursorCurrent[dev->id]);
- }
-
- return 1;
-}
-
-static int
-CursorFreeWindow (pointer data, XID id)
-{
- WindowPtr pWindow = (WindowPtr) data;
- CursorEventPtr e, next;
-
- for (e = cursorEvents; e; e = next)
- {
- next = e->next;
- if (e->pWindow == pWindow)
- {
- FreeResource (e->clientResource, 0);
- }
- }
- return 1;
-}
-
-Bool
-XFixesCursorInit (void)
-{
- int i;
-
- if (party_like_its_1989)
- CursorVisible = EnableCursor;
-
- if (!dixRegisterPrivateKey(&CursorScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
- return FALSE;
-
- for (i = 0; i < screenInfo.numScreens; i++)
- {
- ScreenPtr pScreen = screenInfo.screens[i];
- CursorScreenPtr cs;
-
- cs = (CursorScreenPtr) calloc(1, sizeof (CursorScreenRec));
- if (!cs)
- return FALSE;
- Wrap (cs, pScreen, CloseScreen, CursorCloseScreen);
- Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor);
- cs->pCursorHideCounts = NULL;
- SetCursorScreen (pScreen, cs);
- }
- CursorClientType = CreateNewResourceType(CursorFreeClient,
- "XFixesCursorClient");
- CursorHideCountType = CreateNewResourceType(CursorFreeHideCount,
- "XFixesCursorHideCount");
- CursorWindowType = CreateNewResourceType(CursorFreeWindow,
- "XFixesCursorWindow");
-
- return CursorClientType && CursorHideCountType && CursorWindowType;
-}
-
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Copyright © 2002 Keith Packard
+ *
+ * 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, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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>
+#else
+#define XFIXES
+#endif
+
+#include "xfixesint.h"
+#include "scrnintstr.h"
+#include "cursorstr.h"
+#include "dixevents.h"
+#include "servermd.h"
+#include "mipointer.h"
+#include "inputstr.h"
+#include "windowstr.h"
+#include "xace.h"
+#include "list.h"
+
+static RESTYPE CursorClientType;
+static RESTYPE CursorHideCountType;
+static RESTYPE CursorWindowType;
+RESTYPE PointerBarrierType;
+static CursorPtr CursorCurrent[MAXDEVICES];
+
+static DevPrivateKeyRec CursorScreenPrivateKeyRec;
+#define CursorScreenPrivateKey (&CursorScreenPrivateKeyRec)
+
+static void deleteCursorHideCountsForScreen (ScreenPtr pScreen);
+
+#define VERIFY_CURSOR(pCursor, cursor, client, access) \
+ do { \
+ int err; \
+ err = dixLookupResourceByType((pointer *) &pCursor, cursor, \
+ RT_CURSOR, client, access); \
+ if (err != Success) { \
+ client->errorValue = cursor; \
+ return err; \
+ } \
+ } while (0)
+
+/*
+ * There is a global list of windows selecting for cursor events
+ */
+
+typedef struct _CursorEvent *CursorEventPtr;
+
+typedef struct _CursorEvent {
+ CursorEventPtr next;
+ CARD32 eventMask;
+ ClientPtr pClient;
+ WindowPtr pWindow;
+ XID clientResource;
+} CursorEventRec;
+
+static CursorEventPtr cursorEvents;
+
+/*
+ * Each screen has a list of clients which have requested
+ * that the cursor be hid, and the number of times each
+ * client has requested.
+*/
+
+typedef struct _CursorHideCountRec *CursorHideCountPtr;
+
+typedef struct _CursorHideCountRec {
+ CursorHideCountPtr pNext;
+ ClientPtr pClient;
+ ScreenPtr pScreen;
+ int hideCount;
+ XID resource;
+} CursorHideCountRec;
+
+typedef struct PointerBarrierClient *PointerBarrierClientPtr;
+
+struct PointerBarrierClient {
+ ScreenPtr screen;
+ struct PointerBarrier barrier;
+ struct list entry;
+};
+
+/*
+ * Wrap DisplayCursor to catch cursor change events
+ */
+
+typedef struct _CursorScreen {
+ DisplayCursorProcPtr DisplayCursor;
+ CloseScreenProcPtr CloseScreen;
+ ConstrainCursorHarderProcPtr ConstrainCursorHarder;
+ CursorHideCountPtr pCursorHideCounts;
+ struct list barriers;
+} CursorScreenRec, *CursorScreenPtr;
+
+#define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey))
+#define GetCursorScreenIfSet(s) GetCursorScreen(s)
+#define SetCursorScreen(s,p) dixSetPrivate(&(s)->devPrivates, CursorScreenPrivateKey, p)
+#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func)
+#define Unwrap(as,s,elt,backup) (((backup) = (s)->elt), (s)->elt = (as)->elt)
+
+/* The cursor doesn't show up until the first XDefineCursor() */
+static Bool CursorVisible = FALSE;
+
+Bool EnableCursor = TRUE;
+
+static Bool
+CursorDisplayCursor (DeviceIntPtr pDev,
+ ScreenPtr pScreen,
+ CursorPtr pCursor)
+{
+ CursorScreenPtr cs = GetCursorScreen(pScreen);
+ Bool ret;
+ DisplayCursorProcPtr backupProc;
+
+ Unwrap (cs, pScreen, DisplayCursor, backupProc);
+
+ /*
+ * Have to check ConnectionInfo to distinguish client requests from
+ * initial root window setup. Not a great way to do it, I admit.
+ */
+ if (ConnectionInfo)
+ CursorVisible = EnableCursor;
+
+ if (cs->pCursorHideCounts != NULL || !CursorVisible) {
+ ret = (*pScreen->DisplayCursor) (pDev, pScreen, NullCursor);
+ } else {
+ ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor);
+ }
+
+ if (pCursor != CursorCurrent[pDev->id])
+ {
+ CursorEventPtr e;
+
+ CursorCurrent[pDev->id] = pCursor;
+ for (e = cursorEvents; e; e = e->next)
+ {
+ if ((e->eventMask & XFixesDisplayCursorNotifyMask))
+ {
+ xXFixesCursorNotifyEvent ev;
+ ev.type = XFixesEventBase + XFixesCursorNotify;
+ ev.subtype = XFixesDisplayCursorNotify;
+ ev.window = e->pWindow->drawable.id;
+ ev.cursorSerial = pCursor->serialNumber;
+ ev.timestamp = currentTime.milliseconds;
+ ev.name = pCursor->name;
+ WriteEventsToClient (e->pClient, 1, (xEvent *) &ev);
+ }
+ }
+ }
+ Wrap (cs, pScreen, DisplayCursor, backupProc);
+
+ return ret;
+}
+
+static Bool
+CursorCloseScreen (int index, ScreenPtr pScreen)
+{
+ CursorScreenPtr cs = GetCursorScreen (pScreen);
+ Bool ret;
+ CloseScreenProcPtr close_proc;
+ DisplayCursorProcPtr display_proc;
+ ConstrainCursorHarderProcPtr constrain_proc;
+
+ Unwrap (cs, pScreen, CloseScreen, close_proc);
+ Unwrap (cs, pScreen, DisplayCursor, display_proc);
+ Unwrap (cs, pScreen, ConstrainCursorHarder, constrain_proc);
+ deleteCursorHideCountsForScreen(pScreen);
+ ret = (*pScreen->CloseScreen) (index, pScreen);
+ free(cs);
+ return ret;
+}
+
+#define CursorAllEvents (XFixesDisplayCursorNotifyMask)
+
+static int
+XFixesSelectCursorInput (ClientPtr pClient,
+ WindowPtr pWindow,
+ CARD32 eventMask)
+{
+ CursorEventPtr *prev, e;
+ pointer val;
+ int rc;
+
+ for (prev = &cursorEvents; (e = *prev); prev = &e->next)
+ {
+ if (e->pClient == pClient &&
+ e->pWindow == pWindow)
+ {
+ break;
+ }
+ }
+ if (!eventMask)
+ {
+ if (e)
+ {
+ FreeResource (e->clientResource, 0);
+ }
+ return Success;
+ }
+ if (!e)
+ {
+ e = (CursorEventPtr) malloc(sizeof (CursorEventRec));
+ if (!e)
+ return BadAlloc;
+
+ e->next = 0;
+ e->pClient = pClient;
+ e->pWindow = pWindow;
+ e->clientResource = FakeClientID(pClient->index);
+
+ /*
+ * Add a resource hanging from the window to
+ * catch window destroy
+ */
+ rc = dixLookupResourceByType( &val, pWindow->drawable.id,
+ CursorWindowType, serverClient,
+ DixGetAttrAccess);
+ if (rc != Success)
+ if (!AddResource (pWindow->drawable.id, CursorWindowType,
+ (pointer) pWindow))
+ {
+ free(e);
+ return BadAlloc;
+ }
+
+ if (!AddResource (e->clientResource, CursorClientType, (pointer) e))
+ return BadAlloc;
+
+ *prev = e;
+ }
+ e->eventMask = eventMask;
+ return Success;
+}
+
+int
+ProcXFixesSelectCursorInput (ClientPtr client)
+{
+ REQUEST (xXFixesSelectCursorInputReq);
+ WindowPtr pWin;
+ int rc;
+
+ REQUEST_SIZE_MATCH (xXFixesSelectCursorInputReq);
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ if (stuff->eventMask & ~CursorAllEvents)
+ {
+ client->errorValue = stuff->eventMask;
+ return BadValue;
+ }
+ return XFixesSelectCursorInput (client, pWin, stuff->eventMask);
+}
+
+static int
+GetBit (unsigned char *line, int x)
+{
+ unsigned char mask;
+
+ if (screenInfo.bitmapBitOrder == LSBFirst)
+ mask = (1 << (x & 7));
+ else
+ mask = (0x80 >> (x & 7));
+ /* XXX assumes byte order is host byte order */
+ line += (x >> 3);
+ if (*line & mask)
+ return 1;
+ return 0;
+}
+
+int
+SProcXFixesSelectCursorInput (ClientPtr client)
+{
+ register int n;
+ REQUEST(xXFixesSelectCursorInputReq);
+
+ swaps(&stuff->length, n);
+ swapl(&stuff->window, n);
+ swapl(&stuff->eventMask, n);
+ return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
+}
+
+void
+SXFixesCursorNotifyEvent (xXFixesCursorNotifyEvent *from,
+ xXFixesCursorNotifyEvent *to)
+{
+ to->type = from->type;
+ cpswaps (from->sequenceNumber, to->sequenceNumber);
+ cpswapl (from->window, to->window);
+ cpswapl (from->cursorSerial, to->cursorSerial);
+ cpswapl (from->timestamp, to->timestamp);
+ cpswapl (from->name, to->name);
+}
+
+static void
+CopyCursorToImage (CursorPtr pCursor, CARD32 *image)
+{
+ int width = pCursor->bits->width;
+ int height = pCursor->bits->height;
+ int npixels = width * height;
+
+#ifdef ARGB_CURSOR
+ if (pCursor->bits->argb)
+ memcpy (image, pCursor->bits->argb, npixels * sizeof (CARD32));
+ else
+#endif
+ {
+ unsigned char *srcLine = pCursor->bits->source;
+ unsigned char *mskLine = pCursor->bits->mask;
+ int stride = BitmapBytePad (width);
+ int x, y;
+ CARD32 fg, bg;
+
+ fg = (0xff000000 |
+ ((pCursor->foreRed & 0xff00) << 8) |
+ (pCursor->foreGreen & 0xff00) |
+ (pCursor->foreBlue >> 8));
+ bg = (0xff000000 |
+ ((pCursor->backRed & 0xff00) << 8) |
+ (pCursor->backGreen & 0xff00) |
+ (pCursor->backBlue >> 8));
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x++)
+ {
+ if (GetBit (mskLine, x))
+ {
+ if (GetBit (srcLine, x))
+ *image++ = fg;
+ else
+ *image++ = bg;
+ }
+ else
+ *image++ = 0;
+ }
+ srcLine += stride;
+ mskLine += stride;
+ }
+ }
+}
+
+int
+ProcXFixesGetCursorImage (ClientPtr client)
+{
+/* REQUEST(xXFixesGetCursorImageReq); */
+ xXFixesGetCursorImageReply *rep;
+ CursorPtr pCursor;
+ CARD32 *image;
+ int npixels, width, height, rc, x, y;
+
+ REQUEST_SIZE_MATCH(xXFixesGetCursorImageReq);
+ pCursor = CursorCurrent[PickPointer(client)->id];
+ if (!pCursor)
+ return BadCursor;
+ rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR,
+ pCursor, RT_NONE, NULL, DixReadAccess);
+ if (rc != Success)
+ return rc;
+ GetSpritePosition (PickPointer(client), &x, &y);
+ width = pCursor->bits->width;
+ height = pCursor->bits->height;
+ npixels = width * height;
+ rep = malloc(sizeof (xXFixesGetCursorImageReply) +
+ npixels * sizeof (CARD32));
+ if (!rep)
+ return BadAlloc;
+
+ rep->type = X_Reply;
+ rep->sequenceNumber = client->sequence;
+ rep->length = npixels;
+ rep->width = width;
+ rep->height = height;
+ rep->x = x;
+ rep->y = y;
+ rep->xhot = pCursor->bits->xhot;
+ rep->yhot = pCursor->bits->yhot;
+ rep->cursorSerial = pCursor->serialNumber;
+
+ image = (CARD32 *) (rep + 1);
+ CopyCursorToImage (pCursor, image);
+ if (client->swapped)
+ {
+ int n;
+ swaps (&rep->sequenceNumber, n);
+ swapl (&rep->length, n);
+ swaps (&rep->x, n);
+ swaps (&rep->y, n);
+ swaps (&rep->width, n);
+ swaps (&rep->height, n);
+ swaps (&rep->xhot, n);
+ swaps (&rep->yhot, n);
+ swapl (&rep->cursorSerial, n);
+ SwapLongs (image, npixels);
+ }
+ WriteToClient(client, sizeof (xXFixesGetCursorImageReply) +
+ (npixels << 2), (char *) rep);
+ free(rep);
+ return Success;
+}
+
+int
+SProcXFixesGetCursorImage (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesGetCursorImageReq);
+ swaps (&stuff->length, n);
+ return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
+}
+
+int
+ProcXFixesSetCursorName (ClientPtr client)
+{
+ CursorPtr pCursor;
+ char *tchar;
+ REQUEST(xXFixesSetCursorNameReq);
+ Atom atom;
+
+ REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq);
+ VERIFY_CURSOR(pCursor, stuff->cursor, client, DixSetAttrAccess);
+ tchar = (char *) &stuff[1];
+ atom = MakeAtom (tchar, stuff->nbytes, TRUE);
+ if (atom == BAD_RESOURCE)
+ return BadAlloc;
+
+ pCursor->name = atom;
+ return Success;
+}
+
+int
+SProcXFixesSetCursorName (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesSetCursorNameReq);
+
+ swaps (&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq);
+ swapl (&stuff->cursor, n);
+ swaps (&stuff->nbytes, n);
+ return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
+}
+
+int
+ProcXFixesGetCursorName (ClientPtr client)
+{
+ CursorPtr pCursor;
+ xXFixesGetCursorNameReply reply;
+ REQUEST(xXFixesGetCursorNameReq);
+ const char *str;
+ int len;
+
+ REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq);
+ VERIFY_CURSOR(pCursor, stuff->cursor, client, DixGetAttrAccess);
+ if (pCursor->name)
+ str = NameForAtom (pCursor->name);
+ else
+ str = "";
+ len = strlen (str);
+
+ reply.type = X_Reply;
+ reply.length = bytes_to_int32(len);
+ reply.sequenceNumber = client->sequence;
+ reply.atom = pCursor->name;
+ reply.nbytes = len;
+ if (client->swapped)
+ {
+ int n;
+ swaps (&reply.sequenceNumber, n);
+ swapl (&reply.length, n);
+ swapl (&reply.atom, n);
+ swaps (&reply.nbytes, n);
+ }
+ WriteReplyToClient(client, sizeof(xXFixesGetCursorNameReply), &reply);
+ WriteToClient(client, len, str);
+
+ return Success;
+}
+
+int
+SProcXFixesGetCursorName (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesGetCursorNameReq);
+
+ swaps (&stuff->length, n);
+ REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq);
+ swapl (&stuff->cursor, n);
+ return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
+}
+
+int
+ProcXFixesGetCursorImageAndName (ClientPtr client)
+{
+/* REQUEST(xXFixesGetCursorImageAndNameReq); */
+ xXFixesGetCursorImageAndNameReply *rep;
+ CursorPtr pCursor;
+ CARD32 *image;
+ int npixels;
+ const char *name;
+ int nbytes, nbytesRound;
+ int width, height;
+ int rc, x, y;
+
+ REQUEST_SIZE_MATCH(xXFixesGetCursorImageAndNameReq);
+ pCursor = CursorCurrent[PickPointer(client)->id];
+ if (!pCursor)
+ return BadCursor;
+ rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR,
+ pCursor, RT_NONE, NULL, DixReadAccess|DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ GetSpritePosition (PickPointer(client), &x, &y);
+ width = pCursor->bits->width;
+ height = pCursor->bits->height;
+ npixels = width * height;
+ name = pCursor->name ? NameForAtom (pCursor->name) : "";
+ nbytes = strlen (name);
+ nbytesRound = pad_to_int32(nbytes);
+ rep = malloc(sizeof (xXFixesGetCursorImageAndNameReply) +
+ npixels * sizeof (CARD32) + nbytesRound);
+ if (!rep)
+ return BadAlloc;
+
+ rep->type = X_Reply;
+ rep->sequenceNumber = client->sequence;
+ rep->length = npixels + bytes_to_int32(nbytesRound);
+ rep->width = width;
+ rep->height = height;
+ rep->x = x;
+ rep->y = y;
+ rep->xhot = pCursor->bits->xhot;
+ rep->yhot = pCursor->bits->yhot;
+ rep->cursorSerial = pCursor->serialNumber;
+ rep->cursorName = pCursor->name;
+ rep->nbytes = nbytes;
+
+ image = (CARD32 *) (rep + 1);
+ CopyCursorToImage (pCursor, image);
+ memcpy ((image + npixels), name, nbytes);
+ if (client->swapped)
+ {
+ int n;
+ swaps (&rep->sequenceNumber, n);
+ swapl (&rep->length, n);
+ swaps (&rep->x, n);
+ swaps (&rep->y, n);
+ swaps (&rep->width, n);
+ swaps (&rep->height, n);
+ swaps (&rep->xhot, n);
+ swaps (&rep->yhot, n);
+ swapl (&rep->cursorSerial, n);
+ swapl (&rep->cursorName, n);
+ swaps (&rep->nbytes, n);
+ SwapLongs (image, npixels);
+ }
+ WriteToClient(client, sizeof (xXFixesGetCursorImageAndNameReply) +
+ (npixels << 2) + nbytesRound, (char *) rep);
+ free(rep);
+ return Success;
+}
+
+int
+SProcXFixesGetCursorImageAndName (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesGetCursorImageAndNameReq);
+ swaps (&stuff->length, n);
+ return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
+}
+
+/*
+ * Find every cursor reference in the system, ask testCursor
+ * whether it should be replaced with a reference to pCursor.
+ */
+
+typedef Bool (*TestCursorFunc) (CursorPtr pOld, pointer closure);
+
+typedef struct {
+ RESTYPE type;
+ TestCursorFunc testCursor;
+ CursorPtr pNew;
+ pointer closure;
+} ReplaceCursorLookupRec, *ReplaceCursorLookupPtr;
+
+static const RESTYPE CursorRestypes[] = {
+ RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR
+};
+
+#define NUM_CURSOR_RESTYPES (sizeof (CursorRestypes) / sizeof (CursorRestypes[0]))
+
+static Bool
+ReplaceCursorLookup (pointer value, XID id, pointer closure)
+{
+ ReplaceCursorLookupPtr rcl = (ReplaceCursorLookupPtr) closure;
+ WindowPtr pWin;
+ GrabPtr pGrab;
+ CursorPtr pCursor = 0, *pCursorRef = 0;
+ XID cursor = 0;
+
+ switch (rcl->type) {
+ case RT_WINDOW:
+ pWin = (WindowPtr) value;
+ if (pWin->optional)
+ {
+ pCursorRef = &pWin->optional->cursor;
+ pCursor = *pCursorRef;
+ }
+ break;
+ case RT_PASSIVEGRAB:
+ pGrab = (GrabPtr) value;
+ pCursorRef = &pGrab->cursor;
+ pCursor = *pCursorRef;
+ break;
+ case RT_CURSOR:
+ pCursorRef = 0;
+ pCursor = (CursorPtr) value;
+ cursor = id;
+ break;
+ }
+ if (pCursor && pCursor != rcl->pNew)
+ {
+ if ((*rcl->testCursor) (pCursor, rcl->closure))
+ {
+ rcl->pNew->refcnt++;
+ /* either redirect reference or update resource database */
+ if (pCursorRef)
+ *pCursorRef = rcl->pNew;
+ else
+ ChangeResourceValue (id, RT_CURSOR, rcl->pNew);
+ FreeCursor (pCursor, cursor);
+ }
+ }
+ return FALSE; /* keep walking */
+}
+
+static void
+ReplaceCursor (CursorPtr pCursor,
+ TestCursorFunc testCursor,
+ pointer closure)
+{
+ int clientIndex;
+ int resIndex;
+ ReplaceCursorLookupRec rcl;
+
+ /*
+ * Cursors exist only in the resource database, windows and grabs.
+ * All of these are always pointed at by the resource database. Walk
+ * the whole thing looking for cursors
+ */
+ rcl.testCursor = testCursor;
+ rcl.pNew = pCursor;
+ rcl.closure = closure;
+
+ /* for each client */
+ for (clientIndex = 0; clientIndex < currentMaxClients; clientIndex++)
+ {
+ if (!clients[clientIndex])
+ continue;
+ for (resIndex = 0; resIndex < NUM_CURSOR_RESTYPES; resIndex++)
+ {
+ rcl.type = CursorRestypes[resIndex];
+ /*
+ * This function walks the entire client resource database
+ */
+ LookupClientResourceComplex (clients[clientIndex],
+ rcl.type,
+ ReplaceCursorLookup,
+ (pointer) &rcl);
+ }
+ }
+ /* this "knows" that WindowHasNewCursor doesn't depend on it's argument */
+ WindowHasNewCursor (screenInfo.screens[0]->root);
+}
+
+static Bool
+TestForCursor (CursorPtr pCursor, pointer closure)
+{
+ return (pCursor == (CursorPtr) closure);
+}
+
+int
+ProcXFixesChangeCursor (ClientPtr client)
+{
+ CursorPtr pSource, pDestination;
+ REQUEST(xXFixesChangeCursorReq);
+
+ REQUEST_SIZE_MATCH(xXFixesChangeCursorReq);
+ VERIFY_CURSOR (pSource, stuff->source, client,
+ DixReadAccess|DixGetAttrAccess);
+ VERIFY_CURSOR (pDestination, stuff->destination, client,
+ DixWriteAccess|DixSetAttrAccess);
+
+ ReplaceCursor (pSource, TestForCursor, (pointer) pDestination);
+ return Success;
+}
+
+int
+SProcXFixesChangeCursor (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesChangeCursorReq);
+
+ swaps (&stuff->length, n);
+ REQUEST_SIZE_MATCH(xXFixesChangeCursorReq);
+ swapl (&stuff->source, n);
+ swapl (&stuff->destination, n);
+ return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
+}
+
+static Bool
+TestForCursorName (CursorPtr pCursor, pointer closure)
+{
+ Atom *pName = closure;
+ return pCursor->name == *pName;
+}
+
+int
+ProcXFixesChangeCursorByName (ClientPtr client)
+{
+ CursorPtr pSource;
+ Atom name;
+ char *tchar;
+ REQUEST(xXFixesChangeCursorByNameReq);
+
+ REQUEST_FIXED_SIZE(xXFixesChangeCursorByNameReq, stuff->nbytes);
+ VERIFY_CURSOR(pSource, stuff->source, client,
+ DixReadAccess|DixGetAttrAccess);
+ tchar = (char *) &stuff[1];
+ name = MakeAtom (tchar, stuff->nbytes, FALSE);
+ if (name)
+ ReplaceCursor (pSource, TestForCursorName, &name);
+ return Success;
+}
+
+int
+SProcXFixesChangeCursorByName (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesChangeCursorByNameReq);
+
+ swaps (&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE (xXFixesChangeCursorByNameReq);
+ swapl (&stuff->source, n);
+ swaps (&stuff->nbytes, n);
+ return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
+}
+
+/*
+ * Routines for manipulating the per-screen hide counts list.
+ * This list indicates which clients have requested cursor hiding
+ * for that screen.
+ */
+
+/* Return the screen's hide-counts list element for the given client */
+static CursorHideCountPtr
+findCursorHideCount (ClientPtr pClient, ScreenPtr pScreen)
+{
+ CursorScreenPtr cs = GetCursorScreen(pScreen);
+ CursorHideCountPtr pChc;
+
+ for (pChc = cs->pCursorHideCounts; pChc != NULL; pChc = pChc->pNext) {
+ if (pChc->pClient == pClient) {
+ return pChc;
+ }
+ }
+
+ return NULL;
+}
+
+static int
+createCursorHideCount (ClientPtr pClient, ScreenPtr pScreen)
+{
+ CursorScreenPtr cs = GetCursorScreen(pScreen);
+ CursorHideCountPtr pChc;
+
+ pChc = (CursorHideCountPtr) malloc(sizeof(CursorHideCountRec));
+ if (pChc == NULL) {
+ return BadAlloc;
+ }
+ pChc->pClient = pClient;
+ pChc->pScreen = pScreen;
+ pChc->hideCount = 1;
+ pChc->resource = FakeClientID(pClient->index);
+ pChc->pNext = cs->pCursorHideCounts;
+ cs->pCursorHideCounts = pChc;
+
+ /*
+ * Create a resource for this element so it can be deleted
+ * when the client goes away.
+ */
+ if (!AddResource (pChc->resource, CursorHideCountType,
+ (pointer) pChc)) {
+ free(pChc);
+ return BadAlloc;
+ }
+
+ return Success;
+}
+
+/*
+ * Delete the given hide-counts list element from its screen list.
+ */
+static void
+deleteCursorHideCount (CursorHideCountPtr pChcToDel, ScreenPtr pScreen)
+{
+ CursorScreenPtr cs = GetCursorScreen(pScreen);
+ CursorHideCountPtr pChc, pNext;
+ CursorHideCountPtr pChcLast = NULL;
+
+ pChc = cs->pCursorHideCounts;
+ while (pChc != NULL) {
+ pNext = pChc->pNext;
+ if (pChc == pChcToDel) {
+ free(pChc);
+ if (pChcLast == NULL) {
+ cs->pCursorHideCounts = pNext;
+ } else {
+ pChcLast->pNext = pNext;
+ }
+ return;
+ }
+ pChcLast = pChc;
+ pChc = pNext;
+ }
+}
+
+/*
+ * Delete all the hide-counts list elements for this screen.
+ */
+static void
+deleteCursorHideCountsForScreen (ScreenPtr pScreen)
+{
+ CursorScreenPtr cs = GetCursorScreen(pScreen);
+ CursorHideCountPtr pChc, pTmp;
+
+ pChc = cs->pCursorHideCounts;
+ while (pChc != NULL) {
+ pTmp = pChc->pNext;
+ FreeResource(pChc->resource, 0);
+ pChc = pTmp;
+ }
+ cs->pCursorHideCounts = NULL;
+}
+
+int
+ProcXFixesHideCursor (ClientPtr client)
+{
+ WindowPtr pWin;
+ CursorHideCountPtr pChc;
+ REQUEST(xXFixesHideCursorReq);
+ int ret;
+
+ REQUEST_SIZE_MATCH (xXFixesHideCursorReq);
+
+ ret = dixLookupResourceByType((pointer *)&pWin, stuff->window, RT_WINDOW,
+ client, DixGetAttrAccess);
+ if (ret != Success) {
+ client->errorValue = stuff->window;
+ return ret;
+ }
+
+ /*
+ * Has client hidden the cursor before on this screen?
+ * If so, just increment the count.
+ */
+
+ pChc = findCursorHideCount(client, pWin->drawable.pScreen);
+ if (pChc != NULL) {
+ pChc->hideCount++;
+ return Success;
+ }
+
+ /*
+ * This is the first time this client has hid the cursor
+ * for this screen.
+ */
+ ret = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen,
+ DixHideAccess);
+ if (ret != Success)
+ return ret;
+
+ ret = createCursorHideCount(client, pWin->drawable.pScreen);
+
+ if (ret == Success) {
+ DeviceIntPtr dev;
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (IsMaster(dev) && IsPointerDevice(dev))
+ CursorDisplayCursor(dev, pWin->drawable.pScreen, CursorCurrent[dev->id]);
+ }
+ }
+
+ return ret;
+}
+
+int
+SProcXFixesHideCursor (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesHideCursorReq);
+
+ swaps (&stuff->length, n);
+ REQUEST_SIZE_MATCH (xXFixesHideCursorReq);
+ swapl (&stuff->window, n);
+ return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
+}
+
+int
+ProcXFixesShowCursor (ClientPtr client)
+{
+ WindowPtr pWin;
+ CursorHideCountPtr pChc;
+ int rc;
+ REQUEST(xXFixesShowCursorReq);
+
+ REQUEST_SIZE_MATCH (xXFixesShowCursorReq);
+
+ rc = dixLookupResourceByType((pointer *)&pWin, stuff->window, RT_WINDOW,
+ client, DixGetAttrAccess);
+ if (rc != Success) {
+ client->errorValue = stuff->window;
+ return rc;
+ }
+
+ /*
+ * Has client hidden the cursor on this screen?
+ * If not, generate an error.
+ */
+ pChc = findCursorHideCount(client, pWin->drawable.pScreen);
+ if (pChc == NULL) {
+ return BadMatch;
+ }
+
+ rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen,
+ DixShowAccess);
+ if (rc != Success)
+ return rc;
+
+ pChc->hideCount--;
+ if (pChc->hideCount <= 0) {
+ FreeResource(pChc->resource, 0);
+ }
+
+ return Success;
+}
+
+int
+SProcXFixesShowCursor (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesShowCursorReq);
+
+ swaps (&stuff->length, n);
+ REQUEST_SIZE_MATCH (xXFixesShowCursorReq);
+ swapl (&stuff->window, n);
+ return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
+}
+
+static int
+CursorFreeClient (pointer data, XID id)
+{
+ CursorEventPtr old = (CursorEventPtr) data;
+ CursorEventPtr *prev, e;
+
+ for (prev = &cursorEvents; (e = *prev); prev = &e->next)
+ {
+ if (e == old)
+ {
+ *prev = e->next;
+ free(e);
+ break;
+ }
+ }
+ return 1;
+}
+
+static int
+CursorFreeHideCount (pointer data, XID id)
+{
+ CursorHideCountPtr pChc = (CursorHideCountPtr) data;
+ ScreenPtr pScreen = pChc->pScreen;
+ DeviceIntPtr dev;
+
+ deleteCursorHideCount(pChc, pChc->pScreen);
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (IsMaster(dev) && IsPointerDevice(dev))
+ CursorDisplayCursor(dev, pScreen, CursorCurrent[dev->id]);
+ }
+
+ return 1;
+}
+
+static int
+CursorFreeWindow (pointer data, XID id)
+{
+ WindowPtr pWindow = (WindowPtr) data;
+ CursorEventPtr e, next;
+
+ for (e = cursorEvents; e; e = next)
+ {
+ next = e->next;
+ if (e->pWindow == pWindow)
+ {
+ FreeResource (e->clientResource, 0);
+ }
+ }
+ return 1;
+}
+
+static BOOL
+barrier_is_horizontal(const struct PointerBarrier *barrier)
+{
+ return barrier->y1 == barrier->y2;
+}
+
+static BOOL
+barrier_is_vertical(const struct PointerBarrier *barrier)
+{
+ return barrier->x1 == barrier->x2;
+}
+
+/**
+ * @return The set of barrier movement directions the movement vector
+ * x1/y1 → x2/y2 represents.
+ */
+int
+barrier_get_direction(int x1, int y1, int x2, int y2)
+{
+ int direction = 0;
+
+ /* which way are we trying to go */
+ if (x2 > x1)
+ direction |= BarrierPositiveX;
+ if (x2 < x1)
+ direction |= BarrierNegativeX;
+ if (y2 > y1)
+ direction |= BarrierPositiveY;
+ if (y2 < y1)
+ direction |= BarrierNegativeY;
+
+ return direction;
+}
+
+/**
+ * Test if the barrier may block movement in the direction defined by
+ * x1/y1 → x2/y2. This function only tests whether the directions could be
+ * blocked, it does not test if the barrier actually blocks the movement.
+ *
+ * @return TRUE if the barrier blocks the direction of movement or FALSE
+ * otherwise.
+ */
+BOOL
+barrier_is_blocking_direction(const struct PointerBarrier *barrier, int direction)
+{
+ /* Barriers define which way is ok, not which way is blocking */
+ return (barrier->directions & direction) != direction;
+}
+
+/**
+ * Test if the movement vector x1/y1 → x2/y2 is intersecting with the
+ * barrier. A movement vector with the startpoint or endpoint adjacent to
+ * the barrier itself counts as intersecting.
+ *
+ * @param x1 X start coordinate of movement vector
+ * @param y1 Y start coordinate of movement vector
+ * @param x2 X end coordinate of movement vector
+ * @param y2 Y end coordinate of movement vector
+ * @param[out] distance The distance between the start point and the
+ * intersection with the barrier (if applicable).
+ * @return TRUE if the barrier intersects with the given vector
+ */
+BOOL
+barrier_is_blocking(const struct PointerBarrier *barrier,
+ int x1, int y1, int x2, int y2,
+ double *distance)
+{
+ BOOL rc = FALSE;
+ float ua, ub, ud;
+ int dir = barrier_get_direction(x1, y1, x2, y2);
+
+ /* Algorithm below doesn't handle edge cases well, hence the extra
+ * checks. */
+ if (barrier_is_vertical(barrier)) {
+ /* handle immediate barrier adjacency, moving away */
+ if (dir & BarrierPositiveX && x1 == barrier->x1)
+ return FALSE;
+ if (dir & BarrierNegativeX && x1 == (barrier->x1 - 1))
+ return FALSE;
+ /* startpoint adjacent to barrier, moving towards -> block */
+ if (x1 == barrier->x1 && y1 >= barrier->y1 && y1 <= barrier->y2) {
+ *distance = 0;
+ return TRUE;
+ }
+ } else {
+ /* handle immediate barrier adjacency, moving away */
+ if (dir & BarrierPositiveY && y1 == barrier->y1)
+ return FALSE;
+ if (dir & BarrierNegativeY && y1 == (barrier->y1 - 1))
+ return FALSE;
+ /* startpoint adjacent to barrier, moving towards -> block */
+ if (y1 == barrier->y1 && x1 >= barrier->x1 && x1 <= barrier->x2) {
+ *distance = 0;
+ return TRUE;
+ }
+ }
+
+ /* not an edge case, compute distance */
+ ua = 0;
+ ud = (barrier->y2 - barrier->y1) * (x2 - x1) - (barrier->x2 - barrier->x1) * (y2 - y1);
+ if (ud != 0) {
+ ua = ((barrier->x2 - barrier->x1) * (y1 - barrier->y1) -
+ (barrier->y2 - barrier->y1) * (x1 - barrier->x1)) / ud;
+ ub = ((x2 - x1) * (y1 - barrier->y1) -
+ (y2 - y1) * (x1 - barrier->x1)) / ud;
+ if (ua < 0 || ua > 1 || ub < 0 || ub > 1)
+ ua = 0;
+ }
+
+ if (ua > 0 && ua <= 1)
+ {
+ double ix = barrier->x1 + ua * (barrier->x2 - barrier->x1);
+ double iy = barrier->y1 + ua * (barrier->y2 - barrier->y1);
+
+ *distance = sqrt(pow(x1 - ix, 2) + pow(y1 - iy, 2));
+ rc = TRUE;
+ }
+
+ return rc;
+}
+
+/**
+ * Find the nearest barrier that is blocking movement from x1/y1 to x2/y2.
+ *
+ * @param dir Only barriers blocking movement in direction dir are checked
+ * @param x1 X start coordinate of movement vector
+ * @param y1 Y start coordinate of movement vector
+ * @param x2 X end coordinate of movement vector
+ * @param y2 Y end coordinate of movement vector
+ * @return The barrier nearest to the movement origin that blocks this movement.
+ */
+static struct PointerBarrier*
+barrier_find_nearest(CursorScreenPtr cs, int dir,
+ int x1, int y1, int x2, int y2)
+{
+ struct PointerBarrierClient *c;
+ struct PointerBarrier *nearest = NULL;
+ double min_distance = INT_MAX; /* can't get higher than that in X anyway */
+
+ list_for_each_entry(c, &cs->barriers, entry) {
+ struct PointerBarrier *b = &c->barrier;
+ double distance;
+
+ if (!barrier_is_blocking_direction(b, dir))
+ continue;
+
+ if (barrier_is_blocking(b, x1, y1, x2, y2, &distance))
+ {
+ if (min_distance > distance)
+ {
+ min_distance = distance;
+ nearest = b;
+ }
+ }
+ }
+
+ return nearest;
+}
+
+/**
+ * Clamp to the given barrier given the movement direction specified in dir.
+ *
+ * @param barrier The barrier to clamp to
+ * @param dir The movement direction
+ * @param[out] x The clamped x coordinate.
+ * @param[out] y The clamped x coordinate.
+ */
+void
+barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, int *y)
+{
+ if (barrier_is_vertical(barrier))
+ {
+ if ((dir & BarrierNegativeX) & ~barrier->directions)
+ *x = barrier->x1;
+ if ((dir & BarrierPositiveX) & ~barrier->directions)
+ *x = barrier->x1 - 1;
+ }
+ if (barrier_is_horizontal(barrier))
+ {
+ if ((dir & BarrierNegativeY) & ~barrier->directions)
+ *y = barrier->y1;
+ if ((dir & BarrierPositiveY) & ~barrier->directions)
+ *y = barrier->y1 - 1;
+ }
+}
+
+static void
+CursorConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, int *x, int *y)
+{
+ CursorScreenPtr cs = GetCursorScreen(screen);
+
+ if (!list_is_empty(&cs->barriers) && !IsFloating(dev) && mode == Relative) {
+ int ox, oy;
+ int dir;
+ struct PointerBarrier *nearest = NULL;
+
+ /* where are we coming from */
+ miPointerGetPosition(dev, &ox, &oy);
+
+ /* How this works:
+ * Given the origin and the movement vector, get the nearest barrier
+ * to the origin that is blocking the movement.
+ * Clamp to that barrier.
+ * Then, check from the clamped intersection to the original
+ * destination, again finding the nearest barrier and clamping.
+ */
+ dir = barrier_get_direction(ox, oy, *x, *y);
+
+ nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
+ if (nearest) {
+ barrier_clamp_to_barrier(nearest, dir, x, y);
+
+ if (barrier_is_vertical(nearest)) {
+ dir &= ~(BarrierNegativeX | BarrierPositiveX);
+ ox = *x;
+ } else if (barrier_is_horizontal(nearest)) {
+ dir &= ~(BarrierNegativeY | BarrierPositiveY);
+ oy = *y;
+ }
+
+ nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
+ if (nearest) {
+ barrier_clamp_to_barrier(nearest, dir, x, y);
+ }
+ }
+ }
+
+ if (cs->ConstrainCursorHarder) {
+ screen->ConstrainCursorHarder = cs->ConstrainCursorHarder;
+ screen->ConstrainCursorHarder(dev, screen, mode, x, y);
+ screen->ConstrainCursorHarder = CursorConstrainCursorHarder;
+ }
+}
+
+static struct PointerBarrierClient *
+CreatePointerBarrierClient(ScreenPtr screen, ClientPtr client,
+ xXFixesCreatePointerBarrierReq *stuff)
+{
+ CursorScreenPtr cs = GetCursorScreen(screen);
+ struct PointerBarrierClient *ret = malloc(sizeof(*ret));
+
+ if (ret) {
+ ret->screen = screen;
+ ret->barrier.x1 = min(stuff->x1, stuff->x2);
+ ret->barrier.x2 = max(stuff->x1, stuff->x2);
+ ret->barrier.y1 = min(stuff->y1, stuff->y2);
+ ret->barrier.y2 = max(stuff->y1, stuff->y2);
+ ret->barrier.directions = stuff->directions & 0x0f;
+ if (barrier_is_horizontal(&ret->barrier))
+ ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
+ if (barrier_is_vertical(&ret->barrier))
+ ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY);
+ list_add(&ret->entry, &cs->barriers);
+ }
+
+ return ret;
+}
+
+int
+ProcXFixesCreatePointerBarrier (ClientPtr client)
+{
+ int err;
+ WindowPtr pWin;
+ struct PointerBarrierClient *barrier;
+ struct PointerBarrier b;
+ REQUEST (xXFixesCreatePointerBarrierReq);
+
+ REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
+ LEGAL_NEW_RESOURCE(stuff->barrier, client);
+
+ err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
+ if (err != Success) {
+ client->errorValue = stuff->window;
+ return err;
+ }
+
+ /* This sure does need fixing. */
+ if (stuff->num_devices)
+ return BadImplementation;
+
+ b.x1 = stuff->x1;
+ b.x2 = stuff->x2;
+ b.y1 = stuff->y1;
+ b.y2 = stuff->y2;
+
+ if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b))
+ return BadValue;
+
+ /* no 0-sized barriers */
+ if (barrier_is_horizontal(&b) && barrier_is_vertical(&b))
+ return BadValue;
+
+ if (!(barrier = CreatePointerBarrierClient(pWin->drawable.pScreen,
+ client, stuff)))
+ return BadAlloc;
+
+ if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
+ return BadAlloc;
+
+ return Success;
+}
+
+int
+SProcXFixesCreatePointerBarrier (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesCreatePointerBarrierReq);
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
+ swapl(&stuff->barrier, n);
+ swapl(&stuff->window, n);
+ swaps(&stuff->x1, n);
+ swaps(&stuff->y1, n);
+ swaps(&stuff->x2, n);
+ swaps(&stuff->y2, n);
+ swapl(&stuff->directions, n);
+ return ProcXFixesVector[stuff->xfixesReqType](client);
+}
+
+static int
+CursorFreeBarrier(void *data, XID id)
+{
+ struct PointerBarrierClient *b = NULL, *barrier;
+ ScreenPtr screen;
+ CursorScreenPtr cs;
+
+ barrier = container_of(data, struct PointerBarrierClient, barrier);
+ screen = barrier->screen;
+ cs = GetCursorScreen(screen);
+
+ /* find and unlink from the screen private */
+ list_for_each_entry(b, &cs->barriers, entry) {
+ if (b == barrier) {
+ list_del(&b->entry);
+ break;
+ }
+ }
+
+ free(barrier);
+ return Success;
+}
+
+int
+ProcXFixesDestroyPointerBarrier (ClientPtr client)
+{
+ int err;
+ void *barrier;
+ REQUEST (xXFixesDestroyPointerBarrierReq);
+
+ REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
+
+ err = dixLookupResourceByType((void **)&barrier, stuff->barrier,
+ PointerBarrierType, client,
+ DixDestroyAccess);
+ if (err != Success) {
+ client->errorValue = stuff->barrier;
+ return err;
+ }
+
+ FreeResource(stuff->barrier, RT_NONE);
+ return Success;
+}
+
+int
+SProcXFixesDestroyPointerBarrier (ClientPtr client)
+{
+ int n;
+ REQUEST(xXFixesDestroyPointerBarrierReq);
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
+ swapl(&stuff->barrier, n);
+ return ProcXFixesVector[stuff->xfixesReqType](client);
+}
+
+Bool
+XFixesCursorInit (void)
+{
+ int i;
+
+ if (party_like_its_1989)
+ CursorVisible = EnableCursor;
+
+ if (!dixRegisterPrivateKey(&CursorScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
+ return FALSE;
+
+ for (i = 0; i < screenInfo.numScreens; i++)
+ {
+ ScreenPtr pScreen = screenInfo.screens[i];
+ CursorScreenPtr cs;
+
+ cs = (CursorScreenPtr) calloc(1, sizeof (CursorScreenRec));
+ if (!cs)
+ return FALSE;
+ list_init(&cs->barriers);
+ Wrap (cs, pScreen, CloseScreen, CursorCloseScreen);
+ Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor);
+ Wrap (cs, pScreen, ConstrainCursorHarder, CursorConstrainCursorHarder);
+ cs->pCursorHideCounts = NULL;
+ SetCursorScreen (pScreen, cs);
+ }
+ CursorClientType = CreateNewResourceType(CursorFreeClient,
+ "XFixesCursorClient");
+ CursorHideCountType = CreateNewResourceType(CursorFreeHideCount,
+ "XFixesCursorHideCount");
+ CursorWindowType = CreateNewResourceType(CursorFreeWindow,
+ "XFixesCursorWindow");
+ PointerBarrierType = CreateNewResourceType(CursorFreeBarrier,
+ "XFixesPointerBarrier");
+
+ return CursorClientType && CursorHideCountType && CursorWindowType &&
+ PointerBarrierType;
+}
+