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