1449 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1449 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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>
 | |
| #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;
 | |
|     _X_UNUSED CloseScreenProcPtr	close_proc;
 | |
|     _X_UNUSED 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)
 | |
| {
 | |
|     REQUEST(xXFixesSelectCursorInputReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     swapl(&stuff->window);
 | |
|     swapl(&stuff->eventMask);
 | |
|     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)
 | |
|     {
 | |
| 	swaps(&rep->sequenceNumber);
 | |
| 	swapl(&rep->length);
 | |
| 	swaps(&rep->x);
 | |
| 	swaps(&rep->y);
 | |
| 	swaps(&rep->width);
 | |
| 	swaps(&rep->height);
 | |
| 	swaps(&rep->xhot);
 | |
| 	swaps(&rep->yhot);
 | |
| 	swapl(&rep->cursorSerial);
 | |
| 	SwapLongs (image, npixels);
 | |
|     }
 | |
|     WriteToClient(client, sizeof (xXFixesGetCursorImageReply) +
 | |
| 			 (npixels << 2), (char *) rep);
 | |
|     free(rep);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| int
 | |
| SProcXFixesGetCursorImage (ClientPtr client)
 | |
| {
 | |
|     REQUEST(xXFixesGetCursorImageReq);
 | |
|     swaps(&stuff->length);
 | |
|     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)
 | |
| {
 | |
|     REQUEST(xXFixesSetCursorNameReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq);
 | |
|     swapl(&stuff->cursor);
 | |
|     swaps(&stuff->nbytes);
 | |
|     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)
 | |
|     {
 | |
| 	swaps(&reply.sequenceNumber);
 | |
| 	swapl(&reply.length);
 | |
| 	swapl(&reply.atom);
 | |
| 	swaps(&reply.nbytes);
 | |
|     }
 | |
|     WriteReplyToClient(client, sizeof(xXFixesGetCursorNameReply), &reply);
 | |
|     WriteToClient(client, len, str);
 | |
|     
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| int
 | |
| SProcXFixesGetCursorName (ClientPtr client)
 | |
| {
 | |
|     REQUEST(xXFixesGetCursorNameReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq);
 | |
|     swapl(&stuff->cursor);
 | |
|     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)
 | |
|     {
 | |
| 	swaps(&rep->sequenceNumber);
 | |
| 	swapl(&rep->length);
 | |
| 	swaps(&rep->x);
 | |
| 	swaps(&rep->y);
 | |
| 	swaps(&rep->width);
 | |
| 	swaps(&rep->height);
 | |
| 	swaps(&rep->xhot);
 | |
| 	swaps(&rep->yhot);
 | |
| 	swapl(&rep->cursorSerial);
 | |
| 	swapl(&rep->cursorName);
 | |
| 	swaps(&rep->nbytes);
 | |
| 	SwapLongs (image, npixels);
 | |
|     }
 | |
|     WriteToClient(client, sizeof (xXFixesGetCursorImageAndNameReply) +
 | |
| 			 (npixels << 2) + nbytesRound, (char *) rep);
 | |
|     free(rep);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| int
 | |
| SProcXFixesGetCursorImageAndName (ClientPtr client)
 | |
| {
 | |
|     REQUEST(xXFixesGetCursorImageAndNameReq);
 | |
|     swaps(&stuff->length);
 | |
|     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)
 | |
| {
 | |
|     REQUEST(xXFixesChangeCursorReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     REQUEST_SIZE_MATCH(xXFixesChangeCursorReq);
 | |
|     swapl(&stuff->source);
 | |
|     swapl(&stuff->destination);
 | |
|     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)
 | |
| {
 | |
|     REQUEST(xXFixesChangeCursorByNameReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     REQUEST_AT_LEAST_SIZE (xXFixesChangeCursorByNameReq);
 | |
|     swapl(&stuff->source);
 | |
|     swaps(&stuff->nbytes);
 | |
|     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) 
 | |
| {
 | |
|     REQUEST(xXFixesHideCursorReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     REQUEST_SIZE_MATCH (xXFixesHideCursorReq);
 | |
|     swapl(&stuff->window);
 | |
|     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) 
 | |
| {
 | |
|     REQUEST(xXFixesShowCursorReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     REQUEST_SIZE_MATCH (xXFixesShowCursorReq);
 | |
|     swapl(&stuff->window);
 | |
|     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)
 | |
| {
 | |
|     REQUEST(xXFixesCreatePointerBarrierReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
 | |
|     swapl(&stuff->barrier);
 | |
|     swapl(&stuff->window);
 | |
|     swaps(&stuff->x1);
 | |
|     swaps(&stuff->y1);
 | |
|     swaps(&stuff->x2);
 | |
|     swaps(&stuff->y2);
 | |
|     swapl(&stuff->directions);
 | |
|     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)
 | |
| {
 | |
|     REQUEST(xXFixesDestroyPointerBarrierReq);
 | |
| 
 | |
|     swaps(&stuff->length);
 | |
|     REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
 | |
|     swapl(&stuff->barrier);
 | |
|     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;
 | |
| }
 | |
| 
 |