animcur.c revision 05b261ec
105b261ecSmrg/* 205b261ecSmrg * 305b261ecSmrg * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. 405b261ecSmrg * 505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 705b261ecSmrg * the above copyright notice appear in all copies and that both that 805b261ecSmrg * copyright notice and this permission notice appear in supporting 905b261ecSmrg * documentation, and that the name of Keith Packard not be used in 1005b261ecSmrg * advertising or publicity pertaining to distribution of the software without 1105b261ecSmrg * specific, written prior permission. Keith Packard makes no 1205b261ecSmrg * representations about the suitability of this software for any purpose. It 1305b261ecSmrg * is provided "as is" without express or implied warranty. 1405b261ecSmrg * 1505b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1705b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2105b261ecSmrg * PERFORMANCE OF THIS SOFTWARE. 2205b261ecSmrg */ 2305b261ecSmrg 2405b261ecSmrg/* 2505b261ecSmrg * Animated cursors for X. Not specific to Render in any way, but 2605b261ecSmrg * stuck there because Render has the other cool cursor extension. 2705b261ecSmrg * Besides, everyone has Render. 2805b261ecSmrg * 2905b261ecSmrg * Implemented as a simple layer over the core cursor code; it 3005b261ecSmrg * creates composite cursors out of a set of static cursors and 3105b261ecSmrg * delta times between each image. 3205b261ecSmrg */ 3305b261ecSmrg 3405b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 3505b261ecSmrg#include <dix-config.h> 3605b261ecSmrg#endif 3705b261ecSmrg 3805b261ecSmrg#include <X11/X.h> 3905b261ecSmrg#include <X11/Xmd.h> 4005b261ecSmrg#include "servermd.h" 4105b261ecSmrg#include "scrnintstr.h" 4205b261ecSmrg#include "dixstruct.h" 4305b261ecSmrg#include "cursorstr.h" 4405b261ecSmrg#include "dixfontstr.h" 4505b261ecSmrg#include "opaque.h" 4605b261ecSmrg#include "picturestr.h" 4705b261ecSmrg 4805b261ecSmrgtypedef struct _AnimCurElt { 4905b261ecSmrg CursorPtr pCursor; /* cursor to show */ 5005b261ecSmrg CARD32 delay; /* in ms */ 5105b261ecSmrg} AnimCurElt; 5205b261ecSmrg 5305b261ecSmrgtypedef struct _AnimCur { 5405b261ecSmrg int nelt; /* number of elements in the elts array */ 5505b261ecSmrg AnimCurElt *elts; /* actually allocated right after the structure */ 5605b261ecSmrg} AnimCurRec, *AnimCurPtr; 5705b261ecSmrg 5805b261ecSmrgtypedef struct _AnimScrPriv { 5905b261ecSmrg CursorPtr pCursor; 6005b261ecSmrg int elt; 6105b261ecSmrg CARD32 time; 6205b261ecSmrg 6305b261ecSmrg CloseScreenProcPtr CloseScreen; 6405b261ecSmrg 6505b261ecSmrg ScreenBlockHandlerProcPtr BlockHandler; 6605b261ecSmrg 6705b261ecSmrg CursorLimitsProcPtr CursorLimits; 6805b261ecSmrg DisplayCursorProcPtr DisplayCursor; 6905b261ecSmrg SetCursorPositionProcPtr SetCursorPosition; 7005b261ecSmrg RealizeCursorProcPtr RealizeCursor; 7105b261ecSmrg UnrealizeCursorProcPtr UnrealizeCursor; 7205b261ecSmrg RecolorCursorProcPtr RecolorCursor; 7305b261ecSmrg} AnimCurScreenRec, *AnimCurScreenPtr; 7405b261ecSmrg 7505b261ecSmrgtypedef struct _AnimCurState { 7605b261ecSmrg CursorPtr pCursor; 7705b261ecSmrg ScreenPtr pScreen; 7805b261ecSmrg int elt; 7905b261ecSmrg CARD32 time; 8005b261ecSmrg} AnimCurStateRec, *AnimCurStatePtr; 8105b261ecSmrg 8205b261ecSmrgstatic AnimCurStateRec animCurState; 8305b261ecSmrg 8405b261ecSmrgstatic unsigned char empty[4]; 8505b261ecSmrg 8605b261ecSmrgstatic CursorBits animCursorBits = { 8705b261ecSmrg empty, empty, 2, 1, 1, 0, 0, 1 8805b261ecSmrg}; 8905b261ecSmrg 9005b261ecSmrgstatic int AnimCurScreenPrivateIndex = -1; 9105b261ecSmrgstatic int AnimCurGeneration; 9205b261ecSmrg 9305b261ecSmrg#define IsAnimCur(c) ((c)->bits == &animCursorBits) 9405b261ecSmrg#define GetAnimCur(c) ((AnimCurPtr) ((c) + 1)) 9505b261ecSmrg#define GetAnimCurScreen(s) ((AnimCurScreenPtr) ((s)->devPrivates[AnimCurScreenPrivateIndex].ptr)) 9605b261ecSmrg#define GetAnimCurScreenIfSet(s) ((AnimCurScreenPrivateIndex != -1) ? GetAnimCurScreen(s) : NULL) 9705b261ecSmrg#define SetAnimCurScreen(s,p) ((s)->devPrivates[AnimCurScreenPrivateIndex].ptr = (pointer) (p)) 9805b261ecSmrg 9905b261ecSmrg#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) 10005b261ecSmrg#define Unwrap(as,s,elt) ((s)->elt = (as)->elt) 10105b261ecSmrg 10205b261ecSmrgstatic Bool 10305b261ecSmrgAnimCurDisplayCursor (ScreenPtr pScreen, 10405b261ecSmrg CursorPtr pCursor); 10505b261ecSmrg 10605b261ecSmrgstatic Bool 10705b261ecSmrgAnimCurSetCursorPosition (ScreenPtr pScreen, 10805b261ecSmrg int x, 10905b261ecSmrg int y, 11005b261ecSmrg Bool generateEvent); 11105b261ecSmrg 11205b261ecSmrgstatic Bool 11305b261ecSmrgAnimCurCloseScreen (int index, ScreenPtr pScreen) 11405b261ecSmrg{ 11505b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 11605b261ecSmrg Bool ret; 11705b261ecSmrg 11805b261ecSmrg Unwrap(as, pScreen, CloseScreen); 11905b261ecSmrg 12005b261ecSmrg Unwrap(as, pScreen, BlockHandler); 12105b261ecSmrg 12205b261ecSmrg Unwrap(as, pScreen, CursorLimits); 12305b261ecSmrg Unwrap(as, pScreen, DisplayCursor); 12405b261ecSmrg Unwrap(as, pScreen, SetCursorPosition); 12505b261ecSmrg Unwrap(as, pScreen, RealizeCursor); 12605b261ecSmrg Unwrap(as, pScreen, UnrealizeCursor); 12705b261ecSmrg Unwrap(as, pScreen, RecolorCursor); 12805b261ecSmrg SetAnimCurScreen(pScreen,0); 12905b261ecSmrg ret = (*pScreen->CloseScreen) (index, pScreen); 13005b261ecSmrg xfree (as); 13105b261ecSmrg if (index == 0) 13205b261ecSmrg AnimCurScreenPrivateIndex = -1; 13305b261ecSmrg return ret; 13405b261ecSmrg} 13505b261ecSmrg 13605b261ecSmrgstatic void 13705b261ecSmrgAnimCurCursorLimits (ScreenPtr pScreen, 13805b261ecSmrg CursorPtr pCursor, 13905b261ecSmrg BoxPtr pHotBox, 14005b261ecSmrg BoxPtr pTopLeftBox) 14105b261ecSmrg{ 14205b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 14305b261ecSmrg 14405b261ecSmrg Unwrap (as, pScreen, CursorLimits); 14505b261ecSmrg if (IsAnimCur(pCursor)) 14605b261ecSmrg { 14705b261ecSmrg AnimCurPtr ac = GetAnimCur(pCursor); 14805b261ecSmrg 14905b261ecSmrg (*pScreen->CursorLimits) (pScreen, ac->elts[0].pCursor, pHotBox, pTopLeftBox); 15005b261ecSmrg } 15105b261ecSmrg else 15205b261ecSmrg { 15305b261ecSmrg (*pScreen->CursorLimits) (pScreen, pCursor, pHotBox, pTopLeftBox); 15405b261ecSmrg } 15505b261ecSmrg Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits); 15605b261ecSmrg} 15705b261ecSmrg 15805b261ecSmrg/* 15905b261ecSmrg * This has to be a screen block handler instead of a generic 16005b261ecSmrg * block handler so that it is well ordered with respect to the DRI 16105b261ecSmrg * block handler responsible for releasing the hardware to DRI clients 16205b261ecSmrg */ 16305b261ecSmrg 16405b261ecSmrgstatic void 16505b261ecSmrgAnimCurScreenBlockHandler (int screenNum, 16605b261ecSmrg pointer blockData, 16705b261ecSmrg pointer pTimeout, 16805b261ecSmrg pointer pReadmask) 16905b261ecSmrg{ 17005b261ecSmrg ScreenPtr pScreen = screenInfo.screens[screenNum]; 17105b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 17205b261ecSmrg 17305b261ecSmrg if (pScreen == animCurState.pScreen) 17405b261ecSmrg { 17505b261ecSmrg CARD32 now = GetTimeInMillis (); 17605b261ecSmrg 17705b261ecSmrg if ((INT32) (now - animCurState.time) >= 0) 17805b261ecSmrg { 17905b261ecSmrg AnimCurPtr ac = GetAnimCur(animCurState.pCursor); 18005b261ecSmrg int elt = (animCurState.elt + 1) % ac->nelt; 18105b261ecSmrg DisplayCursorProcPtr DisplayCursor; 18205b261ecSmrg 18305b261ecSmrg /* 18405b261ecSmrg * Not a simple Unwrap/Wrap as this 18505b261ecSmrg * isn't called along the DisplayCursor 18605b261ecSmrg * wrapper chain. 18705b261ecSmrg */ 18805b261ecSmrg DisplayCursor = pScreen->DisplayCursor; 18905b261ecSmrg pScreen->DisplayCursor = as->DisplayCursor; 19005b261ecSmrg (void) (*pScreen->DisplayCursor) (pScreen, ac->elts[elt].pCursor); 19105b261ecSmrg as->DisplayCursor = pScreen->DisplayCursor; 19205b261ecSmrg pScreen->DisplayCursor = DisplayCursor; 19305b261ecSmrg 19405b261ecSmrg animCurState.elt = elt; 19505b261ecSmrg animCurState.time = now + ac->elts[elt].delay; 19605b261ecSmrg } 19705b261ecSmrg AdjustWaitForDelay (pTimeout, animCurState.time - now); 19805b261ecSmrg } 19905b261ecSmrg Unwrap (as, pScreen, BlockHandler); 20005b261ecSmrg (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); 20105b261ecSmrg Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 20205b261ecSmrg} 20305b261ecSmrg 20405b261ecSmrgstatic Bool 20505b261ecSmrgAnimCurDisplayCursor (ScreenPtr pScreen, 20605b261ecSmrg CursorPtr pCursor) 20705b261ecSmrg{ 20805b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 20905b261ecSmrg Bool ret; 21005b261ecSmrg 21105b261ecSmrg Unwrap (as, pScreen, DisplayCursor); 21205b261ecSmrg if (IsAnimCur(pCursor)) 21305b261ecSmrg { 21405b261ecSmrg if (pCursor != animCurState.pCursor) 21505b261ecSmrg { 21605b261ecSmrg AnimCurPtr ac = GetAnimCur(pCursor); 21705b261ecSmrg 21805b261ecSmrg ret = (*pScreen->DisplayCursor) (pScreen, ac->elts[0].pCursor); 21905b261ecSmrg if (ret) 22005b261ecSmrg { 22105b261ecSmrg animCurState.elt = 0; 22205b261ecSmrg animCurState.time = GetTimeInMillis () + ac->elts[0].delay; 22305b261ecSmrg animCurState.pCursor = pCursor; 22405b261ecSmrg animCurState.pScreen = pScreen; 22505b261ecSmrg } 22605b261ecSmrg } 22705b261ecSmrg else 22805b261ecSmrg ret = TRUE; 22905b261ecSmrg } 23005b261ecSmrg else 23105b261ecSmrg { 23205b261ecSmrg animCurState.pCursor = 0; 23305b261ecSmrg animCurState.pScreen = 0; 23405b261ecSmrg ret = (*pScreen->DisplayCursor) (pScreen, pCursor); 23505b261ecSmrg } 23605b261ecSmrg Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor); 23705b261ecSmrg return ret; 23805b261ecSmrg} 23905b261ecSmrg 24005b261ecSmrgstatic Bool 24105b261ecSmrgAnimCurSetCursorPosition (ScreenPtr pScreen, 24205b261ecSmrg int x, 24305b261ecSmrg int y, 24405b261ecSmrg Bool generateEvent) 24505b261ecSmrg{ 24605b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 24705b261ecSmrg Bool ret; 24805b261ecSmrg 24905b261ecSmrg Unwrap (as, pScreen, SetCursorPosition); 25005b261ecSmrg if (animCurState.pCursor) 25105b261ecSmrg animCurState.pScreen = pScreen; 25205b261ecSmrg ret = (*pScreen->SetCursorPosition) (pScreen, x, y, generateEvent); 25305b261ecSmrg Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 25405b261ecSmrg return ret; 25505b261ecSmrg} 25605b261ecSmrg 25705b261ecSmrgstatic Bool 25805b261ecSmrgAnimCurRealizeCursor (ScreenPtr pScreen, 25905b261ecSmrg CursorPtr pCursor) 26005b261ecSmrg{ 26105b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 26205b261ecSmrg Bool ret; 26305b261ecSmrg 26405b261ecSmrg Unwrap (as, pScreen, RealizeCursor); 26505b261ecSmrg if (IsAnimCur(pCursor)) 26605b261ecSmrg ret = TRUE; 26705b261ecSmrg else 26805b261ecSmrg ret = (*pScreen->RealizeCursor) (pScreen, pCursor); 26905b261ecSmrg Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor); 27005b261ecSmrg return ret; 27105b261ecSmrg} 27205b261ecSmrg 27305b261ecSmrgstatic Bool 27405b261ecSmrgAnimCurUnrealizeCursor (ScreenPtr pScreen, 27505b261ecSmrg CursorPtr pCursor) 27605b261ecSmrg{ 27705b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 27805b261ecSmrg Bool ret; 27905b261ecSmrg 28005b261ecSmrg Unwrap (as, pScreen, UnrealizeCursor); 28105b261ecSmrg if (IsAnimCur(pCursor)) 28205b261ecSmrg { 28305b261ecSmrg AnimCurPtr ac = GetAnimCur(pCursor); 28405b261ecSmrg int i; 28505b261ecSmrg 28605b261ecSmrg if (pScreen->myNum == 0) 28705b261ecSmrg for (i = 0; i < ac->nelt; i++) 28805b261ecSmrg FreeCursor (ac->elts[i].pCursor, 0); 28905b261ecSmrg ret = TRUE; 29005b261ecSmrg } 29105b261ecSmrg else 29205b261ecSmrg ret = (*pScreen->UnrealizeCursor) (pScreen, pCursor); 29305b261ecSmrg Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 29405b261ecSmrg return ret; 29505b261ecSmrg} 29605b261ecSmrg 29705b261ecSmrgstatic void 29805b261ecSmrgAnimCurRecolorCursor (ScreenPtr pScreen, 29905b261ecSmrg CursorPtr pCursor, 30005b261ecSmrg Bool displayed) 30105b261ecSmrg{ 30205b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 30305b261ecSmrg 30405b261ecSmrg Unwrap (as, pScreen, RecolorCursor); 30505b261ecSmrg if (IsAnimCur(pCursor)) 30605b261ecSmrg { 30705b261ecSmrg AnimCurPtr ac = GetAnimCur(pCursor); 30805b261ecSmrg int i; 30905b261ecSmrg 31005b261ecSmrg for (i = 0; i < ac->nelt; i++) 31105b261ecSmrg (*pScreen->RecolorCursor) (pScreen, ac->elts[i].pCursor, 31205b261ecSmrg displayed && 31305b261ecSmrg animCurState.elt == i); 31405b261ecSmrg } 31505b261ecSmrg else 31605b261ecSmrg (*pScreen->RecolorCursor) (pScreen, pCursor, displayed); 31705b261ecSmrg Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor); 31805b261ecSmrg} 31905b261ecSmrg 32005b261ecSmrgBool 32105b261ecSmrgAnimCurInit (ScreenPtr pScreen) 32205b261ecSmrg{ 32305b261ecSmrg AnimCurScreenPtr as; 32405b261ecSmrg 32505b261ecSmrg if (AnimCurGeneration != serverGeneration) 32605b261ecSmrg { 32705b261ecSmrg AnimCurScreenPrivateIndex = AllocateScreenPrivateIndex (); 32805b261ecSmrg if (AnimCurScreenPrivateIndex < 0) 32905b261ecSmrg return FALSE; 33005b261ecSmrg AnimCurGeneration = serverGeneration; 33105b261ecSmrg animCurState.pCursor = 0; 33205b261ecSmrg animCurState.pScreen = 0; 33305b261ecSmrg animCurState.elt = 0; 33405b261ecSmrg animCurState.time = 0; 33505b261ecSmrg } 33605b261ecSmrg as = (AnimCurScreenPtr) xalloc (sizeof (AnimCurScreenRec)); 33705b261ecSmrg if (!as) 33805b261ecSmrg return FALSE; 33905b261ecSmrg Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen); 34005b261ecSmrg 34105b261ecSmrg Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 34205b261ecSmrg 34305b261ecSmrg Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); 34405b261ecSmrg Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); 34505b261ecSmrg Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 34605b261ecSmrg Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); 34705b261ecSmrg Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 34805b261ecSmrg Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); 34905b261ecSmrg SetAnimCurScreen(pScreen,as); 35005b261ecSmrg return TRUE; 35105b261ecSmrg} 35205b261ecSmrg 35305b261ecSmrgint 35405b261ecSmrgAnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor) 35505b261ecSmrg{ 35605b261ecSmrg CursorPtr pCursor; 35705b261ecSmrg int i; 35805b261ecSmrg AnimCurPtr ac; 35905b261ecSmrg 36005b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 36105b261ecSmrg if (!GetAnimCurScreenIfSet (screenInfo.screens[i])) 36205b261ecSmrg return BadImplementation; 36305b261ecSmrg 36405b261ecSmrg for (i = 0; i < ncursor; i++) 36505b261ecSmrg if (IsAnimCur (cursors[i])) 36605b261ecSmrg return BadMatch; 36705b261ecSmrg 36805b261ecSmrg pCursor = (CursorPtr) xalloc (sizeof (CursorRec) + 36905b261ecSmrg sizeof (AnimCurRec) + 37005b261ecSmrg ncursor * sizeof (AnimCurElt)); 37105b261ecSmrg if (!pCursor) 37205b261ecSmrg return BadAlloc; 37305b261ecSmrg pCursor->bits = &animCursorBits; 37405b261ecSmrg animCursorBits.refcnt++; 37505b261ecSmrg pCursor->refcnt = 1; 37605b261ecSmrg 37705b261ecSmrg pCursor->foreRed = cursors[0]->foreRed; 37805b261ecSmrg pCursor->foreGreen = cursors[0]->foreGreen; 37905b261ecSmrg pCursor->foreBlue = cursors[0]->foreBlue; 38005b261ecSmrg 38105b261ecSmrg pCursor->backRed = cursors[0]->backRed; 38205b261ecSmrg pCursor->backGreen = cursors[0]->backGreen; 38305b261ecSmrg pCursor->backBlue = cursors[0]->backBlue; 38405b261ecSmrg 38505b261ecSmrg /* 38605b261ecSmrg * Fill in the AnimCurRec 38705b261ecSmrg */ 38805b261ecSmrg ac = GetAnimCur (pCursor); 38905b261ecSmrg ac->nelt = ncursor; 39005b261ecSmrg ac->elts = (AnimCurElt *) (ac + 1); 39105b261ecSmrg 39205b261ecSmrg for (i = 0; i < ncursor; i++) 39305b261ecSmrg { 39405b261ecSmrg cursors[i]->refcnt++; 39505b261ecSmrg ac->elts[i].pCursor = cursors[i]; 39605b261ecSmrg ac->elts[i].delay = deltas[i]; 39705b261ecSmrg } 39805b261ecSmrg 39905b261ecSmrg *ppCursor = pCursor; 40005b261ecSmrg return Success; 40105b261ecSmrg} 402