animcur.c revision 9ace9065
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} AnimCurRec, *AnimCurPtr; 59 60typedef struct _AnimScrPriv { 61 CloseScreenProcPtr CloseScreen; 62 63 ScreenBlockHandlerProcPtr BlockHandler; 64 65 CursorLimitsProcPtr CursorLimits; 66 DisplayCursorProcPtr DisplayCursor; 67 SetCursorPositionProcPtr SetCursorPosition; 68 RealizeCursorProcPtr RealizeCursor; 69 UnrealizeCursorProcPtr UnrealizeCursor; 70 RecolorCursorProcPtr RecolorCursor; 71} AnimCurScreenRec, *AnimCurScreenPtr; 72 73static unsigned char empty[4]; 74 75static CursorBits animCursorBits = { 76 empty, empty, 2, 1, 1, 0, 0, 1 77}; 78 79static DevPrivateKeyRec AnimCurScreenPrivateKeyRec; 80#define AnimCurScreenPrivateKey (&AnimCurScreenPrivateKeyRec) 81 82#define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits)) 83#define GetAnimCur(c) ((AnimCurPtr) ((((char *)(c) + CURSOR_REC_SIZE)))) 84#define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey)) 85#define SetAnimCurScreen(s,p) dixSetPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey, p) 86 87#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) 88#define Unwrap(as,s,elt) ((s)->elt = (as)->elt) 89 90 91static Bool 92AnimCurCloseScreen (int index, ScreenPtr pScreen) 93{ 94 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 95 Bool ret; 96 97 Unwrap(as, pScreen, CloseScreen); 98 99 Unwrap(as, pScreen, CursorLimits); 100 Unwrap(as, pScreen, DisplayCursor); 101 Unwrap(as, pScreen, SetCursorPosition); 102 Unwrap(as, pScreen, RealizeCursor); 103 Unwrap(as, pScreen, UnrealizeCursor); 104 Unwrap(as, pScreen, RecolorCursor); 105 SetAnimCurScreen(pScreen,0); 106 ret = (*pScreen->CloseScreen) (index, pScreen); 107 free(as); 108 return ret; 109} 110 111static void 112AnimCurCursorLimits (DeviceIntPtr pDev, 113 ScreenPtr pScreen, 114 CursorPtr pCursor, 115 BoxPtr pHotBox, 116 BoxPtr pTopLeftBox) 117{ 118 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 119 120 Unwrap (as, pScreen, CursorLimits); 121 if (IsAnimCur(pCursor)) 122 { 123 AnimCurPtr ac = GetAnimCur(pCursor); 124 125 (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor, 126 pHotBox, pTopLeftBox); 127 } 128 else 129 { 130 (*pScreen->CursorLimits) (pDev, pScreen, pCursor, 131 pHotBox, pTopLeftBox); 132 } 133 Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits); 134} 135 136/* 137 * This has to be a screen block handler instead of a generic 138 * block handler so that it is well ordered with respect to the DRI 139 * block handler responsible for releasing the hardware to DRI clients 140 */ 141 142static void 143AnimCurScreenBlockHandler (int screenNum, 144 pointer blockData, 145 pointer pTimeout, 146 pointer pReadmask) 147{ 148 ScreenPtr pScreen = screenInfo.screens[screenNum]; 149 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 150 DeviceIntPtr dev; 151 Bool activeDevice = FALSE; 152 CARD32 now = 0, 153 soonest = ~0; /* earliest time to wakeup again */ 154 155 for (dev = inputInfo.devices; dev; dev = dev->next) 156 { 157 if (IsPointerDevice(dev) && pScreen == dev->spriteInfo->anim.pScreen) 158 { 159 if (!activeDevice) { 160 now = GetTimeInMillis (); 161 activeDevice = TRUE; 162 } 163 164 if ((INT32) (now - dev->spriteInfo->anim.time) >= 0) 165 { 166 AnimCurPtr ac = GetAnimCur(dev->spriteInfo->anim.pCursor); 167 int elt = (dev->spriteInfo->anim.elt + 1) % ac->nelt; 168 DisplayCursorProcPtr DisplayCursor; 169 170 /* 171 * Not a simple Unwrap/Wrap as this 172 * isn't called along the DisplayCursor 173 * wrapper chain. 174 */ 175 DisplayCursor = pScreen->DisplayCursor; 176 pScreen->DisplayCursor = as->DisplayCursor; 177 (void) (*pScreen->DisplayCursor) (dev, 178 pScreen, 179 ac->elts[elt].pCursor); 180 as->DisplayCursor = pScreen->DisplayCursor; 181 pScreen->DisplayCursor = DisplayCursor; 182 183 dev->spriteInfo->anim.elt = elt; 184 dev->spriteInfo->anim.time = now + ac->elts[elt].delay; 185 } 186 187 if (soonest > dev->spriteInfo->anim.time) 188 soonest = dev->spriteInfo->anim.time; 189 } 190 } 191 192 if (activeDevice) 193 AdjustWaitForDelay (pTimeout, soonest - now); 194 195 Unwrap (as, pScreen, BlockHandler); 196 (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); 197 if (activeDevice) 198 Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 199 else 200 as->BlockHandler = NULL; 201} 202 203static Bool 204AnimCurDisplayCursor (DeviceIntPtr pDev, 205 ScreenPtr pScreen, 206 CursorPtr pCursor) 207{ 208 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 209 Bool ret; 210 211 Unwrap (as, pScreen, DisplayCursor); 212 if (IsAnimCur(pCursor)) 213 { 214 if (pCursor != pDev->spriteInfo->anim.pCursor) 215 { 216 AnimCurPtr ac = GetAnimCur(pCursor); 217 218 ret = (*pScreen->DisplayCursor) 219 (pDev, pScreen, ac->elts[0].pCursor); 220 if (ret) 221 { 222 pDev->spriteInfo->anim.elt = 0; 223 pDev->spriteInfo->anim.time = GetTimeInMillis () + ac->elts[0].delay; 224 pDev->spriteInfo->anim.pCursor = pCursor; 225 pDev->spriteInfo->anim.pScreen = pScreen; 226 227 if (!as->BlockHandler) 228 Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 229 } 230 } 231 else 232 ret = TRUE; 233 } 234 else 235 { 236 pDev->spriteInfo->anim.pCursor = 0; 237 pDev->spriteInfo->anim.pScreen = 0; 238 ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); 239 } 240 Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor); 241 return ret; 242} 243 244static Bool 245AnimCurSetCursorPosition (DeviceIntPtr pDev, 246 ScreenPtr pScreen, 247 int x, 248 int y, 249 Bool generateEvent) 250{ 251 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 252 Bool ret; 253 254 Unwrap (as, pScreen, SetCursorPosition); 255 if (pDev->spriteInfo->anim.pCursor) { 256 pDev->spriteInfo->anim.pScreen = pScreen; 257 258 if (!as->BlockHandler) 259 Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 260 } 261 ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent); 262 Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 263 return ret; 264} 265 266static Bool 267AnimCurRealizeCursor (DeviceIntPtr pDev, 268 ScreenPtr pScreen, 269 CursorPtr pCursor) 270{ 271 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 272 Bool ret; 273 274 Unwrap (as, pScreen, RealizeCursor); 275 if (IsAnimCur(pCursor)) 276 ret = TRUE; 277 else 278 ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor); 279 Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor); 280 return ret; 281} 282 283static Bool 284AnimCurUnrealizeCursor (DeviceIntPtr pDev, 285 ScreenPtr pScreen, 286 CursorPtr pCursor) 287{ 288 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 289 Bool ret; 290 291 Unwrap (as, pScreen, UnrealizeCursor); 292 if (IsAnimCur(pCursor)) 293 { 294 AnimCurPtr ac = GetAnimCur(pCursor); 295 int i; 296 297 if (pScreen->myNum == 0) 298 for (i = 0; i < ac->nelt; i++) 299 FreeCursor (ac->elts[i].pCursor, 0); 300 ret = TRUE; 301 } 302 else 303 ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); 304 Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 305 return ret; 306} 307 308static void 309AnimCurRecolorCursor (DeviceIntPtr pDev, 310 ScreenPtr pScreen, 311 CursorPtr pCursor, 312 Bool displayed) 313{ 314 AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 315 316 Unwrap (as, pScreen, RecolorCursor); 317 if (IsAnimCur(pCursor)) 318 { 319 AnimCurPtr ac = GetAnimCur(pCursor); 320 int i; 321 322 for (i = 0; i < ac->nelt; i++) 323 (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor, 324 displayed && 325 pDev->spriteInfo->anim.elt == i); 326 } 327 else 328 (*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed); 329 Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor); 330} 331 332Bool 333AnimCurInit (ScreenPtr pScreen) 334{ 335 AnimCurScreenPtr as; 336 337 if (!dixRegisterPrivateKey(&AnimCurScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 338 return FALSE; 339 340 as = (AnimCurScreenPtr) malloc(sizeof (AnimCurScreenRec)); 341 if (!as) 342 return FALSE; 343 Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen); 344 345 as->BlockHandler = NULL; 346 347 Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); 348 Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); 349 Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 350 Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); 351 Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 352 Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); 353 SetAnimCurScreen(pScreen,as); 354 return TRUE; 355} 356 357int 358AnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor, ClientPtr client, XID cid) 359{ 360 CursorPtr pCursor; 361 int rc, i; 362 AnimCurPtr ac; 363 364 for (i = 0; i < screenInfo.numScreens; i++) 365 if (!GetAnimCurScreen (screenInfo.screens[i])) 366 return BadImplementation; 367 368 for (i = 0; i < ncursor; i++) 369 if (IsAnimCur (cursors[i])) 370 return BadMatch; 371 372 pCursor = (CursorPtr) calloc(CURSOR_REC_SIZE + 373 sizeof (AnimCurRec) + 374 ncursor * sizeof (AnimCurElt), 1); 375 if (!pCursor) 376 return BadAlloc; 377 dixInitPrivates(pCursor, pCursor + 1, PRIVATE_CURSOR); 378 pCursor->bits = &animCursorBits; 379 pCursor->refcnt = 1; 380 381 pCursor->foreRed = cursors[0]->foreRed; 382 pCursor->foreGreen = cursors[0]->foreGreen; 383 pCursor->foreBlue = cursors[0]->foreBlue; 384 385 pCursor->backRed = cursors[0]->backRed; 386 pCursor->backGreen = cursors[0]->backGreen; 387 pCursor->backBlue = cursors[0]->backBlue; 388 389 pCursor->id = cid; 390 391 /* security creation/labeling check */ 392 rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor, 393 RT_NONE, NULL, DixCreateAccess); 394 if (rc != Success) { 395 dixFiniPrivates(pCursor, PRIVATE_CURSOR); 396 free(pCursor); 397 return rc; 398 } 399 400 /* 401 * Fill in the AnimCurRec 402 */ 403 animCursorBits.refcnt++; 404 ac = GetAnimCur (pCursor); 405 ac->nelt = ncursor; 406 ac->elts = (AnimCurElt *) (ac + 1); 407 408 for (i = 0; i < ncursor; i++) 409 { 410 cursors[i]->refcnt++; 411 ac->elts[i].pCursor = cursors[i]; 412 ac->elts[i].delay = deltas[i]; 413 } 414 415 *ppCursor = pCursor; 416 return Success; 417} 418