1706f2543Smrg/* 2706f2543Smrg * 3706f2543Smrg * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. 4706f2543Smrg * 5706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 7706f2543Smrg * the above copyright notice appear in all copies and that both that 8706f2543Smrg * copyright notice and this permission notice appear in supporting 9706f2543Smrg * documentation, and that the name of Keith Packard not be used in 10706f2543Smrg * advertising or publicity pertaining to distribution of the software without 11706f2543Smrg * specific, written prior permission. Keith Packard makes no 12706f2543Smrg * representations about the suitability of this software for any purpose. It 13706f2543Smrg * is provided "as is" without express or implied warranty. 14706f2543Smrg * 15706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21706f2543Smrg * PERFORMANCE OF THIS SOFTWARE. 22706f2543Smrg */ 23706f2543Smrg 24706f2543Smrg/* 25706f2543Smrg * Animated cursors for X. Not specific to Render in any way, but 26706f2543Smrg * stuck there because Render has the other cool cursor extension. 27706f2543Smrg * Besides, everyone has Render. 28706f2543Smrg * 29706f2543Smrg * Implemented as a simple layer over the core cursor code; it 30706f2543Smrg * creates composite cursors out of a set of static cursors and 31706f2543Smrg * delta times between each image. 32706f2543Smrg */ 33706f2543Smrg 34706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 35706f2543Smrg#include <dix-config.h> 36706f2543Smrg#endif 37706f2543Smrg 38706f2543Smrg#include <X11/X.h> 39706f2543Smrg#include <X11/Xmd.h> 40706f2543Smrg#include "servermd.h" 41706f2543Smrg#include "scrnintstr.h" 42706f2543Smrg#include "dixstruct.h" 43706f2543Smrg#include "cursorstr.h" 44706f2543Smrg#include "dixfontstr.h" 45706f2543Smrg#include "opaque.h" 46706f2543Smrg#include "picturestr.h" 47706f2543Smrg#include "inputstr.h" 48706f2543Smrg#include "xace.h" 49706f2543Smrg 50706f2543Smrgtypedef struct _AnimCurElt { 51706f2543Smrg CursorPtr pCursor; /* cursor to show */ 52706f2543Smrg CARD32 delay; /* in ms */ 53706f2543Smrg} AnimCurElt; 54706f2543Smrg 55706f2543Smrgtypedef struct _AnimCur { 56706f2543Smrg int nelt; /* number of elements in the elts array */ 57706f2543Smrg AnimCurElt *elts; /* actually allocated right after the structure */ 58706f2543Smrg} AnimCurRec, *AnimCurPtr; 59706f2543Smrg 60706f2543Smrgtypedef struct _AnimScrPriv { 61706f2543Smrg CloseScreenProcPtr CloseScreen; 62706f2543Smrg 63706f2543Smrg ScreenBlockHandlerProcPtr BlockHandler; 64706f2543Smrg 65706f2543Smrg CursorLimitsProcPtr CursorLimits; 66706f2543Smrg DisplayCursorProcPtr DisplayCursor; 67706f2543Smrg SetCursorPositionProcPtr SetCursorPosition; 68706f2543Smrg RealizeCursorProcPtr RealizeCursor; 69706f2543Smrg UnrealizeCursorProcPtr UnrealizeCursor; 70706f2543Smrg RecolorCursorProcPtr RecolorCursor; 71706f2543Smrg} AnimCurScreenRec, *AnimCurScreenPtr; 72706f2543Smrg 73706f2543Smrgstatic unsigned char empty[4]; 74706f2543Smrg 75706f2543Smrgstatic CursorBits animCursorBits = { 76706f2543Smrg empty, empty, 2, 1, 1, 0, 0, 1 77706f2543Smrg}; 78706f2543Smrg 79706f2543Smrgstatic DevPrivateKeyRec AnimCurScreenPrivateKeyRec; 80706f2543Smrg#define AnimCurScreenPrivateKey (&AnimCurScreenPrivateKeyRec) 81706f2543Smrg 82706f2543Smrg#define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits)) 83706f2543Smrg#define GetAnimCur(c) ((AnimCurPtr) ((((char *)(c) + CURSOR_REC_SIZE)))) 84706f2543Smrg#define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey)) 85706f2543Smrg#define SetAnimCurScreen(s,p) dixSetPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey, p) 86706f2543Smrg 87706f2543Smrg#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) 88706f2543Smrg#define Unwrap(as,s,elt) ((s)->elt = (as)->elt) 89706f2543Smrg 90706f2543Smrg 91706f2543Smrgstatic Bool 92706f2543SmrgAnimCurCloseScreen (int index, ScreenPtr pScreen) 93706f2543Smrg{ 94706f2543Smrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 95706f2543Smrg Bool ret; 96706f2543Smrg 97706f2543Smrg Unwrap(as, pScreen, CloseScreen); 98706f2543Smrg 99706f2543Smrg Unwrap(as, pScreen, CursorLimits); 100706f2543Smrg Unwrap(as, pScreen, DisplayCursor); 101706f2543Smrg Unwrap(as, pScreen, SetCursorPosition); 102706f2543Smrg Unwrap(as, pScreen, RealizeCursor); 103706f2543Smrg Unwrap(as, pScreen, UnrealizeCursor); 104706f2543Smrg Unwrap(as, pScreen, RecolorCursor); 105706f2543Smrg SetAnimCurScreen(pScreen,0); 106706f2543Smrg ret = (*pScreen->CloseScreen) (index, pScreen); 107706f2543Smrg free(as); 108706f2543Smrg return ret; 109706f2543Smrg} 110706f2543Smrg 111706f2543Smrgstatic void 112706f2543SmrgAnimCurCursorLimits (DeviceIntPtr pDev, 113706f2543Smrg ScreenPtr pScreen, 114706f2543Smrg CursorPtr pCursor, 115706f2543Smrg BoxPtr pHotBox, 116706f2543Smrg BoxPtr pTopLeftBox) 117706f2543Smrg{ 118706f2543Smrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 119706f2543Smrg 120706f2543Smrg Unwrap (as, pScreen, CursorLimits); 121706f2543Smrg if (IsAnimCur(pCursor)) 122706f2543Smrg { 123706f2543Smrg AnimCurPtr ac = GetAnimCur(pCursor); 124706f2543Smrg 125706f2543Smrg (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor, 126706f2543Smrg pHotBox, pTopLeftBox); 127706f2543Smrg } 128706f2543Smrg else 129706f2543Smrg { 130706f2543Smrg (*pScreen->CursorLimits) (pDev, pScreen, pCursor, 131706f2543Smrg pHotBox, pTopLeftBox); 132706f2543Smrg } 133706f2543Smrg Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits); 134706f2543Smrg} 135706f2543Smrg 136706f2543Smrg/* 137706f2543Smrg * This has to be a screen block handler instead of a generic 138706f2543Smrg * block handler so that it is well ordered with respect to the DRI 139706f2543Smrg * block handler responsible for releasing the hardware to DRI clients 140706f2543Smrg */ 141706f2543Smrg 142706f2543Smrgstatic void 143706f2543SmrgAnimCurScreenBlockHandler (int screenNum, 144706f2543Smrg pointer blockData, 145706f2543Smrg pointer pTimeout, 146706f2543Smrg pointer pReadmask) 147706f2543Smrg{ 148706f2543Smrg ScreenPtr pScreen = screenInfo.screens[screenNum]; 149706f2543Smrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 150706f2543Smrg DeviceIntPtr dev; 151706f2543Smrg Bool activeDevice = FALSE; 152706f2543Smrg CARD32 now = 0, 153706f2543Smrg soonest = ~0; /* earliest time to wakeup again */ 154706f2543Smrg 155706f2543Smrg for (dev = inputInfo.devices; dev; dev = dev->next) 156706f2543Smrg { 157706f2543Smrg if (IsPointerDevice(dev) && pScreen == dev->spriteInfo->anim.pScreen) 158706f2543Smrg { 159706f2543Smrg if (!activeDevice) { 160706f2543Smrg now = GetTimeInMillis (); 161706f2543Smrg activeDevice = TRUE; 162706f2543Smrg } 163706f2543Smrg 164706f2543Smrg if ((INT32) (now - dev->spriteInfo->anim.time) >= 0) 165706f2543Smrg { 166706f2543Smrg AnimCurPtr ac = GetAnimCur(dev->spriteInfo->anim.pCursor); 167706f2543Smrg int elt = (dev->spriteInfo->anim.elt + 1) % ac->nelt; 168706f2543Smrg DisplayCursorProcPtr DisplayCursor; 169706f2543Smrg 170706f2543Smrg /* 171706f2543Smrg * Not a simple Unwrap/Wrap as this 172706f2543Smrg * isn't called along the DisplayCursor 173706f2543Smrg * wrapper chain. 174706f2543Smrg */ 175706f2543Smrg DisplayCursor = pScreen->DisplayCursor; 176706f2543Smrg pScreen->DisplayCursor = as->DisplayCursor; 177706f2543Smrg (void) (*pScreen->DisplayCursor) (dev, 178706f2543Smrg pScreen, 179706f2543Smrg ac->elts[elt].pCursor); 180706f2543Smrg as->DisplayCursor = pScreen->DisplayCursor; 181706f2543Smrg pScreen->DisplayCursor = DisplayCursor; 182706f2543Smrg 183706f2543Smrg dev->spriteInfo->anim.elt = elt; 184706f2543Smrg dev->spriteInfo->anim.time = now + ac->elts[elt].delay; 185706f2543Smrg } 186706f2543Smrg 187706f2543Smrg if (soonest > dev->spriteInfo->anim.time) 188706f2543Smrg soonest = dev->spriteInfo->anim.time; 189706f2543Smrg } 190706f2543Smrg } 191706f2543Smrg 192706f2543Smrg if (activeDevice) 193706f2543Smrg AdjustWaitForDelay (pTimeout, soonest - now); 194706f2543Smrg 195706f2543Smrg Unwrap (as, pScreen, BlockHandler); 196706f2543Smrg (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); 197706f2543Smrg if (activeDevice) 198706f2543Smrg Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 199706f2543Smrg else 200706f2543Smrg as->BlockHandler = NULL; 201706f2543Smrg} 202706f2543Smrg 203706f2543Smrgstatic Bool 204706f2543SmrgAnimCurDisplayCursor (DeviceIntPtr pDev, 205706f2543Smrg ScreenPtr pScreen, 206706f2543Smrg CursorPtr pCursor) 207706f2543Smrg{ 208706f2543Smrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 209706f2543Smrg Bool ret; 210706f2543Smrg 211706f2543Smrg Unwrap (as, pScreen, DisplayCursor); 212706f2543Smrg if (IsAnimCur(pCursor)) 213706f2543Smrg { 214706f2543Smrg if (pCursor != pDev->spriteInfo->anim.pCursor) 215706f2543Smrg { 216706f2543Smrg AnimCurPtr ac = GetAnimCur(pCursor); 217706f2543Smrg 218706f2543Smrg ret = (*pScreen->DisplayCursor) 219706f2543Smrg (pDev, pScreen, ac->elts[0].pCursor); 220706f2543Smrg if (ret) 221706f2543Smrg { 222706f2543Smrg pDev->spriteInfo->anim.elt = 0; 223706f2543Smrg pDev->spriteInfo->anim.time = GetTimeInMillis () + ac->elts[0].delay; 224706f2543Smrg pDev->spriteInfo->anim.pCursor = pCursor; 225706f2543Smrg pDev->spriteInfo->anim.pScreen = pScreen; 226706f2543Smrg 227706f2543Smrg if (!as->BlockHandler) 228706f2543Smrg Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 229706f2543Smrg } 230706f2543Smrg } 231706f2543Smrg else 232706f2543Smrg ret = TRUE; 233706f2543Smrg } 234706f2543Smrg else 235706f2543Smrg { 236706f2543Smrg pDev->spriteInfo->anim.pCursor = 0; 237706f2543Smrg pDev->spriteInfo->anim.pScreen = 0; 238706f2543Smrg ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); 239706f2543Smrg } 240706f2543Smrg Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor); 241706f2543Smrg return ret; 242706f2543Smrg} 243706f2543Smrg 244706f2543Smrgstatic Bool 245706f2543SmrgAnimCurSetCursorPosition (DeviceIntPtr pDev, 246706f2543Smrg ScreenPtr pScreen, 247706f2543Smrg int x, 248706f2543Smrg int y, 249706f2543Smrg Bool generateEvent) 250706f2543Smrg{ 251706f2543Smrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 252706f2543Smrg Bool ret; 253706f2543Smrg 254706f2543Smrg Unwrap (as, pScreen, SetCursorPosition); 255706f2543Smrg if (pDev->spriteInfo->anim.pCursor) { 256706f2543Smrg pDev->spriteInfo->anim.pScreen = pScreen; 257706f2543Smrg 258706f2543Smrg if (!as->BlockHandler) 259706f2543Smrg Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 260706f2543Smrg } 261706f2543Smrg ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent); 262706f2543Smrg Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 263706f2543Smrg return ret; 264706f2543Smrg} 265706f2543Smrg 266706f2543Smrgstatic Bool 267706f2543SmrgAnimCurRealizeCursor (DeviceIntPtr pDev, 268706f2543Smrg ScreenPtr pScreen, 269706f2543Smrg CursorPtr pCursor) 270706f2543Smrg{ 271706f2543Smrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 272706f2543Smrg Bool ret; 273706f2543Smrg 274706f2543Smrg Unwrap (as, pScreen, RealizeCursor); 275706f2543Smrg if (IsAnimCur(pCursor)) 276706f2543Smrg ret = TRUE; 277706f2543Smrg else 278706f2543Smrg ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor); 279706f2543Smrg Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor); 280706f2543Smrg return ret; 281706f2543Smrg} 282706f2543Smrg 283706f2543Smrgstatic Bool 284706f2543SmrgAnimCurUnrealizeCursor (DeviceIntPtr pDev, 285706f2543Smrg ScreenPtr pScreen, 286706f2543Smrg CursorPtr pCursor) 287706f2543Smrg{ 288706f2543Smrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 289706f2543Smrg Bool ret; 290706f2543Smrg 291706f2543Smrg Unwrap (as, pScreen, UnrealizeCursor); 292706f2543Smrg if (IsAnimCur(pCursor)) 293706f2543Smrg { 294706f2543Smrg AnimCurPtr ac = GetAnimCur(pCursor); 295706f2543Smrg int i; 296706f2543Smrg 297706f2543Smrg if (pScreen->myNum == 0) 298706f2543Smrg for (i = 0; i < ac->nelt; i++) 299706f2543Smrg FreeCursor (ac->elts[i].pCursor, 0); 300706f2543Smrg ret = TRUE; 301706f2543Smrg } 302706f2543Smrg else 303706f2543Smrg ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); 304706f2543Smrg Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 305706f2543Smrg return ret; 306706f2543Smrg} 307706f2543Smrg 308706f2543Smrgstatic void 309706f2543SmrgAnimCurRecolorCursor (DeviceIntPtr pDev, 310706f2543Smrg ScreenPtr pScreen, 311706f2543Smrg CursorPtr pCursor, 312706f2543Smrg Bool displayed) 313706f2543Smrg{ 314706f2543Smrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 315706f2543Smrg 316706f2543Smrg Unwrap (as, pScreen, RecolorCursor); 317706f2543Smrg if (IsAnimCur(pCursor)) 318706f2543Smrg { 319706f2543Smrg AnimCurPtr ac = GetAnimCur(pCursor); 320706f2543Smrg int i; 321706f2543Smrg 322706f2543Smrg for (i = 0; i < ac->nelt; i++) 323706f2543Smrg (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor, 324706f2543Smrg displayed && 325706f2543Smrg pDev->spriteInfo->anim.elt == i); 326706f2543Smrg } 327706f2543Smrg else 328706f2543Smrg (*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed); 329706f2543Smrg Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor); 330706f2543Smrg} 331706f2543Smrg 332706f2543SmrgBool 333706f2543SmrgAnimCurInit (ScreenPtr pScreen) 334706f2543Smrg{ 335706f2543Smrg AnimCurScreenPtr as; 336706f2543Smrg 337706f2543Smrg if (!dixRegisterPrivateKey(&AnimCurScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 338706f2543Smrg return FALSE; 339706f2543Smrg 340706f2543Smrg as = (AnimCurScreenPtr) malloc(sizeof (AnimCurScreenRec)); 341706f2543Smrg if (!as) 342706f2543Smrg return FALSE; 343706f2543Smrg Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen); 344706f2543Smrg 345706f2543Smrg as->BlockHandler = NULL; 346706f2543Smrg 347706f2543Smrg Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); 348706f2543Smrg Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); 349706f2543Smrg Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 350706f2543Smrg Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); 351706f2543Smrg Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 352706f2543Smrg Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); 353706f2543Smrg SetAnimCurScreen(pScreen,as); 354706f2543Smrg return TRUE; 355706f2543Smrg} 356706f2543Smrg 357706f2543Smrgint 358706f2543SmrgAnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor, ClientPtr client, XID cid) 359706f2543Smrg{ 360706f2543Smrg CursorPtr pCursor; 361706f2543Smrg int rc, i; 362706f2543Smrg AnimCurPtr ac; 363706f2543Smrg 364706f2543Smrg for (i = 0; i < screenInfo.numScreens; i++) 365706f2543Smrg if (!GetAnimCurScreen (screenInfo.screens[i])) 366706f2543Smrg return BadImplementation; 367706f2543Smrg 368706f2543Smrg for (i = 0; i < ncursor; i++) 369706f2543Smrg if (IsAnimCur (cursors[i])) 370706f2543Smrg return BadMatch; 371706f2543Smrg 372706f2543Smrg pCursor = (CursorPtr) calloc(CURSOR_REC_SIZE + 373706f2543Smrg sizeof (AnimCurRec) + 374706f2543Smrg ncursor * sizeof (AnimCurElt), 1); 375706f2543Smrg if (!pCursor) 376706f2543Smrg return BadAlloc; 377706f2543Smrg dixInitPrivates(pCursor, pCursor + 1, PRIVATE_CURSOR); 378706f2543Smrg pCursor->bits = &animCursorBits; 379706f2543Smrg pCursor->refcnt = 1; 380706f2543Smrg 381706f2543Smrg pCursor->foreRed = cursors[0]->foreRed; 382706f2543Smrg pCursor->foreGreen = cursors[0]->foreGreen; 383706f2543Smrg pCursor->foreBlue = cursors[0]->foreBlue; 384706f2543Smrg 385706f2543Smrg pCursor->backRed = cursors[0]->backRed; 386706f2543Smrg pCursor->backGreen = cursors[0]->backGreen; 387706f2543Smrg pCursor->backBlue = cursors[0]->backBlue; 388706f2543Smrg 389706f2543Smrg pCursor->id = cid; 390706f2543Smrg 391706f2543Smrg /* security creation/labeling check */ 392706f2543Smrg rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor, 393706f2543Smrg RT_NONE, NULL, DixCreateAccess); 394706f2543Smrg if (rc != Success) { 395706f2543Smrg dixFiniPrivates(pCursor, PRIVATE_CURSOR); 396706f2543Smrg free(pCursor); 397706f2543Smrg return rc; 398706f2543Smrg } 399706f2543Smrg 400706f2543Smrg /* 401706f2543Smrg * Fill in the AnimCurRec 402706f2543Smrg */ 403706f2543Smrg animCursorBits.refcnt++; 404706f2543Smrg ac = GetAnimCur (pCursor); 405706f2543Smrg ac->nelt = ncursor; 406706f2543Smrg ac->elts = (AnimCurElt *) (ac + 1); 407706f2543Smrg 408706f2543Smrg for (i = 0; i < ncursor; i++) 409706f2543Smrg { 410706f2543Smrg cursors[i]->refcnt++; 411706f2543Smrg ac->elts[i].pCursor = cursors[i]; 412706f2543Smrg ac->elts[i].delay = deltas[i]; 413706f2543Smrg } 414706f2543Smrg 415706f2543Smrg *ppCursor = pCursor; 416706f2543Smrg return Success; 417706f2543Smrg} 418