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