animcur.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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. * Animated cursors for X. Not specific to Render in any way, but
  25. * stuck there because Render has the other cool cursor extension.
  26. * Besides, everyone has Render.
  27. *
  28. * Implemented as a simple layer over the core cursor code; it
  29. * creates composite cursors out of a set of static cursors and
  30. * delta times between each image.
  31. */
  32. #ifdef HAVE_DIX_CONFIG_H
  33. #include <dix-config.h>
  34. #endif
  35. #include <X11/X.h>
  36. #include <X11/Xmd.h>
  37. #include "servermd.h"
  38. #include "scrnintstr.h"
  39. #include "dixstruct.h"
  40. #include "cursorstr.h"
  41. #include "dixfontstr.h"
  42. #include "opaque.h"
  43. #include "picturestr.h"
  44. typedef struct _AnimCurElt {
  45. CursorPtr pCursor; /* cursor to show */
  46. CARD32 delay; /* in ms */
  47. } AnimCurElt;
  48. typedef struct _AnimCur {
  49. int nelt; /* number of elements in the elts array */
  50. AnimCurElt *elts; /* actually allocated right after the structure */
  51. } AnimCurRec, *AnimCurPtr;
  52. typedef struct _AnimScrPriv {
  53. CursorPtr pCursor;
  54. int elt;
  55. CARD32 time;
  56. CloseScreenProcPtr CloseScreen;
  57. ScreenBlockHandlerProcPtr BlockHandler;
  58. CursorLimitsProcPtr CursorLimits;
  59. DisplayCursorProcPtr DisplayCursor;
  60. SetCursorPositionProcPtr SetCursorPosition;
  61. RealizeCursorProcPtr RealizeCursor;
  62. UnrealizeCursorProcPtr UnrealizeCursor;
  63. RecolorCursorProcPtr RecolorCursor;
  64. } AnimCurScreenRec, *AnimCurScreenPtr;
  65. typedef struct _AnimCurState {
  66. CursorPtr pCursor;
  67. ScreenPtr pScreen;
  68. int elt;
  69. CARD32 time;
  70. } AnimCurStateRec, *AnimCurStatePtr;
  71. static AnimCurStateRec animCurState;
  72. static unsigned char empty[4];
  73. static CursorBits animCursorBits = {
  74. empty, empty, 2, 1, 1, 0, 0, 1
  75. };
  76. int AnimCurScreenPrivateIndex = -1;
  77. int AnimCurGeneration;
  78. #define IsAnimCur(c) ((c)->bits == &animCursorBits)
  79. #define GetAnimCur(c) ((AnimCurPtr) ((c) + 1))
  80. #define GetAnimCurScreen(s) ((AnimCurScreenPtr) ((s)->devPrivates[AnimCurScreenPrivateIndex].ptr))
  81. #define GetAnimCurScreenIfSet(s) ((AnimCurScreenPrivateIndex != -1) ? GetAnimCurScreen(s) : NULL)
  82. #define SetAnimCurScreen(s,p) ((s)->devPrivates[AnimCurScreenPrivateIndex].ptr = (pointer) (p))
  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. static Bool
  86. AnimCurDisplayCursor(ScreenPtr pScreen, CursorPtr pCursor);
  87. static Bool
  88. AnimCurSetCursorPosition(ScreenPtr pScreen, int x, int y, Bool generateEvent);
  89. static Bool
  90. AnimCurCloseScreen(int index, ScreenPtr pScreen)
  91. {
  92. AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
  93. Bool ret;
  94. Unwrap(as, pScreen, CloseScreen);
  95. Unwrap(as, pScreen, BlockHandler);
  96. Unwrap(as, pScreen, CursorLimits);
  97. Unwrap(as, pScreen, DisplayCursor);
  98. Unwrap(as, pScreen, SetCursorPosition);
  99. Unwrap(as, pScreen, RealizeCursor);
  100. Unwrap(as, pScreen, UnrealizeCursor);
  101. Unwrap(as, pScreen, RecolorCursor);
  102. SetAnimCurScreen(pScreen, 0);
  103. ret = (*pScreen->CloseScreen) (index, pScreen);
  104. free(as);
  105. if (index == 0)
  106. AnimCurScreenPrivateIndex = -1;
  107. return ret;
  108. }
  109. static void
  110. AnimCurCursorLimits(ScreenPtr pScreen,
  111. CursorPtr pCursor, BoxPtr pHotBox, BoxPtr pTopLeftBox)
  112. {
  113. AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
  114. Unwrap(as, pScreen, CursorLimits);
  115. if (IsAnimCur(pCursor)) {
  116. AnimCurPtr ac = GetAnimCur(pCursor);
  117. (*pScreen->CursorLimits) (pScreen, ac->elts[0].pCursor, pHotBox,
  118. pTopLeftBox);
  119. }
  120. else {
  121. (*pScreen->CursorLimits) (pScreen, pCursor, pHotBox, pTopLeftBox);
  122. }
  123. Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits);
  124. }
  125. /*
  126. * This has to be a screen block handler instead of a generic
  127. * block handler so that it is well ordered with respect to the DRI
  128. * block handler responsible for releasing the hardware to DRI clients
  129. */
  130. static void
  131. AnimCurScreenBlockHandler(int screenNum,
  132. pointer blockData,
  133. pointer pTimeout, pointer pReadmask)
  134. {
  135. ScreenPtr pScreen = screenInfo.screens[screenNum];
  136. AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
  137. if (pScreen == animCurState.pScreen) {
  138. CARD32 now = GetTimeInMillis();
  139. if ((INT32) (now - animCurState.time) >= 0) {
  140. AnimCurPtr ac = GetAnimCur(animCurState.pCursor);
  141. int elt = (animCurState.elt + 1) % ac->nelt;
  142. DisplayCursorProcPtr DisplayCursor;
  143. /*
  144. * Not a simple Unwrap/Wrap as this
  145. * isn't called along the DisplayCursor
  146. * wrapper chain.
  147. */
  148. DisplayCursor = pScreen->DisplayCursor;
  149. pScreen->DisplayCursor = as->DisplayCursor;
  150. (void) (*pScreen->DisplayCursor) (pScreen, ac->elts[elt].pCursor);
  151. as->DisplayCursor = pScreen->DisplayCursor;
  152. pScreen->DisplayCursor = DisplayCursor;
  153. animCurState.elt = elt;
  154. animCurState.time = now + ac->elts[elt].delay;
  155. }
  156. AdjustWaitForDelay(pTimeout, animCurState.time - now);
  157. }
  158. Unwrap(as, pScreen, BlockHandler);
  159. (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
  160. Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
  161. }
  162. static Bool
  163. AnimCurDisplayCursor(ScreenPtr pScreen, CursorPtr pCursor)
  164. {
  165. AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
  166. Bool ret;
  167. Unwrap(as, pScreen, DisplayCursor);
  168. if (IsAnimCur(pCursor)) {
  169. if (pCursor != animCurState.pCursor) {
  170. AnimCurPtr ac = GetAnimCur(pCursor);
  171. ret = (*pScreen->DisplayCursor) (pScreen, ac->elts[0].pCursor);
  172. if (ret) {
  173. animCurState.elt = 0;
  174. animCurState.time = GetTimeInMillis() + ac->elts[0].delay;
  175. animCurState.pCursor = pCursor;
  176. animCurState.pScreen = pScreen;
  177. }
  178. }
  179. else
  180. ret = TRUE;
  181. }
  182. else {
  183. animCurState.pCursor = 0;
  184. animCurState.pScreen = 0;
  185. ret = (*pScreen->DisplayCursor) (pScreen, pCursor);
  186. }
  187. Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor);
  188. return ret;
  189. }
  190. static Bool
  191. AnimCurSetCursorPosition(ScreenPtr pScreen, int x, int y, Bool generateEvent)
  192. {
  193. AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
  194. Bool ret;
  195. Unwrap(as, pScreen, SetCursorPosition);
  196. if (animCurState.pCursor)
  197. animCurState.pScreen = pScreen;
  198. ret = (*pScreen->SetCursorPosition) (pScreen, x, y, generateEvent);
  199. Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
  200. return ret;
  201. }
  202. static Bool
  203. AnimCurRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
  204. {
  205. AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
  206. Bool ret;
  207. Unwrap(as, pScreen, RealizeCursor);
  208. if (IsAnimCur(pCursor))
  209. ret = TRUE;
  210. else
  211. ret = (*pScreen->RealizeCursor) (pScreen, pCursor);
  212. Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor);
  213. return ret;
  214. }
  215. static Bool
  216. AnimCurUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
  217. {
  218. AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
  219. Bool ret;
  220. Unwrap(as, pScreen, UnrealizeCursor);
  221. if (IsAnimCur(pCursor)) {
  222. AnimCurPtr ac = GetAnimCur(pCursor);
  223. int i;
  224. if (pScreen->myNum == 0)
  225. for (i = 0; i < ac->nelt; i++)
  226. FreeCursor(ac->elts[i].pCursor, 0);
  227. ret = TRUE;
  228. }
  229. else
  230. ret = (*pScreen->UnrealizeCursor) (pScreen, pCursor);
  231. Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
  232. return ret;
  233. }
  234. static void
  235. AnimCurRecolorCursor(ScreenPtr pScreen, CursorPtr pCursor, Bool displayed)
  236. {
  237. AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
  238. Unwrap(as, pScreen, RecolorCursor);
  239. if (IsAnimCur(pCursor)) {
  240. AnimCurPtr ac = GetAnimCur(pCursor);
  241. int i;
  242. for (i = 0; i < ac->nelt; i++)
  243. (*pScreen->RecolorCursor) (pScreen, ac->elts[i].pCursor,
  244. displayed && animCurState.elt == i);
  245. }
  246. else
  247. (*pScreen->RecolorCursor) (pScreen, pCursor, displayed);
  248. Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor);
  249. }
  250. Bool
  251. AnimCurInit(ScreenPtr pScreen)
  252. {
  253. AnimCurScreenPtr as;
  254. if (AnimCurGeneration != serverGeneration) {
  255. AnimCurScreenPrivateIndex = AllocateScreenPrivateIndex();
  256. if (AnimCurScreenPrivateIndex < 0)
  257. return FALSE;
  258. AnimCurGeneration = serverGeneration;
  259. animCurState.pCursor = 0;
  260. animCurState.pScreen = 0;
  261. animCurState.elt = 0;
  262. animCurState.time = 0;
  263. }
  264. as = malloc(sizeof(AnimCurScreenRec));
  265. if (!as)
  266. return FALSE;
  267. Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen);
  268. Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
  269. Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits);
  270. Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor);
  271. Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
  272. Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor);
  273. Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
  274. Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor);
  275. SetAnimCurScreen(pScreen, as);
  276. return TRUE;
  277. }
  278. int
  279. AnimCursorCreate(CursorPtr *cursors, CARD32 *deltas, int ncursor,
  280. CursorPtr *ppCursor)
  281. {
  282. CursorPtr pCursor;
  283. int i;
  284. AnimCurPtr ac;
  285. for (i = 0; i < screenInfo.numScreens; i++)
  286. if (!GetAnimCurScreenIfSet(screenInfo.screens[i]))
  287. return BadImplementation;
  288. for (i = 0; i < ncursor; i++)
  289. if (IsAnimCur(cursors[i]))
  290. return BadMatch;
  291. pCursor = malloc(sizeof(CursorRec) +
  292. sizeof(AnimCurRec) +
  293. ncursor * sizeof(AnimCurElt));
  294. if (!pCursor)
  295. return BadAlloc;
  296. pCursor->bits = &animCursorBits;
  297. animCursorBits.refcnt++;
  298. pCursor->refcnt = 1;
  299. pCursor->foreRed = cursors[0]->foreRed;
  300. pCursor->foreGreen = cursors[0]->foreGreen;
  301. pCursor->foreBlue = cursors[0]->foreBlue;
  302. pCursor->backRed = cursors[0]->backRed;
  303. pCursor->backGreen = cursors[0]->backGreen;
  304. pCursor->backBlue = cursors[0]->backBlue;
  305. /*
  306. * Fill in the AnimCurRec
  307. */
  308. ac = GetAnimCur(pCursor);
  309. ac->nelt = ncursor;
  310. ac->elts = (AnimCurElt *) (ac + 1);
  311. for (i = 0; i < ncursor; i++) {
  312. cursors[i]->refcnt++;
  313. ac->elts[i].pCursor = cursors[i];
  314. ac->elts[i].delay = deltas[i];
  315. }
  316. *ppCursor = pCursor;
  317. return Success;
  318. }