1/* 2 * 3 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that 8 * copyright notice and this permission notice appear in supporting 9 * documentation, and that the name of Keith Packard not be used in 10 * advertising or publicity pertaining to distribution of the software without 11 * specific, written prior permission. Keith Packard makes no 12 * representations about the suitability of this software for any purpose. It 13 * is provided "as is" without express or implied warranty. 14 * 15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24/* 25 * Animated cursors for X. Not specific to Render in any way, but 26 * stuck there because Render has the other cool cursor extension. 27 * Besides, everyone has Render. 28 * 29 * Implemented as a simple layer over the core cursor code; it 30 * creates composite cursors out of a set of static cursors and 31 * delta times between each image. 32 */ 33 34#ifdef HAVE_DIX_CONFIG_H 35#include <dix-config.h> 36#endif 37 38#include <X11/X.h> 39#include <X11/Xmd.h> 40#include "servermd.h" 41#include "scrnintstr.h" 42#include "dixstruct.h" 43#include "cursorstr.h" 44#include "dixfontstr.h" 45#include "opaque.h" 46#include "picturestr.h" 47#include "inputstr.h" 48#include "xace.h" 49 50typedef struct _AnimCurElt { 51 CursorPtr pCursor; /* cursor to show */ 52 CARD32 delay; /* in ms */ 53} AnimCurElt; 54 55typedef struct _AnimCur { 56 int nelt; /* number of elements in the elts array */ 57 AnimCurElt *elts; /* actually allocated right after the structure */ 58 OsTimerPtr timer; 59} AnimCurRec, *AnimCurPtr; 60 61typedef struct _AnimScrPriv { 62 CloseScreenProcPtr CloseScreen; 63 CursorLimitsProcPtr CursorLimits; 64 DisplayCursorProcPtr DisplayCursor; 65 SetCursorPositionProcPtr SetCursorPosition; 66 RealizeCursorProcPtr RealizeCursor; 67 UnrealizeCursorProcPtr UnrealizeCursor; 68 RecolorCursorProcPtr RecolorCursor; 69} AnimCurScreenRec, *AnimCurScreenPtr; 70 71static unsigned char empty[4]; 72 73static CursorBits animCursorBits = { 74 empty, empty, 2, 1, 1, 0, 0, 1 75}; 76 77static DevPrivateKeyRec AnimCurScreenPrivateKeyRec; 78 79#define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits)) 80#define GetAnimCur(c) ((AnimCurPtr) ((((char *)(c) + CURSOR_REC_SIZE)))) 81#define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, &AnimCurScreenPrivateKeyRec)) 82 83#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) 84#define Unwrap(as,s,elt) ((s)->elt = (as)->elt) 85 86static Bool 87AnimCurCloseScreen(ScreenPtr pScreen) 88{ 89 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 90 Bool ret; 91 92 Unwrap(as, pScreen, CloseScreen); 93 94 Unwrap(as, pScreen, CursorLimits); 95 Unwrap(as, pScreen, DisplayCursor); 96 Unwrap(as, pScreen, SetCursorPosition); 97 Unwrap(as, pScreen, RealizeCursor); 98 Unwrap(as, pScreen, UnrealizeCursor); 99 Unwrap(as, pScreen, RecolorCursor); 100 ret = (*pScreen->CloseScreen) (pScreen); 101 return ret; 102} 103 104static void 105AnimCurCursorLimits(DeviceIntPtr pDev, 106 ScreenPtr pScreen, 107 CursorPtr pCursor, BoxPtr pHotBox, BoxPtr pTopLeftBox) 108{ 109 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 110 111 Unwrap(as, pScreen, CursorLimits); 112 if (IsAnimCur(pCursor)) { 113 AnimCurPtr ac = GetAnimCur(pCursor); 114 115 (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor, 116 pHotBox, pTopLeftBox); 117 } 118 else { 119 (*pScreen->CursorLimits) (pDev, pScreen, pCursor, pHotBox, pTopLeftBox); 120 } 121 Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); 122} 123 124/* 125 * The cursor animation timer has expired, go display any relevant cursor changes 126 * and compute a new timeout value 127 */ 128 129static CARD32 130AnimCurTimerNotify(OsTimerPtr timer, CARD32 now, void *arg) 131{ 132 DeviceIntPtr dev = arg; 133 ScreenPtr pScreen = dev->spriteInfo->anim.pScreen; 134 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 135 136 AnimCurPtr ac = GetAnimCur(dev->spriteInfo->sprite->current); 137 int elt = (dev->spriteInfo->anim.elt + 1) % ac->nelt; 138 DisplayCursorProcPtr DisplayCursor = pScreen->DisplayCursor; 139 140 /* 141 * Not a simple Unwrap/Wrap as this isn't called along the DisplayCursor 142 * wrapper chain. 143 */ 144 pScreen->DisplayCursor = as->DisplayCursor; 145 (void) (*pScreen->DisplayCursor) (dev, pScreen, ac->elts[elt].pCursor); 146 as->DisplayCursor = pScreen->DisplayCursor; 147 pScreen->DisplayCursor = DisplayCursor; 148 149 dev->spriteInfo->anim.elt = elt; 150 dev->spriteInfo->anim.pCursor = ac->elts[elt].pCursor; 151 152 return ac->elts[elt].delay; 153} 154 155static void 156AnimCurCancelTimer(DeviceIntPtr pDev) 157{ 158 CursorPtr cur = pDev->spriteInfo->sprite ? 159 pDev->spriteInfo->sprite->current : NULL; 160 161 if (IsAnimCur(cur)) 162 TimerCancel(GetAnimCur(cur)->timer); 163} 164 165static Bool 166AnimCurDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 167{ 168 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 169 Bool ret = TRUE; 170 171 if (IsFloating(pDev)) 172 return FALSE; 173 174 Unwrap(as, pScreen, DisplayCursor); 175 if (IsAnimCur(pCursor)) { 176 if (pCursor != pDev->spriteInfo->sprite->current) { 177 AnimCurPtr ac = GetAnimCur(pCursor); 178 179 AnimCurCancelTimer(pDev); 180 ret = (*pScreen->DisplayCursor) (pDev, pScreen, 181 ac->elts[0].pCursor); 182 183 if (ret) { 184 pDev->spriteInfo->anim.elt = 0; 185 pDev->spriteInfo->anim.pCursor = pCursor; 186 pDev->spriteInfo->anim.pScreen = pScreen; 187 188 ac->timer = TimerSet(ac->timer, 0, ac->elts[0].delay, 189 AnimCurTimerNotify, pDev); 190 } 191 } 192 } 193 else { 194 AnimCurCancelTimer(pDev); 195 pDev->spriteInfo->anim.pCursor = 0; 196 pDev->spriteInfo->anim.pScreen = 0; 197 ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); 198 } 199 Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); 200 return ret; 201} 202 203static Bool 204AnimCurSetCursorPosition(DeviceIntPtr pDev, 205 ScreenPtr pScreen, int x, int y, Bool generateEvent) 206{ 207 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 208 Bool ret; 209 210 Unwrap(as, pScreen, SetCursorPosition); 211 if (pDev->spriteInfo->anim.pCursor) { 212 pDev->spriteInfo->anim.pScreen = pScreen; 213 } 214 ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent); 215 Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 216 return ret; 217} 218 219static Bool 220AnimCurRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 221{ 222 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 223 Bool ret; 224 225 Unwrap(as, pScreen, RealizeCursor); 226 if (IsAnimCur(pCursor)) 227 ret = TRUE; 228 else 229 ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor); 230 Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); 231 return ret; 232} 233 234static Bool 235AnimCurUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 236{ 237 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 238 Bool ret; 239 240 Unwrap(as, pScreen, UnrealizeCursor); 241 if (IsAnimCur(pCursor)) { 242 AnimCurPtr ac = GetAnimCur(pCursor); 243 int i; 244 245 if (pScreen->myNum == 0) 246 for (i = 0; i < ac->nelt; i++) 247 FreeCursor(ac->elts[i].pCursor, 0); 248 ret = TRUE; 249 } 250 else 251 ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); 252 Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 253 return ret; 254} 255 256static void 257AnimCurRecolorCursor(DeviceIntPtr pDev, 258 ScreenPtr pScreen, CursorPtr pCursor, Bool displayed) 259{ 260 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 261 262 Unwrap(as, pScreen, RecolorCursor); 263 if (IsAnimCur(pCursor)) { 264 AnimCurPtr ac = GetAnimCur(pCursor); 265 int i; 266 267 for (i = 0; i < ac->nelt; i++) 268 (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor, 269 displayed && 270 pDev->spriteInfo->anim.elt == i); 271 } 272 else 273 (*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed); 274 Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); 275} 276 277Bool 278AnimCurInit(ScreenPtr pScreen) 279{ 280 AnimCurScreenPtr as; 281 282 if (!dixRegisterPrivateKey(&AnimCurScreenPrivateKeyRec, PRIVATE_SCREEN, 283 sizeof(AnimCurScreenRec))) 284 return FALSE; 285 286 as = GetAnimCurScreen(pScreen); 287 288 Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen); 289 290 Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); 291 Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); 292 Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 293 Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); 294 Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 295 Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); 296 return TRUE; 297} 298 299int 300AnimCursorCreate(CursorPtr *cursors, CARD32 *deltas, int ncursor, 301 CursorPtr *ppCursor, ClientPtr client, XID cid) 302{ 303 CursorPtr pCursor; 304 int rc = BadAlloc, i; 305 AnimCurPtr ac; 306 307 if (ncursor <= 0) 308 return BadValue; 309 310 for (i = 0; i < screenInfo.numScreens; i++) 311 if (!GetAnimCurScreen(screenInfo.screens[i])) 312 return BadImplementation; 313 314 for (i = 0; i < ncursor; i++) 315 if (IsAnimCur(cursors[i])) 316 return BadMatch; 317 318 pCursor = (CursorPtr) calloc(CURSOR_REC_SIZE + 319 sizeof(AnimCurRec) + 320 ncursor * sizeof(AnimCurElt), 1); 321 if (!pCursor) 322 return rc; 323 dixInitPrivates(pCursor, pCursor + 1, PRIVATE_CURSOR); 324 pCursor->bits = &animCursorBits; 325 pCursor->refcnt = 1; 326 327 pCursor->foreRed = cursors[0]->foreRed; 328 pCursor->foreGreen = cursors[0]->foreGreen; 329 pCursor->foreBlue = cursors[0]->foreBlue; 330 331 pCursor->backRed = cursors[0]->backRed; 332 pCursor->backGreen = cursors[0]->backGreen; 333 pCursor->backBlue = cursors[0]->backBlue; 334 335 pCursor->id = cid; 336 337 ac = GetAnimCur(pCursor); 338 ac->timer = TimerSet(NULL, 0, 0, AnimCurTimerNotify, NULL); 339 340 /* security creation/labeling check */ 341 if (ac->timer) 342 rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor, 343 RT_NONE, NULL, DixCreateAccess); 344 345 if (rc != Success) { 346 TimerFree(ac->timer); 347 dixFiniPrivates(pCursor, PRIVATE_CURSOR); 348 free(pCursor); 349 return rc; 350 } 351 352 /* 353 * Fill in the AnimCurRec 354 */ 355 animCursorBits.refcnt++; 356 ac->nelt = ncursor; 357 ac->elts = (AnimCurElt *) (ac + 1); 358 359 for (i = 0; i < ncursor; i++) { 360 ac->elts[i].pCursor = RefCursor(cursors[i]); 361 ac->elts[i].delay = deltas[i]; 362 } 363 364 *ppCursor = pCursor; 365 return Success; 366} 367