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
50 typedef struct _AnimCurElt {
51 CursorPtr pCursor; /* cursor to show */
52 CARD32 delay; /* in ms */
53 } AnimCurElt;
54
55 typedef struct _AnimCur {
56 int nelt; /* number of elements in the elts array */
57 AnimCurElt *elts; /* actually allocated right after the structure */
58 OsTimerPtr timer;
59 } AnimCurRec, *AnimCurPtr;
60
61 typedef struct _AnimScrPriv {
62 CloseScreenProcPtr CloseScreen;
63 CursorLimitsProcPtr CursorLimits;
64 DisplayCursorProcPtr DisplayCursor;
65 SetCursorPositionProcPtr SetCursorPosition;
66 RealizeCursorProcPtr RealizeCursor;
67 UnrealizeCursorProcPtr UnrealizeCursor;
68 RecolorCursorProcPtr RecolorCursor;
69 } AnimCurScreenRec, *AnimCurScreenPtr;
70
71 static unsigned char empty[4];
72
73 static CursorBits animCursorBits = {
74 empty, empty, 2, 1, 1, 0, 0, 1
75 };
76
77 static DevPrivateKeyRec AnimCurScreenPrivateKeyRec;
78
79 #define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits))
80 #define GetAnimCur(c) ((AnimCurPtr) ((((char *)(c) + CURSOR_REC_SIZE))))
81 #define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, &AnimCurScreenPrivateKeyRec))
82
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
86 static Bool
AnimCurCloseScreen(ScreenPtr pScreen)87 AnimCurCloseScreen(ScreenPtr pScreen)
88 {
89 AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
90 Bool ret;
91
92 Unwrap(as, pScreen, CloseScreen);
93
94 Unwrap(as, pScreen, CursorLimits);
95 Unwrap(as, pScreen, DisplayCursor);
96 Unwrap(as, pScreen, SetCursorPosition);
97 Unwrap(as, pScreen, RealizeCursor);
98 Unwrap(as, pScreen, UnrealizeCursor);
99 Unwrap(as, pScreen, RecolorCursor);
100 ret = (*pScreen->CloseScreen) (pScreen);
101 return ret;
102 }
103
104 static void
AnimCurCursorLimits(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,BoxPtr pHotBox,BoxPtr pTopLeftBox)105 AnimCurCursorLimits(DeviceIntPtr pDev,
106 ScreenPtr pScreen,
107 CursorPtr pCursor, BoxPtr pHotBox, BoxPtr pTopLeftBox)
108 {
109 AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
110
111 Unwrap(as, pScreen, CursorLimits);
112 if (IsAnimCur(pCursor)) {
113 AnimCurPtr ac = GetAnimCur(pCursor);
114
115 (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor,
116 pHotBox, pTopLeftBox);
117 }
118 else {
119 (*pScreen->CursorLimits) (pDev, pScreen, pCursor, pHotBox, pTopLeftBox);
120 }
121 Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits);
122 }
123
124 /*
125 * The cursor animation timer has expired, go display any relevant cursor changes
126 * and compute a new timeout value
127 */
128
129 static CARD32
AnimCurTimerNotify(OsTimerPtr timer,CARD32 now,void * arg)130 AnimCurTimerNotify(OsTimerPtr timer, CARD32 now, void *arg)
131 {
132 DeviceIntPtr dev = arg;
133 ScreenPtr pScreen = dev->spriteInfo->anim.pScreen;
134 AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
135
136 AnimCurPtr ac = GetAnimCur(dev->spriteInfo->sprite->current);
137 int elt = (dev->spriteInfo->anim.elt + 1) % ac->nelt;
138 DisplayCursorProcPtr DisplayCursor = pScreen->DisplayCursor;
139
140 /*
141 * Not a simple Unwrap/Wrap as this isn't called along the DisplayCursor
142 * wrapper chain.
143 */
144 pScreen->DisplayCursor = as->DisplayCursor;
145 (void) (*pScreen->DisplayCursor) (dev, pScreen, ac->elts[elt].pCursor);
146 as->DisplayCursor = pScreen->DisplayCursor;
147 pScreen->DisplayCursor = DisplayCursor;
148
149 dev->spriteInfo->anim.elt = elt;
150 dev->spriteInfo->anim.pCursor = ac->elts[elt].pCursor;
151
152 return ac->elts[elt].delay;
153 }
154
155 static void
AnimCurCancelTimer(DeviceIntPtr pDev)156 AnimCurCancelTimer(DeviceIntPtr pDev)
157 {
158 CursorPtr cur = pDev->spriteInfo->sprite ?
159 pDev->spriteInfo->sprite->current : NULL;
160
161 if (IsAnimCur(cur))
162 TimerCancel(GetAnimCur(cur)->timer);
163 }
164
165 static Bool
AnimCurDisplayCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)166 AnimCurDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
167 {
168 AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
169 Bool ret = TRUE;
170
171 if (IsFloating(pDev))
172 return FALSE;
173
174 Unwrap(as, pScreen, DisplayCursor);
175 if (IsAnimCur(pCursor)) {
176 if (pCursor != pDev->spriteInfo->sprite->current) {
177 AnimCurPtr ac = GetAnimCur(pCursor);
178
179 AnimCurCancelTimer(pDev);
180 ret = (*pScreen->DisplayCursor) (pDev, pScreen,
181 ac->elts[0].pCursor);
182
183 if (ret) {
184 pDev->spriteInfo->anim.elt = 0;
185 pDev->spriteInfo->anim.pCursor = pCursor;
186 pDev->spriteInfo->anim.pScreen = pScreen;
187
188 ac->timer = TimerSet(ac->timer, 0, ac->elts[0].delay,
189 AnimCurTimerNotify, pDev);
190 }
191 }
192 }
193 else {
194 AnimCurCancelTimer(pDev);
195 pDev->spriteInfo->anim.pCursor = 0;
196 pDev->spriteInfo->anim.pScreen = 0;
197 ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor);
198 }
199 Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor);
200 return ret;
201 }
202
203 static Bool
AnimCurSetCursorPosition(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y,Bool generateEvent)204 AnimCurSetCursorPosition(DeviceIntPtr pDev,
205 ScreenPtr pScreen, int x, int y, Bool generateEvent)
206 {
207 AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
208 Bool ret;
209
210 Unwrap(as, pScreen, SetCursorPosition);
211 if (pDev->spriteInfo->anim.pCursor) {
212 pDev->spriteInfo->anim.pScreen = pScreen;
213 }
214 ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent);
215 Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
216 return ret;
217 }
218
219 static Bool
AnimCurRealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)220 AnimCurRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
221 {
222 AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
223 Bool ret;
224
225 Unwrap(as, pScreen, RealizeCursor);
226 if (IsAnimCur(pCursor))
227 ret = TRUE;
228 else
229 ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor);
230 Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor);
231 return ret;
232 }
233
234 static Bool
AnimCurUnrealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)235 AnimCurUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
236 {
237 AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
238 Bool ret;
239
240 Unwrap(as, pScreen, UnrealizeCursor);
241 if (IsAnimCur(pCursor)) {
242 AnimCurPtr ac = GetAnimCur(pCursor);
243 int i;
244
245 if (pScreen->myNum == 0)
246 for (i = 0; i < ac->nelt; i++)
247 FreeCursor(ac->elts[i].pCursor, 0);
248 ret = TRUE;
249 }
250 else
251 ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor);
252 Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
253 return ret;
254 }
255
256 static void
AnimCurRecolorCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,Bool displayed)257 AnimCurRecolorCursor(DeviceIntPtr pDev,
258 ScreenPtr pScreen, CursorPtr pCursor, Bool displayed)
259 {
260 AnimCurScreenPtr as = GetAnimCurScreen(pScreen);
261
262 Unwrap(as, pScreen, RecolorCursor);
263 if (IsAnimCur(pCursor)) {
264 AnimCurPtr ac = GetAnimCur(pCursor);
265 int i;
266
267 for (i = 0; i < ac->nelt; i++)
268 (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor,
269 displayed &&
270 pDev->spriteInfo->anim.elt == i);
271 }
272 else
273 (*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed);
274 Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor);
275 }
276
277 Bool
AnimCurInit(ScreenPtr pScreen)278 AnimCurInit(ScreenPtr pScreen)
279 {
280 AnimCurScreenPtr as;
281
282 if (!dixRegisterPrivateKey(&AnimCurScreenPrivateKeyRec, PRIVATE_SCREEN,
283 sizeof(AnimCurScreenRec)))
284 return FALSE;
285
286 as = GetAnimCurScreen(pScreen);
287
288 Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen);
289
290 Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits);
291 Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor);
292 Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
293 Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor);
294 Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
295 Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor);
296 return TRUE;
297 }
298
299 int
AnimCursorCreate(CursorPtr * cursors,CARD32 * deltas,int ncursor,CursorPtr * ppCursor,ClientPtr client,XID cid)300 AnimCursorCreate(CursorPtr *cursors, CARD32 *deltas, int ncursor,
301 CursorPtr *ppCursor, ClientPtr client, XID cid)
302 {
303 CursorPtr pCursor;
304 int rc = BadAlloc, i;
305 AnimCurPtr ac;
306
307 for (i = 0; i < screenInfo.numScreens; i++)
308 if (!GetAnimCurScreen(screenInfo.screens[i]))
309 return BadImplementation;
310
311 for (i = 0; i < ncursor; i++)
312 if (IsAnimCur(cursors[i]))
313 return BadMatch;
314
315 pCursor = (CursorPtr) calloc(CURSOR_REC_SIZE +
316 sizeof(AnimCurRec) +
317 ncursor * sizeof(AnimCurElt), 1);
318 if (!pCursor)
319 return rc;
320 dixInitPrivates(pCursor, pCursor + 1, PRIVATE_CURSOR);
321 pCursor->bits = &animCursorBits;
322 pCursor->refcnt = 1;
323
324 pCursor->foreRed = cursors[0]->foreRed;
325 pCursor->foreGreen = cursors[0]->foreGreen;
326 pCursor->foreBlue = cursors[0]->foreBlue;
327
328 pCursor->backRed = cursors[0]->backRed;
329 pCursor->backGreen = cursors[0]->backGreen;
330 pCursor->backBlue = cursors[0]->backBlue;
331
332 pCursor->id = cid;
333
334 ac = GetAnimCur(pCursor);
335 ac->timer = TimerSet(NULL, 0, 0, AnimCurTimerNotify, NULL);
336
337 /* security creation/labeling check */
338 if (ac->timer)
339 rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor,
340 RT_NONE, NULL, DixCreateAccess);
341
342 if (rc != Success) {
343 TimerFree(ac->timer);
344 dixFiniPrivates(pCursor, PRIVATE_CURSOR);
345 free(pCursor);
346 return rc;
347 }
348
349 /*
350 * Fill in the AnimCurRec
351 */
352 animCursorBits.refcnt++;
353 ac->nelt = ncursor;
354 ac->elts = (AnimCurElt *) (ac + 1);
355
356 for (i = 0; i < ncursor; i++) {
357 ac->elts[i].pCursor = RefCursor(cursors[i]);
358 ac->elts[i].delay = deltas[i];
359 }
360
361 *ppCursor = pCursor;
362 return Success;
363 }
364