105b261ecSmrg/* 205b261ecSmrg * 305b261ecSmrg * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. 405b261ecSmrg * 505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 705b261ecSmrg * the above copyright notice appear in all copies and that both that 805b261ecSmrg * copyright notice and this permission notice appear in supporting 905b261ecSmrg * documentation, and that the name of Keith Packard not be used in 1005b261ecSmrg * advertising or publicity pertaining to distribution of the software without 1105b261ecSmrg * specific, written prior permission. Keith Packard makes no 1205b261ecSmrg * representations about the suitability of this software for any purpose. It 1305b261ecSmrg * is provided "as is" without express or implied warranty. 1405b261ecSmrg * 1505b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1705b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2105b261ecSmrg * PERFORMANCE OF THIS SOFTWARE. 2205b261ecSmrg */ 2305b261ecSmrg 2405b261ecSmrg/* 2505b261ecSmrg * Animated cursors for X. Not specific to Render in any way, but 2605b261ecSmrg * stuck there because Render has the other cool cursor extension. 2705b261ecSmrg * Besides, everyone has Render. 2805b261ecSmrg * 2905b261ecSmrg * Implemented as a simple layer over the core cursor code; it 3005b261ecSmrg * creates composite cursors out of a set of static cursors and 3105b261ecSmrg * delta times between each image. 3205b261ecSmrg */ 3305b261ecSmrg 3405b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 3505b261ecSmrg#include <dix-config.h> 3605b261ecSmrg#endif 3705b261ecSmrg 3805b261ecSmrg#include <X11/X.h> 3905b261ecSmrg#include <X11/Xmd.h> 4005b261ecSmrg#include "servermd.h" 4105b261ecSmrg#include "scrnintstr.h" 4205b261ecSmrg#include "dixstruct.h" 4305b261ecSmrg#include "cursorstr.h" 4405b261ecSmrg#include "dixfontstr.h" 4505b261ecSmrg#include "opaque.h" 4605b261ecSmrg#include "picturestr.h" 474642e01fSmrg#include "inputstr.h" 484642e01fSmrg#include "xace.h" 4905b261ecSmrg 5005b261ecSmrgtypedef struct _AnimCurElt { 5135c4bbdfSmrg CursorPtr pCursor; /* cursor to show */ 5235c4bbdfSmrg CARD32 delay; /* in ms */ 5305b261ecSmrg} AnimCurElt; 5405b261ecSmrg 5505b261ecSmrgtypedef struct _AnimCur { 5635c4bbdfSmrg int nelt; /* number of elements in the elts array */ 5735c4bbdfSmrg AnimCurElt *elts; /* actually allocated right after the structure */ 581b5d61b8Smrg OsTimerPtr timer; 5905b261ecSmrg} AnimCurRec, *AnimCurPtr; 6005b261ecSmrg 6105b261ecSmrgtypedef struct _AnimScrPriv { 6235c4bbdfSmrg CloseScreenProcPtr CloseScreen; 6335c4bbdfSmrg CursorLimitsProcPtr CursorLimits; 6435c4bbdfSmrg DisplayCursorProcPtr DisplayCursor; 6535c4bbdfSmrg SetCursorPositionProcPtr SetCursorPosition; 6635c4bbdfSmrg RealizeCursorProcPtr RealizeCursor; 6735c4bbdfSmrg UnrealizeCursorProcPtr UnrealizeCursor; 6835c4bbdfSmrg RecolorCursorProcPtr RecolorCursor; 6905b261ecSmrg} AnimCurScreenRec, *AnimCurScreenPtr; 7005b261ecSmrg 7105b261ecSmrgstatic unsigned char empty[4]; 7205b261ecSmrg 7335c4bbdfSmrgstatic CursorBits animCursorBits = { 7405b261ecSmrg empty, empty, 2, 1, 1, 0, 0, 1 7505b261ecSmrg}; 7605b261ecSmrg 776747b715Smrgstatic DevPrivateKeyRec AnimCurScreenPrivateKeyRec; 7835c4bbdfSmrg 794642e01fSmrg#define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits)) 806747b715Smrg#define GetAnimCur(c) ((AnimCurPtr) ((((char *)(c) + CURSOR_REC_SIZE)))) 811b5d61b8Smrg#define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, &AnimCurScreenPrivateKeyRec)) 8205b261ecSmrg 8305b261ecSmrg#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) 8405b261ecSmrg#define Unwrap(as,s,elt) ((s)->elt = (as)->elt) 8505b261ecSmrg 8605b261ecSmrgstatic Bool 8735c4bbdfSmrgAnimCurCloseScreen(ScreenPtr pScreen) 8805b261ecSmrg{ 8935c4bbdfSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 9035c4bbdfSmrg Bool ret; 9105b261ecSmrg 9205b261ecSmrg Unwrap(as, pScreen, CloseScreen); 9305b261ecSmrg 9405b261ecSmrg Unwrap(as, pScreen, CursorLimits); 9505b261ecSmrg Unwrap(as, pScreen, DisplayCursor); 9605b261ecSmrg Unwrap(as, pScreen, SetCursorPosition); 9705b261ecSmrg Unwrap(as, pScreen, RealizeCursor); 9805b261ecSmrg Unwrap(as, pScreen, UnrealizeCursor); 9905b261ecSmrg Unwrap(as, pScreen, RecolorCursor); 10035c4bbdfSmrg ret = (*pScreen->CloseScreen) (pScreen); 10105b261ecSmrg return ret; 10205b261ecSmrg} 10305b261ecSmrg 10435c4bbdfSmrgstatic void 10535c4bbdfSmrgAnimCurCursorLimits(DeviceIntPtr pDev, 10635c4bbdfSmrg ScreenPtr pScreen, 10735c4bbdfSmrg CursorPtr pCursor, BoxPtr pHotBox, BoxPtr pTopLeftBox) 10805b261ecSmrg{ 10935c4bbdfSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 11005b261ecSmrg 11135c4bbdfSmrg Unwrap(as, pScreen, CursorLimits); 11235c4bbdfSmrg if (IsAnimCur(pCursor)) { 11335c4bbdfSmrg AnimCurPtr ac = GetAnimCur(pCursor); 11405b261ecSmrg 11535c4bbdfSmrg (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor, 11635c4bbdfSmrg pHotBox, pTopLeftBox); 11705b261ecSmrg } 11835c4bbdfSmrg else { 11935c4bbdfSmrg (*pScreen->CursorLimits) (pDev, pScreen, pCursor, pHotBox, pTopLeftBox); 12005b261ecSmrg } 12135c4bbdfSmrg Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); 12205b261ecSmrg} 12305b261ecSmrg 12405b261ecSmrg/* 1251b5d61b8Smrg * The cursor animation timer has expired, go display any relevant cursor changes 1261b5d61b8Smrg * and compute a new timeout value 12705b261ecSmrg */ 12805b261ecSmrg 1291b5d61b8Smrgstatic CARD32 1301b5d61b8SmrgAnimCurTimerNotify(OsTimerPtr timer, CARD32 now, void *arg) 13105b261ecSmrg{ 1321b5d61b8Smrg DeviceIntPtr dev = arg; 1331b5d61b8Smrg ScreenPtr pScreen = dev->spriteInfo->anim.pScreen; 13435c4bbdfSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 13535c4bbdfSmrg 1361b5d61b8Smrg AnimCurPtr ac = GetAnimCur(dev->spriteInfo->sprite->current); 1371b5d61b8Smrg int elt = (dev->spriteInfo->anim.elt + 1) % ac->nelt; 1381b5d61b8Smrg DisplayCursorProcPtr DisplayCursor = pScreen->DisplayCursor; 13935c4bbdfSmrg 1401b5d61b8Smrg /* 1411b5d61b8Smrg * Not a simple Unwrap/Wrap as this isn't called along the DisplayCursor 1421b5d61b8Smrg * wrapper chain. 1431b5d61b8Smrg */ 1441b5d61b8Smrg pScreen->DisplayCursor = as->DisplayCursor; 1451b5d61b8Smrg (void) (*pScreen->DisplayCursor) (dev, pScreen, ac->elts[elt].pCursor); 1461b5d61b8Smrg as->DisplayCursor = pScreen->DisplayCursor; 1471b5d61b8Smrg pScreen->DisplayCursor = DisplayCursor; 1484642e01fSmrg 1491b5d61b8Smrg dev->spriteInfo->anim.elt = elt; 1501b5d61b8Smrg dev->spriteInfo->anim.pCursor = ac->elts[elt].pCursor; 15135c4bbdfSmrg 1521b5d61b8Smrg return ac->elts[elt].delay; 1531b5d61b8Smrg} 1544642e01fSmrg 1551b5d61b8Smrgstatic void 1561b5d61b8SmrgAnimCurCancelTimer(DeviceIntPtr pDev) 1571b5d61b8Smrg{ 1581b5d61b8Smrg CursorPtr cur = pDev->spriteInfo->sprite ? 1591b5d61b8Smrg pDev->spriteInfo->sprite->current : NULL; 1604642e01fSmrg 1611b5d61b8Smrg if (IsAnimCur(cur)) 1621b5d61b8Smrg TimerCancel(GetAnimCur(cur)->timer); 16305b261ecSmrg} 16405b261ecSmrg 16505b261ecSmrgstatic Bool 16635c4bbdfSmrgAnimCurDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 16705b261ecSmrg{ 16835c4bbdfSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 1691b5d61b8Smrg Bool ret = TRUE; 17005b261ecSmrg 17135c4bbdfSmrg if (IsFloating(pDev)) 17235c4bbdfSmrg return FALSE; 17305b261ecSmrg 17435c4bbdfSmrg Unwrap(as, pScreen, DisplayCursor); 17535c4bbdfSmrg if (IsAnimCur(pCursor)) { 1761b5d61b8Smrg if (pCursor != pDev->spriteInfo->sprite->current) { 17735c4bbdfSmrg AnimCurPtr ac = GetAnimCur(pCursor); 17835c4bbdfSmrg 1791b5d61b8Smrg AnimCurCancelTimer(pDev); 1801b5d61b8Smrg ret = (*pScreen->DisplayCursor) (pDev, pScreen, 1811b5d61b8Smrg ac->elts[0].pCursor); 1821b5d61b8Smrg 18335c4bbdfSmrg if (ret) { 18435c4bbdfSmrg pDev->spriteInfo->anim.elt = 0; 18535c4bbdfSmrg pDev->spriteInfo->anim.pCursor = pCursor; 18635c4bbdfSmrg pDev->spriteInfo->anim.pScreen = pScreen; 18735c4bbdfSmrg 1881b5d61b8Smrg ac->timer = TimerSet(ac->timer, 0, ac->elts[0].delay, 1891b5d61b8Smrg AnimCurTimerNotify, pDev); 19035c4bbdfSmrg } 19135c4bbdfSmrg } 19205b261ecSmrg } 19335c4bbdfSmrg else { 1941b5d61b8Smrg AnimCurCancelTimer(pDev); 19535c4bbdfSmrg pDev->spriteInfo->anim.pCursor = 0; 19635c4bbdfSmrg pDev->spriteInfo->anim.pScreen = 0; 19735c4bbdfSmrg ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); 19805b261ecSmrg } 19935c4bbdfSmrg Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); 20005b261ecSmrg return ret; 20105b261ecSmrg} 20205b261ecSmrg 20305b261ecSmrgstatic Bool 20435c4bbdfSmrgAnimCurSetCursorPosition(DeviceIntPtr pDev, 20535c4bbdfSmrg ScreenPtr pScreen, int x, int y, Bool generateEvent) 20605b261ecSmrg{ 20735c4bbdfSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 20835c4bbdfSmrg Bool ret; 20935c4bbdfSmrg 21035c4bbdfSmrg Unwrap(as, pScreen, SetCursorPosition); 2119ace9065Smrg if (pDev->spriteInfo->anim.pCursor) { 21235c4bbdfSmrg pDev->spriteInfo->anim.pScreen = pScreen; 2139ace9065Smrg } 2144642e01fSmrg ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent); 21535c4bbdfSmrg Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 21605b261ecSmrg return ret; 21705b261ecSmrg} 21805b261ecSmrg 21935c4bbdfSmrgstatic Bool 22035c4bbdfSmrgAnimCurRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 22105b261ecSmrg{ 22235c4bbdfSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 22335c4bbdfSmrg Bool ret; 22435c4bbdfSmrg 22535c4bbdfSmrg Unwrap(as, pScreen, RealizeCursor); 22605b261ecSmrg if (IsAnimCur(pCursor)) 22735c4bbdfSmrg ret = TRUE; 22805b261ecSmrg else 22935c4bbdfSmrg ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor); 23035c4bbdfSmrg Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); 23105b261ecSmrg return ret; 23205b261ecSmrg} 23305b261ecSmrg 23435c4bbdfSmrgstatic Bool 23535c4bbdfSmrgAnimCurUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 23605b261ecSmrg{ 23735c4bbdfSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 23835c4bbdfSmrg Bool ret; 23935c4bbdfSmrg 24035c4bbdfSmrg Unwrap(as, pScreen, UnrealizeCursor); 24135c4bbdfSmrg if (IsAnimCur(pCursor)) { 24235c4bbdfSmrg AnimCurPtr ac = GetAnimCur(pCursor); 24335c4bbdfSmrg int i; 24435c4bbdfSmrg 24535c4bbdfSmrg if (pScreen->myNum == 0) 24635c4bbdfSmrg for (i = 0; i < ac->nelt; i++) 24735c4bbdfSmrg FreeCursor(ac->elts[i].pCursor, 0); 24835c4bbdfSmrg ret = TRUE; 24905b261ecSmrg } 25005b261ecSmrg else 25135c4bbdfSmrg ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); 25235c4bbdfSmrg Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 25305b261ecSmrg return ret; 25405b261ecSmrg} 25505b261ecSmrg 25605b261ecSmrgstatic void 25735c4bbdfSmrgAnimCurRecolorCursor(DeviceIntPtr pDev, 25835c4bbdfSmrg ScreenPtr pScreen, CursorPtr pCursor, Bool displayed) 25905b261ecSmrg{ 26035c4bbdfSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 26135c4bbdfSmrg 26235c4bbdfSmrg Unwrap(as, pScreen, RecolorCursor); 26335c4bbdfSmrg if (IsAnimCur(pCursor)) { 26435c4bbdfSmrg AnimCurPtr ac = GetAnimCur(pCursor); 26535c4bbdfSmrg int i; 26605b261ecSmrg 26705b261ecSmrg for (i = 0; i < ac->nelt; i++) 26835c4bbdfSmrg (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor, 26935c4bbdfSmrg displayed && 27035c4bbdfSmrg pDev->spriteInfo->anim.elt == i); 27105b261ecSmrg } 27205b261ecSmrg else 27335c4bbdfSmrg (*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed); 27435c4bbdfSmrg Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); 27505b261ecSmrg} 27605b261ecSmrg 27705b261ecSmrgBool 27835c4bbdfSmrgAnimCurInit(ScreenPtr pScreen) 27905b261ecSmrg{ 28035c4bbdfSmrg AnimCurScreenPtr as; 28105b261ecSmrg 2821b5d61b8Smrg if (!dixRegisterPrivateKey(&AnimCurScreenPrivateKeyRec, PRIVATE_SCREEN, 2831b5d61b8Smrg sizeof(AnimCurScreenRec))) 28435c4bbdfSmrg return FALSE; 2856747b715Smrg 2861b5d61b8Smrg as = GetAnimCurScreen(pScreen); 28705b261ecSmrg 2881b5d61b8Smrg Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen); 28905b261ecSmrg 29005b261ecSmrg Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); 29105b261ecSmrg Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); 29205b261ecSmrg Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 29305b261ecSmrg Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); 29405b261ecSmrg Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 29505b261ecSmrg Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); 29605b261ecSmrg return TRUE; 29705b261ecSmrg} 29805b261ecSmrg 29905b261ecSmrgint 30035c4bbdfSmrgAnimCursorCreate(CursorPtr *cursors, CARD32 *deltas, int ncursor, 30135c4bbdfSmrg CursorPtr *ppCursor, ClientPtr client, XID cid) 30205b261ecSmrg{ 30335c4bbdfSmrg CursorPtr pCursor; 3041b5d61b8Smrg int rc = BadAlloc, i; 30535c4bbdfSmrg AnimCurPtr ac; 30605b261ecSmrg 30754b5899cSmrg if (ncursor <= 0) 30854b5899cSmrg return BadValue; 30954b5899cSmrg 31005b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 31135c4bbdfSmrg if (!GetAnimCurScreen(screenInfo.screens[i])) 31235c4bbdfSmrg return BadImplementation; 31305b261ecSmrg 31405b261ecSmrg for (i = 0; i < ncursor; i++) 31535c4bbdfSmrg if (IsAnimCur(cursors[i])) 31635c4bbdfSmrg return BadMatch; 31735c4bbdfSmrg 3186747b715Smrg pCursor = (CursorPtr) calloc(CURSOR_REC_SIZE + 31935c4bbdfSmrg sizeof(AnimCurRec) + 32035c4bbdfSmrg ncursor * sizeof(AnimCurElt), 1); 32105b261ecSmrg if (!pCursor) 3221b5d61b8Smrg return rc; 3236747b715Smrg dixInitPrivates(pCursor, pCursor + 1, PRIVATE_CURSOR); 32405b261ecSmrg pCursor->bits = &animCursorBits; 32505b261ecSmrg pCursor->refcnt = 1; 32635c4bbdfSmrg 32705b261ecSmrg pCursor->foreRed = cursors[0]->foreRed; 32805b261ecSmrg pCursor->foreGreen = cursors[0]->foreGreen; 32905b261ecSmrg pCursor->foreBlue = cursors[0]->foreBlue; 33035c4bbdfSmrg 33105b261ecSmrg pCursor->backRed = cursors[0]->backRed; 33205b261ecSmrg pCursor->backGreen = cursors[0]->backGreen; 33305b261ecSmrg pCursor->backBlue = cursors[0]->backBlue; 33405b261ecSmrg 3354642e01fSmrg pCursor->id = cid; 3364642e01fSmrg 3371b5d61b8Smrg ac = GetAnimCur(pCursor); 3381b5d61b8Smrg ac->timer = TimerSet(NULL, 0, 0, AnimCurTimerNotify, NULL); 3391b5d61b8Smrg 3404642e01fSmrg /* security creation/labeling check */ 3411b5d61b8Smrg if (ac->timer) 3421b5d61b8Smrg rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor, 3431b5d61b8Smrg RT_NONE, NULL, DixCreateAccess); 3441b5d61b8Smrg 3454642e01fSmrg if (rc != Success) { 3461b5d61b8Smrg TimerFree(ac->timer); 34735c4bbdfSmrg dixFiniPrivates(pCursor, PRIVATE_CURSOR); 34835c4bbdfSmrg free(pCursor); 34935c4bbdfSmrg return rc; 3504642e01fSmrg } 35135c4bbdfSmrg 35205b261ecSmrg /* 35305b261ecSmrg * Fill in the AnimCurRec 35405b261ecSmrg */ 3554642e01fSmrg animCursorBits.refcnt++; 35605b261ecSmrg ac->nelt = ncursor; 35705b261ecSmrg ac->elts = (AnimCurElt *) (ac + 1); 35835c4bbdfSmrg 35935c4bbdfSmrg for (i = 0; i < ncursor; i++) { 36035c4bbdfSmrg ac->elts[i].pCursor = RefCursor(cursors[i]); 36135c4bbdfSmrg ac->elts[i].delay = deltas[i]; 36205b261ecSmrg } 36335c4bbdfSmrg 36405b261ecSmrg *ppCursor = pCursor; 36505b261ecSmrg return Success; 36605b261ecSmrg} 367