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