Imported Upstream version 1.15.1
[deb_xorg-server.git] / render / animcur.c
CommitLineData
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
50typedef struct _AnimCurElt {
51 CursorPtr pCursor; /* cursor to show */
52 CARD32 delay; /* in ms */
53} AnimCurElt;
54
55typedef 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
60typedef 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
73static unsigned char empty[4];
74
75static CursorBits animCursorBits = {
76 empty, empty, 2, 1, 1, 0, 0, 1
77};
78
79static 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
91static Bool
92AnimCurCloseScreen(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
111static void
112AnimCurCursorLimits(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
137static void
138AnimCurScreenBlockHandler(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
192static Bool
193AnimCurDisplayCursor(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
231static Bool
232AnimCurSetCursorPosition(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
250static Bool
251AnimCurRealizeCursor(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
265static Bool
266AnimCurUnrealizeCursor(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
287static void
288AnimCurRecolorCursor(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
308Bool
309AnimCurInit(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
333int
334AnimCursorCreate(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}