1 /*
2  * misprite.c
3  *
4  * machine independent software sprite routines
5  */
6 
7 /*
8 
9 Copyright 1989, 1998  The Open Group
10 
11 Permission to use, copy, modify, distribute, and sell this software and its
12 documentation for any purpose is hereby granted without fee, provided that
13 the above copyright notice appear in all copies and that both that
14 copyright notice and this permission notice appear in supporting
15 documentation.
16 
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
23 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
24 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 
27 Except as contained in this notice, the name of The Open Group shall not be
28 used in advertising or otherwise to promote the sale, use or other dealings
29 in this Software without prior written authorization from The Open Group.
30 */
31 
32 #ifdef HAVE_DIX_CONFIG_H
33 #include <dix-config.h>
34 #endif
35 
36 #include   <X11/X.h>
37 #include   <X11/Xproto.h>
38 #include   "misc.h"
39 #include   "pixmapstr.h"
40 #include   "input.h"
41 #include   "mi.h"
42 #include   "cursorstr.h"
43 #include   <X11/fonts/font.h>
44 #include   "scrnintstr.h"
45 #include   "colormapst.h"
46 #include   "windowstr.h"
47 #include   "gcstruct.h"
48 #include   "mipointer.h"
49 #include   "misprite.h"
50 #include   "dixfontstr.h"
51 #include   <X11/fonts/fontstruct.h>
52 #include   "inputstr.h"
53 #include   "damage.h"
54 
55 typedef struct {
56     CursorPtr pCursor;
57     int x;                      /* cursor hotspot */
58     int y;
59     BoxRec saved;               /* saved area from the screen */
60     Bool isUp;                  /* cursor in frame buffer */
61     Bool shouldBeUp;            /* cursor should be displayed */
62     Bool checkPixels;           /* check colormap collision */
63     ScreenPtr pScreen;
64 } miCursorInfoRec, *miCursorInfoPtr;
65 
66 /*
67  * per screen information
68  */
69 
70 typedef struct {
71     /* screen procedures */
72     CloseScreenProcPtr CloseScreen;
73     SourceValidateProcPtr SourceValidate;
74 
75     /* window procedures */
76     CopyWindowProcPtr CopyWindow;
77 
78     /* colormap procedures */
79     InstallColormapProcPtr InstallColormap;
80     StoreColorsProcPtr StoreColors;
81 
82     /* os layer procedures */
83     ScreenBlockHandlerProcPtr BlockHandler;
84 
85     xColorItem colors[2];
86     ColormapPtr pInstalledMap;
87     ColormapPtr pColormap;
88     VisualPtr pVisual;
89     DamagePtr pDamage;          /* damage tracking structure */
90     Bool damageRegistered;
91     int numberOfCursors;
92 } miSpriteScreenRec, *miSpriteScreenPtr;
93 
94 #define SOURCE_COLOR	0
95 #define MASK_COLOR	1
96 
97 /*
98  * Overlap BoxPtr and Box elements
99  */
100 #define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \
101  	(((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \
102 	 ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2))
103 
104 /*
105  * Overlap BoxPtr, origins, and rectangle
106  */
107 #define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \
108     BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h))
109 
110 /*
111  * Overlap BoxPtr, origins and RectPtr
112  */
113 #define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \
114     ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \
115 		(int)((pRect)->width), (int)((pRect)->height))
116 /*
117  * Overlap BoxPtr and horizontal span
118  */
119 #define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y))
120 
121 #define LINE_SORT(x1,y1,x2,y2) \
122 { int _t; \
123   if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \
124   if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } }
125 
126 #define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \
127     BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2))
128 
129 #define SPRITE_DEBUG_ENABLE 0
130 #if SPRITE_DEBUG_ENABLE
131 #define SPRITE_DEBUG(x)	ErrorF x
132 #else
133 #define SPRITE_DEBUG(x)
134 #endif
135 
136 static DevPrivateKeyRec miSpriteScreenKeyRec;
137 static DevPrivateKeyRec miSpriteDevPrivatesKeyRec;
138 
139 static miSpriteScreenPtr
GetSpriteScreen(ScreenPtr pScreen)140 GetSpriteScreen(ScreenPtr pScreen)
141 {
142     return dixLookupPrivate(&pScreen->devPrivates, &miSpriteScreenKeyRec);
143 }
144 
145 static miCursorInfoPtr
GetSprite(DeviceIntPtr dev)146 GetSprite(DeviceIntPtr dev)
147 {
148     if (IsFloating(dev))
149        return dixLookupPrivate(&dev->devPrivates, &miSpriteDevPrivatesKeyRec);
150 
151     return dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates,
152                             &miSpriteDevPrivatesKeyRec);
153 }
154 
155 static void
miSpriteDisableDamage(ScreenPtr pScreen,miSpriteScreenPtr pScreenPriv)156 miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
157 {
158     if (pScreenPriv->damageRegistered) {
159         DamageUnregister(pScreenPriv->pDamage);
160         pScreenPriv->damageRegistered = 0;
161     }
162 }
163 
164 static void
miSpriteEnableDamage(ScreenPtr pScreen,miSpriteScreenPtr pScreenPriv)165 miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
166 {
167     if (!pScreenPriv->damageRegistered) {
168         pScreenPriv->damageRegistered = 1;
169         DamageRegister(&(pScreen->GetScreenPixmap(pScreen)->drawable),
170                        pScreenPriv->pDamage);
171     }
172 }
173 
174 static void
miSpriteIsUp(miCursorInfoPtr pDevCursor)175 miSpriteIsUp(miCursorInfoPtr pDevCursor)
176 {
177     pDevCursor->isUp = TRUE;
178 }
179 
180 static void
miSpriteIsDown(miCursorInfoPtr pDevCursor)181 miSpriteIsDown(miCursorInfoPtr pDevCursor)
182 {
183     pDevCursor->isUp = FALSE;
184 }
185 
186 /*
187  * screen wrappers
188  */
189 
190 static Bool miSpriteCloseScreen(ScreenPtr pScreen);
191 static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y,
192                                    int width, int height,
193                                    unsigned int subWindowMode);
194 static void miSpriteCopyWindow(WindowPtr pWindow,
195                                DDXPointRec ptOldOrg, RegionPtr prgnSrc);
196 static void miSpriteBlockHandler(ScreenPtr pScreen, void *timeout);
197 static void miSpriteInstallColormap(ColormapPtr pMap);
198 static void miSpriteStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef);
199 
200 static void miSpriteComputeSaved(DeviceIntPtr pDev, ScreenPtr pScreen);
201 
202 static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev,
203                                            ScreenPtr pScreen);
204 static void miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen);
205 
206 #define SCREEN_PROLOGUE(pPriv, pScreen, field) ((pScreen)->field = \
207    (pPriv)->field)
208 #define SCREEN_EPILOGUE(pPriv, pScreen, field)\
209     ((pPriv)->field = (pScreen)->field, (pScreen)->field = miSprite##field)
210 
211 /*
212  * pointer-sprite method table
213  */
214 
215 static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
216                                   CursorPtr pCursor);
217 static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
218                                     CursorPtr pCursor);
219 static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
220                               CursorPtr pCursor, int x, int y);
221 static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
222                                int x, int y);
223 
224 miPointerSpriteFuncRec miSpritePointerFuncs = {
225     miSpriteRealizeCursor,
226     miSpriteUnrealizeCursor,
227     miSpriteSetCursor,
228     miSpriteMoveCursor,
229     miSpriteDeviceCursorInitialize,
230     miSpriteDeviceCursorCleanup,
231 };
232 
233 /*
234  * other misc functions
235  */
236 
237 static void miSpriteRemoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen);
238 static void miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen);
239 static void miSpriteRestoreCursor(DeviceIntPtr pDev, ScreenPtr pScreen);
240 
241 static void
miSpriteRegisterBlockHandler(ScreenPtr pScreen,miSpriteScreenPtr pScreenPriv)242 miSpriteRegisterBlockHandler(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
243 {
244     if (!pScreenPriv->BlockHandler) {
245         pScreenPriv->BlockHandler = pScreen->BlockHandler;
246         pScreen->BlockHandler = miSpriteBlockHandler;
247     }
248 }
249 
250 static void
miSpriteReportDamage(DamagePtr pDamage,RegionPtr pRegion,void * closure)251 miSpriteReportDamage(DamagePtr pDamage, RegionPtr pRegion, void *closure)
252 {
253     ScreenPtr pScreen = closure;
254     miCursorInfoPtr pCursorInfo;
255     DeviceIntPtr pDev;
256 
257     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
258         if (DevHasCursor(pDev)) {
259             pCursorInfo = GetSprite(pDev);
260 
261             if (pCursorInfo->isUp &&
262                 pCursorInfo->pScreen == pScreen &&
263                 RegionContainsRect(pRegion, &pCursorInfo->saved) != rgnOUT) {
264                 SPRITE_DEBUG(("Damage remove\n"));
265                 miSpriteRemoveCursor(pDev, pScreen);
266             }
267         }
268     }
269 }
270 
271 /*
272  * miSpriteInitialize -- called from device-dependent screen
273  * initialization proc after all of the function pointers have
274  * been stored in the screen structure.
275  */
276 
277 Bool
miSpriteInitialize(ScreenPtr pScreen,miPointerScreenFuncPtr screenFuncs)278 miSpriteInitialize(ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs)
279 {
280     miSpriteScreenPtr pScreenPriv;
281     VisualPtr pVisual;
282 
283     if (!DamageSetup(pScreen))
284         return FALSE;
285 
286     if (!dixRegisterPrivateKey(&miSpriteScreenKeyRec, PRIVATE_SCREEN, 0))
287         return FALSE;
288 
289     if (!dixRegisterPrivateKey
290         (&miSpriteDevPrivatesKeyRec, PRIVATE_DEVICE, sizeof(miCursorInfoRec)))
291         return FALSE;
292 
293     pScreenPriv = malloc(sizeof(miSpriteScreenRec));
294     if (!pScreenPriv)
295         return FALSE;
296 
297     pScreenPriv->pDamage = DamageCreate(miSpriteReportDamage,
298                                         NULL,
299                                         DamageReportRawRegion,
300                                         TRUE, pScreen, pScreen);
301 
302     if (!miPointerInitialize(pScreen, &miSpritePointerFuncs, screenFuncs, TRUE)) {
303         free(pScreenPriv);
304         return FALSE;
305     }
306     for (pVisual = pScreen->visuals;
307          pVisual->vid != pScreen->rootVisual; pVisual++);
308     pScreenPriv->pVisual = pVisual;
309     pScreenPriv->CloseScreen = pScreen->CloseScreen;
310     pScreenPriv->SourceValidate = pScreen->SourceValidate;
311 
312     pScreenPriv->CopyWindow = pScreen->CopyWindow;
313 
314     pScreenPriv->InstallColormap = pScreen->InstallColormap;
315     pScreenPriv->StoreColors = pScreen->StoreColors;
316 
317     pScreenPriv->BlockHandler = NULL;
318 
319     pScreenPriv->pInstalledMap = NULL;
320     pScreenPriv->pColormap = NULL;
321     pScreenPriv->colors[SOURCE_COLOR].red = 0;
322     pScreenPriv->colors[SOURCE_COLOR].green = 0;
323     pScreenPriv->colors[SOURCE_COLOR].blue = 0;
324     pScreenPriv->colors[MASK_COLOR].red = 0;
325     pScreenPriv->colors[MASK_COLOR].green = 0;
326     pScreenPriv->colors[MASK_COLOR].blue = 0;
327     pScreenPriv->damageRegistered = 0;
328     pScreenPriv->numberOfCursors = 0;
329 
330     dixSetPrivate(&pScreen->devPrivates, &miSpriteScreenKeyRec, pScreenPriv);
331 
332     pScreen->CloseScreen = miSpriteCloseScreen;
333     pScreen->SourceValidate = miSpriteSourceValidate;
334 
335     pScreen->CopyWindow = miSpriteCopyWindow;
336     pScreen->InstallColormap = miSpriteInstallColormap;
337     pScreen->StoreColors = miSpriteStoreColors;
338 
339     return TRUE;
340 }
341 
342 /*
343  * Screen wrappers
344  */
345 
346 /*
347  * CloseScreen wrapper -- unwrap everything, free the private data
348  * and call the wrapped function
349  */
350 
351 static Bool
miSpriteCloseScreen(ScreenPtr pScreen)352 miSpriteCloseScreen(ScreenPtr pScreen)
353 {
354     miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen);
355 
356     pScreen->CloseScreen = pScreenPriv->CloseScreen;
357     pScreen->SourceValidate = pScreenPriv->SourceValidate;
358     pScreen->InstallColormap = pScreenPriv->InstallColormap;
359     pScreen->StoreColors = pScreenPriv->StoreColors;
360 
361     DamageDestroy(pScreenPriv->pDamage);
362 
363     free(pScreenPriv);
364 
365     return (*pScreen->CloseScreen) (pScreen);
366 }
367 
368 static void
miSpriteSourceValidate(DrawablePtr pDrawable,int x,int y,int width,int height,unsigned int subWindowMode)369 miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, int width,
370                        int height, unsigned int subWindowMode)
371 {
372     ScreenPtr pScreen = pDrawable->pScreen;
373     DeviceIntPtr pDev;
374     miCursorInfoPtr pCursorInfo;
375     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
376 
377     SCREEN_PROLOGUE(pPriv, pScreen, SourceValidate);
378 
379     if (pDrawable->type == DRAWABLE_WINDOW) {
380         for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
381             if (DevHasCursor(pDev)) {
382                 pCursorInfo = GetSprite(pDev);
383                 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
384                     ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y,
385                                 x, y, width, height)) {
386                     SPRITE_DEBUG(("SourceValidate remove\n"));
387                     miSpriteRemoveCursor(pDev, pScreen);
388                 }
389             }
390         }
391     }
392 
393     (*pScreen->SourceValidate) (pDrawable, x, y, width, height,
394                                 subWindowMode);
395 
396     SCREEN_EPILOGUE(pPriv, pScreen, SourceValidate);
397 }
398 
399 static void
miSpriteCopyWindow(WindowPtr pWindow,DDXPointRec ptOldOrg,RegionPtr prgnSrc)400 miSpriteCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
401 {
402     ScreenPtr pScreen = pWindow->drawable.pScreen;
403     DeviceIntPtr pDev;
404     miCursorInfoPtr pCursorInfo;
405     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
406 
407     SCREEN_PROLOGUE(pPriv, pScreen, CopyWindow);
408 
409     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
410         if (DevHasCursor(pDev)) {
411             pCursorInfo = GetSprite(pDev);
412             /*
413              * Damage will take care of destination check
414              */
415             if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
416                 RegionContainsRect(prgnSrc, &pCursorInfo->saved) != rgnOUT) {
417                 SPRITE_DEBUG(("CopyWindow remove\n"));
418                 miSpriteRemoveCursor(pDev, pScreen);
419             }
420         }
421     }
422 
423     (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
424     SCREEN_EPILOGUE(pPriv, pScreen, CopyWindow);
425 }
426 
427 static void
miSpriteBlockHandler(ScreenPtr pScreen,void * timeout)428 miSpriteBlockHandler(ScreenPtr pScreen, void *timeout)
429 {
430     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
431     DeviceIntPtr pDev;
432     miCursorInfoPtr pCursorInfo;
433     Bool WorkToDo = FALSE;
434 
435     SCREEN_PROLOGUE(pPriv, pScreen, BlockHandler);
436 
437     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
438         if (DevHasCursor(pDev)) {
439             pCursorInfo = GetSprite(pDev);
440             if (pCursorInfo && !pCursorInfo->isUp
441                 && pCursorInfo->pScreen == pScreen && pCursorInfo->shouldBeUp) {
442                 SPRITE_DEBUG(("BlockHandler save"));
443                 miSpriteSaveUnderCursor(pDev, pScreen);
444             }
445         }
446     }
447     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
448         if (DevHasCursor(pDev)) {
449             pCursorInfo = GetSprite(pDev);
450             if (pCursorInfo && !pCursorInfo->isUp &&
451                 pCursorInfo->pScreen == pScreen && pCursorInfo->shouldBeUp) {
452                 SPRITE_DEBUG(("BlockHandler restore\n"));
453                 miSpriteRestoreCursor(pDev, pScreen);
454                 if (!pCursorInfo->isUp)
455                     WorkToDo = TRUE;
456             }
457         }
458     }
459 
460     (*pScreen->BlockHandler) (pScreen, timeout);
461 
462     if (WorkToDo)
463         SCREEN_EPILOGUE(pPriv, pScreen, BlockHandler);
464     else
465         pPriv->BlockHandler = NULL;
466 }
467 
468 static void
miSpriteInstallColormap(ColormapPtr pMap)469 miSpriteInstallColormap(ColormapPtr pMap)
470 {
471     ScreenPtr pScreen = pMap->pScreen;
472     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
473 
474     SCREEN_PROLOGUE(pPriv, pScreen, InstallColormap);
475 
476     (*pScreen->InstallColormap) (pMap);
477 
478     SCREEN_EPILOGUE(pPriv, pScreen, InstallColormap);
479 
480     /* InstallColormap can be called before devices are initialized. */
481     pPriv->pInstalledMap = pMap;
482     if (pPriv->pColormap != pMap) {
483         DeviceIntPtr pDev;
484         miCursorInfoPtr pCursorInfo;
485 
486         for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
487             if (DevHasCursor(pDev)) {
488                 pCursorInfo = GetSprite(pDev);
489                 pCursorInfo->checkPixels = TRUE;
490                 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
491                     miSpriteRemoveCursor(pDev, pScreen);
492             }
493         }
494 
495     }
496 }
497 
498 static void
miSpriteStoreColors(ColormapPtr pMap,int ndef,xColorItem * pdef)499 miSpriteStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef)
500 {
501     ScreenPtr pScreen = pMap->pScreen;
502     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
503     int i;
504     int updated;
505     VisualPtr pVisual;
506     DeviceIntPtr pDev;
507     miCursorInfoPtr pCursorInfo;
508 
509     SCREEN_PROLOGUE(pPriv, pScreen, StoreColors);
510 
511     (*pScreen->StoreColors) (pMap, ndef, pdef);
512 
513     SCREEN_EPILOGUE(pPriv, pScreen, StoreColors);
514 
515     if (pPriv->pColormap == pMap) {
516         updated = 0;
517         pVisual = pMap->pVisual;
518         if (pVisual->class == DirectColor) {
519             /* Direct color - match on any of the subfields */
520 
521 #define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask)))
522 
523 #define UpdateDAC(dev, plane,dac,mask) {\
524     if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\
525 	dev->colors[plane].dac = pdef[i].dac; \
526 	updated = 1; \
527     } \
528 }
529 
530 #define CheckDirect(dev, plane) \
531 	    UpdateDAC(dev, plane,red,redMask) \
532 	    UpdateDAC(dev, plane,green,greenMask) \
533 	    UpdateDAC(dev, plane,blue,blueMask)
534 
535             for (i = 0; i < ndef; i++) {
536                 CheckDirect(pPriv, SOURCE_COLOR)
537                     CheckDirect(pPriv, MASK_COLOR)
538             }
539         }
540         else {
541             /* PseudoColor/GrayScale - match on exact pixel */
542             for (i = 0; i < ndef; i++) {
543                 if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel) {
544                     pPriv->colors[SOURCE_COLOR] = pdef[i];
545                     if (++updated == 2)
546                         break;
547                 }
548                 if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel) {
549                     pPriv->colors[MASK_COLOR] = pdef[i];
550                     if (++updated == 2)
551                         break;
552                 }
553             }
554         }
555         if (updated) {
556             for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
557                 if (DevHasCursor(pDev)) {
558                     pCursorInfo = GetSprite(pDev);
559                     pCursorInfo->checkPixels = TRUE;
560                     if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
561                         miSpriteRemoveCursor(pDev, pScreen);
562                 }
563             }
564         }
565     }
566 }
567 
568 static void
miSpriteFindColors(miCursorInfoPtr pDevCursor,ScreenPtr pScreen)569 miSpriteFindColors(miCursorInfoPtr pDevCursor, ScreenPtr pScreen)
570 {
571     miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen);
572     CursorPtr pCursor;
573     xColorItem *sourceColor, *maskColor;
574 
575     pCursor = pDevCursor->pCursor;
576     sourceColor = &pScreenPriv->colors[SOURCE_COLOR];
577     maskColor = &pScreenPriv->colors[MASK_COLOR];
578     if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap ||
579         !(pCursor->foreRed == sourceColor->red &&
580           pCursor->foreGreen == sourceColor->green &&
581           pCursor->foreBlue == sourceColor->blue &&
582           pCursor->backRed == maskColor->red &&
583           pCursor->backGreen == maskColor->green &&
584           pCursor->backBlue == maskColor->blue)) {
585         pScreenPriv->pColormap = pScreenPriv->pInstalledMap;
586         sourceColor->red = pCursor->foreRed;
587         sourceColor->green = pCursor->foreGreen;
588         sourceColor->blue = pCursor->foreBlue;
589         FakeAllocColor(pScreenPriv->pColormap, sourceColor);
590         maskColor->red = pCursor->backRed;
591         maskColor->green = pCursor->backGreen;
592         maskColor->blue = pCursor->backBlue;
593         FakeAllocColor(pScreenPriv->pColormap, maskColor);
594         /* "free" the pixels right away, don't let this confuse you */
595         FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel);
596         FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel);
597     }
598 
599     pDevCursor->checkPixels = FALSE;
600 
601 }
602 
603 /*
604  * miPointer interface routines
605  */
606 
607 #define SPRITE_PAD  8
608 
609 static Bool
miSpriteRealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)610 miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
611 {
612     miCursorInfoPtr pCursorInfo;
613 
614     if (IsFloating(pDev))
615         return FALSE;
616 
617     pCursorInfo = GetSprite(pDev);
618 
619     if (pCursor == pCursorInfo->pCursor)
620         pCursorInfo->checkPixels = TRUE;
621 
622     return miDCRealizeCursor(pScreen, pCursor);
623 }
624 
625 static Bool
miSpriteUnrealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)626 miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
627 {
628     return miDCUnrealizeCursor(pScreen, pCursor);
629 }
630 
631 static void
miSpriteSetCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)632 miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
633                   CursorPtr pCursor, int x, int y)
634 {
635     miCursorInfoPtr pPointer;
636     miSpriteScreenPtr pScreenPriv;
637 
638     if (IsFloating(pDev))
639         return;
640 
641     pPointer = GetSprite(pDev);
642     pScreenPriv = GetSpriteScreen(pScreen);
643 
644     if (!pCursor) {
645         if (pPointer->shouldBeUp)
646             --pScreenPriv->numberOfCursors;
647         pPointer->shouldBeUp = FALSE;
648         if (pPointer->isUp)
649             miSpriteRemoveCursor(pDev, pScreen);
650         if (pScreenPriv->numberOfCursors == 0)
651             miSpriteDisableDamage(pScreen, pScreenPriv);
652         pPointer->pCursor = 0;
653         return;
654     }
655     if (!pPointer->shouldBeUp)
656         pScreenPriv->numberOfCursors++;
657     pPointer->shouldBeUp = TRUE;
658     if (!pPointer->isUp)
659         miSpriteRegisterBlockHandler(pScreen, pScreenPriv);
660     if (pPointer->x == x &&
661         pPointer->y == y &&
662         pPointer->pCursor == pCursor && !pPointer->checkPixels) {
663         return;
664     }
665     pPointer->x = x;
666     pPointer->y = y;
667     if (pPointer->checkPixels || pPointer->pCursor != pCursor) {
668         pPointer->pCursor = pCursor;
669         miSpriteFindColors(pPointer, pScreen);
670     }
671     if (pPointer->isUp) {
672         /* TODO: reimplement flicker-free MoveCursor */
673         SPRITE_DEBUG(("SetCursor remove %d\n", pDev->id));
674         miSpriteRemoveCursor(pDev, pScreen);
675     }
676 
677     if (!pPointer->isUp && pPointer->pCursor) {
678         SPRITE_DEBUG(("SetCursor restore %d\n", pDev->id));
679         miSpriteSaveUnderCursor(pDev, pScreen);
680         miSpriteRestoreCursor(pDev, pScreen);
681     }
682 
683 }
684 
685 static void
miSpriteMoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)686 miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
687 {
688     CursorPtr pCursor;
689 
690     if (IsFloating(pDev))
691         return;
692 
693     pCursor = GetSprite(pDev)->pCursor;
694 
695     miSpriteSetCursor(pDev, pScreen, pCursor, x, y);
696 }
697 
698 static Bool
miSpriteDeviceCursorInitialize(DeviceIntPtr pDev,ScreenPtr pScreen)699 miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
700 {
701     int ret = miDCDeviceInitialize(pDev, pScreen);
702 
703     if (ret) {
704         miCursorInfoPtr pCursorInfo;
705 
706         pCursorInfo =
707             dixLookupPrivate(&pDev->devPrivates, &miSpriteDevPrivatesKeyRec);
708         pCursorInfo->pCursor = NULL;
709         pCursorInfo->x = 0;
710         pCursorInfo->y = 0;
711         pCursorInfo->isUp = FALSE;
712         pCursorInfo->shouldBeUp = FALSE;
713         pCursorInfo->checkPixels = TRUE;
714         pCursorInfo->pScreen = FALSE;
715     }
716 
717     return ret;
718 }
719 
720 static void
miSpriteDeviceCursorCleanup(DeviceIntPtr pDev,ScreenPtr pScreen)721 miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
722 {
723     miCursorInfoPtr pCursorInfo =
724         dixLookupPrivate(&pDev->devPrivates, &miSpriteDevPrivatesKeyRec);
725 
726     if (DevHasCursor(pDev))
727         miDCDeviceCleanup(pDev, pScreen);
728 
729     memset(pCursorInfo, 0, sizeof(miCursorInfoRec));
730 }
731 
732 /*
733  * undraw/draw cursor
734  */
735 
736 static void
miSpriteRemoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen)737 miSpriteRemoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
738 {
739     miSpriteScreenPtr pScreenPriv;
740     miCursorInfoPtr pCursorInfo;
741 
742     if (IsFloating(pDev))
743         return;
744 
745     DamageDrawInternal(pScreen, TRUE);
746     pScreenPriv = GetSpriteScreen(pScreen);
747     pCursorInfo = GetSprite(pDev);
748 
749     miSpriteIsDown(pCursorInfo);
750     miSpriteRegisterBlockHandler(pScreen, pScreenPriv);
751     miSpriteDisableDamage(pScreen, pScreenPriv);
752     if (!miDCRestoreUnderCursor(pDev,
753                                 pScreen,
754                                 pCursorInfo->saved.x1,
755                                 pCursorInfo->saved.y1,
756                                 pCursorInfo->saved.x2 -
757                                 pCursorInfo->saved.x1,
758                                 pCursorInfo->saved.y2 -
759                                 pCursorInfo->saved.y1)) {
760         miSpriteIsUp(pCursorInfo);
761     }
762     miSpriteEnableDamage(pScreen, pScreenPriv);
763     DamageDrawInternal(pScreen, FALSE);
764 }
765 
766 /*
767  * Called from the block handler, saves area under cursor
768  * before waiting for something to do.
769  */
770 
771 static void
miSpriteSaveUnderCursor(DeviceIntPtr pDev,ScreenPtr pScreen)772 miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
773 {
774     miSpriteScreenPtr pScreenPriv;
775     miCursorInfoPtr pCursorInfo;
776 
777     if (IsFloating(pDev))
778         return;
779 
780     DamageDrawInternal(pScreen, TRUE);
781     pScreenPriv = GetSpriteScreen(pScreen);
782     pCursorInfo = GetSprite(pDev);
783 
784     miSpriteComputeSaved(pDev, pScreen);
785 
786     miSpriteDisableDamage(pScreen, pScreenPriv);
787 
788     miDCSaveUnderCursor(pDev,
789                         pScreen,
790                         pCursorInfo->saved.x1,
791                         pCursorInfo->saved.y1,
792                         pCursorInfo->saved.x2 -
793                         pCursorInfo->saved.x1,
794                         pCursorInfo->saved.y2 - pCursorInfo->saved.y1);
795     SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id));
796     miSpriteEnableDamage(pScreen, pScreenPriv);
797     DamageDrawInternal(pScreen, FALSE);
798 }
799 
800 /*
801  * Called from the block handler, restores the cursor
802  * before waiting for something to do.
803  */
804 
805 static void
miSpriteRestoreCursor(DeviceIntPtr pDev,ScreenPtr pScreen)806 miSpriteRestoreCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
807 {
808     miSpriteScreenPtr pScreenPriv;
809     int x, y;
810     CursorPtr pCursor;
811     miCursorInfoPtr pCursorInfo;
812 
813     if (IsFloating(pDev))
814         return;
815 
816     DamageDrawInternal(pScreen, TRUE);
817     pScreenPriv = GetSpriteScreen(pScreen);
818     pCursorInfo = GetSprite(pDev);
819 
820     miSpriteComputeSaved(pDev, pScreen);
821     pCursor = pCursorInfo->pCursor;
822 
823     x = pCursorInfo->x - (int) pCursor->bits->xhot;
824     y = pCursorInfo->y - (int) pCursor->bits->yhot;
825     miSpriteDisableDamage(pScreen, pScreenPriv);
826     SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id));
827     if (pCursorInfo->checkPixels)
828         miSpriteFindColors(pCursorInfo, pScreen);
829     if (miDCPutUpCursor(pDev, pScreen,
830                         pCursor, x, y,
831                         pScreenPriv->colors[SOURCE_COLOR].pixel,
832                         pScreenPriv->colors[MASK_COLOR].pixel)) {
833         miSpriteIsUp(pCursorInfo);
834         pCursorInfo->pScreen = pScreen;
835     }
836     miSpriteEnableDamage(pScreen, pScreenPriv);
837     DamageDrawInternal(pScreen, FALSE);
838 }
839 
840 /*
841  * compute the desired area of the screen to save
842  */
843 
844 static void
miSpriteComputeSaved(DeviceIntPtr pDev,ScreenPtr pScreen)845 miSpriteComputeSaved(DeviceIntPtr pDev, ScreenPtr pScreen)
846 {
847     int x, y, w, h;
848     int wpad, hpad;
849     CursorPtr pCursor;
850     miCursorInfoPtr pCursorInfo;
851 
852     if (IsFloating(pDev))
853         return;
854 
855     pCursorInfo = GetSprite(pDev);
856 
857     pCursor = pCursorInfo->pCursor;
858     x = pCursorInfo->x - (int) pCursor->bits->xhot;
859     y = pCursorInfo->y - (int) pCursor->bits->yhot;
860     w = pCursor->bits->width;
861     h = pCursor->bits->height;
862     wpad = SPRITE_PAD;
863     hpad = SPRITE_PAD;
864     pCursorInfo->saved.x1 = x - wpad;
865     pCursorInfo->saved.y1 = y - hpad;
866     pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2;
867     pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2;
868 }
869