diff options
-rw-r--r-- | Changelog | 14 | ||||
-rw-r--r-- | Xi/Makefile.am | 2 | ||||
-rw-r--r-- | Xi/chdevcur.c | 123 | ||||
-rw-r--r-- | Xi/chdevcur.h | 39 | ||||
-rw-r--r-- | Xi/extinit.c | 3 | ||||
-rw-r--r-- | dix/events.c | 17 | ||||
-rw-r--r-- | dix/window.c | 242 | ||||
-rw-r--r-- | include/window.h | 13 | ||||
-rw-r--r-- | include/windowstr.h | 8 |
9 files changed, 456 insertions, 5 deletions
@@ -1,3 +1,17 @@ +== 08.01.06 == +Xi: Adding ChangeDeviceCursor request + +Files: + dix/window.c + dix/events.c + include/window.h + include/windowstr.h + Xi/extinit.c + Xi/chdevcur.c + Xi/chdevcur.h + Xi/Makefile.am + + == 20.12.06 == xfree86: Changing "IsMPDevice" to "SharedPointer" option. Devices will default to MP devices. diff --git a/Xi/Makefile.am b/Xi/Makefile.am index 0aa58449f..9e7d1c43e 100644 --- a/Xi/Makefile.am +++ b/Xi/Makefile.am @@ -5,6 +5,8 @@ AM_CFLAGS = $(DIX_CFLAGS) libXi_la_SOURCES = \ allowev.c \ allowev.h \ + chdevcur.c \ + chdevcur.h \ chgdctl.c \ chgdctl.h \ chgfctl.c \ diff --git a/Xi/chdevcur.c b/Xi/chdevcur.c new file mode 100644 index 000000000..fc4b0e01d --- /dev/null +++ b/Xi/chdevcur.c @@ -0,0 +1,123 @@ +/* + +Copyright 2006 Peter Hutterer <peter@cs.unisa.edu.au> + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the author shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the author. + +*/ + +/*********************************************************************** + * + * Request to change a given device pointer's cursor. + * + */ + +#define NEED_EVENTS +#define NEED_REPLIES +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> /* for inputstr.h */ +#include <X11/Xproto.h> /* Request macro */ +#include "inputstr.h" /* DeviceIntPtr */ +#include "windowstr.h" /* window structure */ +#include "scrnintstr.h" /* screen structure */ +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "extnsionst.h" +#include "extinit.h" /* LookupDeviceIntRec */ +#include "exevents.h" +#include "exglobals.h" + +#include "chdevcur.h" + +/*********************************************************************** + * + * This procedure allows a client to set one pointer's cursor. + * + */ + +int +SProcXChangeDeviceCursor(register ClientPtr client) +{ + register char n; + + REQUEST(xChangeDeviceCursorReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xChangeDeviceCursorReq); + return (ProcXChangeDeviceCursor(client)); +} + +int ProcXChangeDeviceCursor(register ClientPtr client) +{ + int err; + WindowPtr pWin = NULL; + DeviceIntPtr pDev = NULL; + CursorPtr pCursor = NULL; + + REQUEST(xChangeDeviceCursorReq); + REQUEST_SIZE_MATCH(xChangeDeviceCursorReq); + + pDev = LookupDeviceIntRec(stuff->deviceid); + if (pDev == NULL) { + SendErrorToClient(client, IReqCode, X_ChangeDeviceCursor, 0, + BadDevice); + return Success; + } + + if (stuff->win != None) + { + err = dixLookupWindow(&pWin, stuff->win, client, DixReadWriteAccess); + if (err != Success) + { + SendErrorToClient(client, IReqCode, X_ChangeDeviceCursor, + stuff->win, err); + return Success; + } + } + + if (stuff->cursor == None) + { + if (pWin == WindowTable[pWin->drawable.pScreen->myNum]) + pCursor = rootCursor; + else + pCursor = (CursorPtr)None; + } + else + { + pCursor = (CursorPtr)SecurityLookupIDByType(client, stuff->cursor, + RT_CURSOR, DixReadAccess); + if (!pCursor) + { + SendErrorToClient(client, IReqCode, X_ChangeDeviceCursor, + stuff->cursor, BadCursor); + return Success; + } + } + + ChangeWindowDeviceCursor(pWin, pDev, pCursor); + + return Success; +} + diff --git a/Xi/chdevcur.h b/Xi/chdevcur.h new file mode 100644 index 000000000..92c8d4f0d --- /dev/null +++ b/Xi/chdevcur.h @@ -0,0 +1,39 @@ +/************************************************************ + +Copyright 2006 by Peter Hutterer <peter@cs.unisa.edu.au> + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the above listed +copyright holder(s) not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD +TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) 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 + +#ifndef CHDEVCUR_H +#define CHDEVCUR_H 1 + +int SProcXChangeDeviceCursor(ClientPtr /* client */ + ); + +int ProcXChangeDeviceCursor(ClientPtr /* client */ + ); + +#endif /* CHDEVCUR_H */ diff --git a/Xi/extinit.c b/Xi/extinit.c index 7c737a143..82bed5000 100644 --- a/Xi/extinit.c +++ b/Xi/extinit.c @@ -74,6 +74,7 @@ SOFTWARE. /* modules local to Xi */ #include "allowev.h" +#include "chdevcur.h" #include "chgdctl.h" #include "chgfctl.h" #include "chgkbd.h" @@ -340,6 +341,8 @@ ProcIDispatch(register ClientPtr client) return (ProcXQueryDevicePointer(client)); else if (stuff->data == X_WarpDevicePointer) return (ProcXWarpDevicePointer(client)); + else if (stuff->data == X_ChangeDeviceCursor) + return (ProcXChangeDeviceCursor(client)); else { SendErrorToClient(client, IReqCode, stuff->data, 0, BadRequest); } diff --git a/dix/events.c b/dix/events.c index 81efb708a..3c11723c1 100644 --- a/dix/events.c +++ b/dix/events.c @@ -921,6 +921,7 @@ PostNewCursor(DeviceIntPtr pDev) register WindowPtr win; register GrabPtr grab = pDev->grab; SpritePtr pSprite = pDev->pSprite; + CursorPtr pCursor; if (syncEvents.playingEvents) return; @@ -939,11 +940,19 @@ PostNewCursor(DeviceIntPtr pDev) else win = pSprite->win; for (; win; win = win->parent) - if (win->optional && win->optional->cursor != NullCursor) - { - ChangeToCursor(pDev, win->optional->cursor); - return; + { + if (win->optional) + { + pCursor = WindowGetDeviceCursor(win, pDev); + if (!pCursor && win->optional->cursor != NullCursor) + pCursor = win->optional->cursor; + if (pCursor) + { + ChangeToCursor(pDev, pCursor); + return; + } } + } } _X_EXPORT WindowPtr diff --git a/dix/window.c b/dix/window.c index e33140dd4..604af384d 100644 --- a/dix/window.c +++ b/dix/window.c @@ -110,6 +110,7 @@ Equipment Corporation. #include "validate.h" #include "windowstr.h" #include "input.h" +#include "inputstr.h" #include "resource.h" #include "colormapst.h" #include "cursorstr.h" @@ -135,12 +136,21 @@ Equipment Corporation. * GetWindowAttributes, DeleteWindow, DestroySubWindows, * HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows, * UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow, - * + * ChangeWindowDeviceCursor ******/ static unsigned char _back_lsb[4] = {0x88, 0x22, 0x44, 0x11}; static unsigned char _back_msb[4] = {0x11, 0x44, 0x22, 0x88}; +static Bool WindowParentHasDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + CursorPtr pCurs); +static Bool +WindowSeekDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + DevCursNodePtr* pNode, + DevCursNodePtr* pPrev); + _X_EXPORT int screenIsSaved = SCREEN_SAVER_OFF; _X_EXPORT ScreenSaverStuffRec savedScreenInfo[MAXSCREENS]; @@ -440,6 +450,7 @@ CreateRootWindow(ScreenPtr pScreen) #endif #ifdef XINPUT pWin->optional->inputMasks = NULL; + pWin->optional->deviceCursors = NULL; #endif pWin->optional->colormap = pScreen->defColormap; pWin->optional->visual = pScreen->rootVisual; @@ -3639,6 +3650,17 @@ CheckWindowOptionalNeed (register WindowPtr w) if (optional->inputMasks != NULL) return; #endif + if (optional->deviceCursors != NULL) + { + DevCursNodePtr pNode = optional->deviceCursors; + while(pNode) + { + if (pNode->cursor != None) + return; + pNode = pNode->next; + } + } + parentOptional = FindWindowWithOptional(w)->optional; if (optional->visual != parentOptional->visual) return; @@ -3683,6 +3705,7 @@ MakeWindowOptional (register WindowPtr pWin) #endif #ifdef XINPUT optional->inputMasks = NULL; + optional->deviceCursors = NULL; #endif parentOptional = FindWindowWithOptional(pWin)->optional; optional->visual = parentOptional->visual; @@ -3731,10 +3754,227 @@ DisposeWindowOptional (register WindowPtr pWin) } else pWin->cursorIsNone = TRUE; + + if (pWin->optional->deviceCursors) + { + DevCursorList pList; + DevCursorList pPrev; + pList = pWin->optional->deviceCursors; + while(pList) + { + if (pList->cursor) + FreeCursor(pList->cursor, (XID)0); + pPrev = pList; + pList = pList->next; + xfree(pPrev); + } + pWin->optional->deviceCursors = NULL; + } + xfree (pWin->optional); pWin->optional = NULL; } +/* + * Changes the cursor struct for the given device and the given window. + * A cursor that does not have a device cursor set will use whatever the + * standard cursor is for the window. If all devices have a cursor set, + * changing the window cursor (e.g. using XDefineCursor()) will not have any + * visible effect. Only when one of the device cursors is set to None again, + * this device's cursor will display the changed standard cursor. + * + * CursorIsNone of the window struct is NOT modified if you set a device + * cursor. + * + * Assumption: If there is a node for a device in the list, the device has a + * cursor. If the cursor is set to None, it is inherited by the parent. + */ +int ChangeWindowDeviceCursor(register WindowPtr pWin, + DeviceIntPtr pDev, + CursorPtr pCursor) +{ + DevCursNodePtr pNode, pPrev; + CursorPtr pOldCursor = NULL; + ScreenPtr pScreen; + WindowPtr pChild; + + if (!pWin->optional && !MakeWindowOptional(pWin)) + return BadAlloc; + + /* 1) Check if window has device cursor set + * Yes: 1.1) swap cursor with given cursor if parent does not have same + * cursor, free old cursor + * 1.2) free old cursor, use parent cursor + * No: 1.1) add node to beginning of list. + * 1.2) add cursor to node if parent does not have same cursor + * 1.3) use parent cursor if parent does not have same cursor + * 2) Patch up children if child has a devcursor + * 2.1) if child has cursor None, it inherited from parent, set to old + * cursor + * 2.2) if child has same cursor as new cursor, remove and set to None + */ + + pScreen = pWin->drawable.pScreen; + + if (WindowSeekDeviceCursor(pWin, pDev, &pNode, &pPrev)) + { + /* has device cursor */ + + if (pNode->cursor == pCursor) + return Success; + + pOldCursor = pNode->cursor; + + if (!pCursor) /* remove from list */ + { + pPrev->next = pNode->next; + xfree(pNode); + } + + } else + { + /* no device cursor yet */ + DevCursNodePtr pNewNode; + + if (!pCursor) + return Success; + + pNewNode = (DevCursNodePtr)xalloc(sizeof(DevCursNodeRec)); + pNewNode->dev = pDev; + pNewNode->next = pWin->optional->deviceCursors; + pWin->optional->deviceCursors = pNewNode; + pNode = pNewNode; + + } + + if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor)) + pNode->cursor = None; + else + { + pNode->cursor = pCursor; + pCursor->refcnt++; + } + + pNode = pPrev = NULL; + /* fix up children */ + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev)) + { + if (pNode->cursor == None) /* inherited from parent */ + { + pNode->cursor = pOldCursor; + pOldCursor->refcnt++; + } else if (pNode->cursor == pCursor) + { + pNode->cursor = None; + FreeCursor(pCursor, (Cursor)0); /* fix up refcnt */ + } + } + } + + if (pWin->realized) + WindowHasNewCursor(pWin); + + if (pOldCursor) + FreeCursor(pOldCursor, (Cursor)0); + + /* FIXME: We SHOULD check for an error value here XXX + (comment taken from ChangeWindowAttributes) */ + (*pScreen->ChangeWindowAttributes)(pWin, CWCursor); + + return Success; +} + +/* Get device cursor for given device or None if none is set */ +CursorPtr WindowGetDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev) +{ + DevCursorList pList; + + if (!pWin->optional || !pWin->optional->deviceCursors) + return NULL; + + pList = pWin->optional->deviceCursors; + + while(pList) + { + if (pList->dev == pDev) + { + if (pList->cursor == None) /* inherited from parent */ + return WindowGetDeviceCursor(pWin->parent, pDev); + else + return pList->cursor; + } + pList = pList->next; + } + return NULL; +} + +/* Searches for a DevCursorNode for the given window and device. If one is + * found, return True and set pNode and pPrev to the node and to the node + * before the node respectively. Otherwise return False. + */ +static Bool +WindowSeekDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + DevCursNodePtr* pNode, + DevCursNodePtr* pPrev) +{ + DevCursorList pList; + + if (!pWin->optional) + return FALSE; + + pList = pWin->optional->deviceCursors; + while(pList) + { + if (pList->next) + { + if (pList->next->dev == pDev) + { + *pNode = pList->next; + *pPrev = pList; + return TRUE; + } + } + pList = pList->next; + } + return FALSE; +} + +/* Return True if a parent has the same device cursor set or False if + * otherwise + */ +static Bool +WindowParentHasDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + CursorPtr pCursor) +{ + WindowPtr pParent; + DevCursNodePtr pParentNode, pParentPrev; + + pParent = pWin->parent; + while(pParent) + { + if (WindowSeekDeviceCursor(pParent, pDev, + &pParentNode, &pParentPrev)) + { + /* if there is a node in the list, the win has a dev cursor */ + if (!pParentNode->cursor) /* inherited. loop needs to cont. */ + { + } else if (pParentNode->cursor == pCursor) /* inherit */ + return TRUE; + else /* different cursor */ + return FALSE; + } + else + /* parent does not have a device cursor for our device */ + return FALSE; + } + return FALSE; +} + + #ifndef NOLOGOHACK static void DrawLogo(WindowPtr pWin) diff --git a/include/window.h b/include/window.h index bddeb252b..8f2522cbb 100644 --- a/include/window.h +++ b/include/window.h @@ -67,6 +67,10 @@ SOFTWARE. #define WT_NOMATCH 3 #define NullWindow ((WindowPtr) 0) +/* Forward declaration, we can't include input.h here */ +struct _DeviceIntRec; +struct _Cursor; + typedef struct _BackingStore *BackingStorePtr; typedef struct _Window *WindowPtr; @@ -143,6 +147,15 @@ extern int ChangeWindowAttributes( XID* /*vlist*/, ClientPtr /*client*/); +extern int ChangeWindowDeviceCursor( + WindowPtr /*pWin*/, + struct _DeviceIntRec* /*pDev*/, + struct _Cursor* /*pCursor*/); + +extern struct _Cursor* WindowGetDeviceCursor( + WindowPtr /*pWin*/, + struct _DeviceIntRec* /*pDev*/); + /* Quartz support on Mac OS X uses the HIToolbox framework whose GetWindowAttributes function conflicts here. */ #ifdef __DARWIN__ diff --git a/include/windowstr.h b/include/windowstr.h index a37dc6b75..4e9c82cb5 100644 --- a/include/windowstr.h +++ b/include/windowstr.h @@ -70,6 +70,13 @@ SOFTWARE. #define SameBorder(as, a, bs, b) \ EqualPixUnion(as, a, bs, b) +/* used as NULL-terminated list */ +typedef struct _DevCursorNode { + CursorPtr cursor; + DeviceIntPtr dev; + struct _DevCursorNode* next; +} DevCursNodeRec, *DevCursNodePtr, *DevCursorList; + typedef struct _WindowOpt { VisualID visual; /* default: same as parent */ CursorPtr cursor; /* default: window.cursorNone */ @@ -89,6 +96,7 @@ typedef struct _WindowOpt { #ifdef XINPUT struct _OtherInputMasks *inputMasks; /* default: NULL */ #endif + DevCursorList deviceCursors; /* default: NULL */ } WindowOptRec, *WindowOptPtr; #define BackgroundPixel 2L |