xref: /OK3568_Linux_fs/external/xserver/mi/misprite.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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     GetImageProcPtr GetImage;
74     GetSpansProcPtr GetSpans;
75     SourceValidateProcPtr SourceValidate;
76 
77     /* window procedures */
78     CopyWindowProcPtr CopyWindow;
79 
80     /* colormap procedures */
81     InstallColormapProcPtr InstallColormap;
82     StoreColorsProcPtr StoreColors;
83 
84     /* os layer procedures */
85     ScreenBlockHandlerProcPtr BlockHandler;
86 
87     xColorItem colors[2];
88     ColormapPtr pInstalledMap;
89     ColormapPtr pColormap;
90     VisualPtr pVisual;
91     DamagePtr pDamage;          /* damage tracking structure */
92     Bool damageRegistered;
93     int numberOfCursors;
94 } miSpriteScreenRec, *miSpriteScreenPtr;
95 
96 #define SOURCE_COLOR	0
97 #define MASK_COLOR	1
98 
99 /*
100  * Overlap BoxPtr and Box elements
101  */
102 #define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \
103  	(((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \
104 	 ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2))
105 
106 /*
107  * Overlap BoxPtr, origins, and rectangle
108  */
109 #define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \
110     BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h))
111 
112 /*
113  * Overlap BoxPtr, origins and RectPtr
114  */
115 #define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \
116     ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \
117 		(int)((pRect)->width), (int)((pRect)->height))
118 /*
119  * Overlap BoxPtr and horizontal span
120  */
121 #define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y))
122 
123 #define LINE_SORT(x1,y1,x2,y2) \
124 { int _t; \
125   if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \
126   if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } }
127 
128 #define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \
129     BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2))
130 
131 #define SPRITE_DEBUG_ENABLE 0
132 #if SPRITE_DEBUG_ENABLE
133 #define SPRITE_DEBUG(x)	ErrorF x
134 #else
135 #define SPRITE_DEBUG(x)
136 #endif
137 
138 static DevPrivateKeyRec miSpriteScreenKeyRec;
139 static DevPrivateKeyRec miSpriteDevPrivatesKeyRec;
140 
141 static miSpriteScreenPtr
GetSpriteScreen(ScreenPtr pScreen)142 GetSpriteScreen(ScreenPtr pScreen)
143 {
144     return dixLookupPrivate(&pScreen->devPrivates, &miSpriteScreenKeyRec);
145 }
146 
147 static miCursorInfoPtr
GetSprite(DeviceIntPtr dev)148 GetSprite(DeviceIntPtr dev)
149 {
150     if (IsFloating(dev))
151        return dixLookupPrivate(&dev->devPrivates, &miSpriteDevPrivatesKeyRec);
152 
153     return dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates,
154                             &miSpriteDevPrivatesKeyRec);
155 }
156 
157 static void
miSpriteDisableDamage(ScreenPtr pScreen,miSpriteScreenPtr pScreenPriv)158 miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
159 {
160     if (pScreenPriv->damageRegistered) {
161         DamageUnregister(pScreenPriv->pDamage);
162         pScreenPriv->damageRegistered = 0;
163     }
164 }
165 
166 static void
miSpriteEnableDamage(ScreenPtr pScreen,miSpriteScreenPtr pScreenPriv)167 miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
168 {
169     if (!pScreenPriv->damageRegistered) {
170         pScreenPriv->damageRegistered = 1;
171         DamageRegister(&(pScreen->GetScreenPixmap(pScreen)->drawable),
172                        pScreenPriv->pDamage);
173     }
174 }
175 
176 static void
miSpriteIsUp(miCursorInfoPtr pDevCursor)177 miSpriteIsUp(miCursorInfoPtr pDevCursor)
178 {
179     pDevCursor->isUp = TRUE;
180 }
181 
182 static void
miSpriteIsDown(miCursorInfoPtr pDevCursor)183 miSpriteIsDown(miCursorInfoPtr pDevCursor)
184 {
185     pDevCursor->isUp = FALSE;
186 }
187 
188 /*
189  * screen wrappers
190  */
191 
192 static Bool miSpriteCloseScreen(ScreenPtr pScreen);
193 static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy,
194                              int w, int h, unsigned int format,
195                              unsigned long planemask, char *pdstLine);
196 static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax,
197                              DDXPointPtr ppt, int *pwidth, int nspans,
198                              char *pdstStart);
199 static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y,
200                                    int width, int height,
201                                    unsigned int subWindowMode);
202 static void miSpriteCopyWindow(WindowPtr pWindow,
203                                DDXPointRec ptOldOrg, RegionPtr prgnSrc);
204 static void miSpriteBlockHandler(ScreenPtr pScreen, void *timeout);
205 static void miSpriteInstallColormap(ColormapPtr pMap);
206 static void miSpriteStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef);
207 
208 static void miSpriteComputeSaved(DeviceIntPtr pDev, ScreenPtr pScreen);
209 
210 static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev,
211                                            ScreenPtr pScreen);
212 static void miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen);
213 
214 #define SCREEN_PROLOGUE(pPriv, pScreen, field) ((pScreen)->field = \
215    (pPriv)->field)
216 #define SCREEN_EPILOGUE(pPriv, pScreen, field)\
217     ((pPriv)->field = (pScreen)->field, (pScreen)->field = miSprite##field)
218 
219 /*
220  * pointer-sprite method table
221  */
222 
223 static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
224                                   CursorPtr pCursor);
225 static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
226                                     CursorPtr pCursor);
227 static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
228                               CursorPtr pCursor, int x, int y);
229 static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
230                                int x, int y);
231 
232 miPointerSpriteFuncRec miSpritePointerFuncs = {
233     miSpriteRealizeCursor,
234     miSpriteUnrealizeCursor,
235     miSpriteSetCursor,
236     miSpriteMoveCursor,
237     miSpriteDeviceCursorInitialize,
238     miSpriteDeviceCursorCleanup,
239 };
240 
241 /*
242  * other misc functions
243  */
244 
245 static void miSpriteRemoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen);
246 static void miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen);
247 static void miSpriteRestoreCursor(DeviceIntPtr pDev, ScreenPtr pScreen);
248 
249 static void
miSpriteRegisterBlockHandler(ScreenPtr pScreen,miSpriteScreenPtr pScreenPriv)250 miSpriteRegisterBlockHandler(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
251 {
252     if (!pScreenPriv->BlockHandler) {
253         pScreenPriv->BlockHandler = pScreen->BlockHandler;
254         pScreen->BlockHandler = miSpriteBlockHandler;
255     }
256 }
257 
258 static void
miSpriteReportDamage(DamagePtr pDamage,RegionPtr pRegion,void * closure)259 miSpriteReportDamage(DamagePtr pDamage, RegionPtr pRegion, void *closure)
260 {
261     ScreenPtr pScreen = closure;
262     miCursorInfoPtr pCursorInfo;
263     DeviceIntPtr pDev;
264 
265     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
266         if (DevHasCursor(pDev)) {
267             pCursorInfo = GetSprite(pDev);
268 
269             if (pCursorInfo->isUp &&
270                 pCursorInfo->pScreen == pScreen &&
271                 RegionContainsRect(pRegion, &pCursorInfo->saved) != rgnOUT) {
272                 SPRITE_DEBUG(("Damage remove\n"));
273                 miSpriteRemoveCursor(pDev, pScreen);
274             }
275         }
276     }
277 }
278 
279 /*
280  * miSpriteInitialize -- called from device-dependent screen
281  * initialization proc after all of the function pointers have
282  * been stored in the screen structure.
283  */
284 
285 Bool
miSpriteInitialize(ScreenPtr pScreen,miPointerScreenFuncPtr screenFuncs)286 miSpriteInitialize(ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs)
287 {
288     miSpriteScreenPtr pScreenPriv;
289     VisualPtr pVisual;
290 
291     if (!DamageSetup(pScreen))
292         return FALSE;
293 
294     if (!dixRegisterPrivateKey(&miSpriteScreenKeyRec, PRIVATE_SCREEN, 0))
295         return FALSE;
296 
297     if (!dixRegisterPrivateKey
298         (&miSpriteDevPrivatesKeyRec, PRIVATE_DEVICE, sizeof(miCursorInfoRec)))
299         return FALSE;
300 
301     pScreenPriv = malloc(sizeof(miSpriteScreenRec));
302     if (!pScreenPriv)
303         return FALSE;
304 
305     pScreenPriv->pDamage = DamageCreate(miSpriteReportDamage,
306                                         NULL,
307                                         DamageReportRawRegion,
308                                         TRUE, pScreen, pScreen);
309 
310     if (!miPointerInitialize(pScreen, &miSpritePointerFuncs, screenFuncs, TRUE)) {
311         free(pScreenPriv);
312         return FALSE;
313     }
314     for (pVisual = pScreen->visuals;
315          pVisual->vid != pScreen->rootVisual; pVisual++);
316     pScreenPriv->pVisual = pVisual;
317     pScreenPriv->CloseScreen = pScreen->CloseScreen;
318     pScreenPriv->GetImage = pScreen->GetImage;
319     pScreenPriv->GetSpans = pScreen->GetSpans;
320     pScreenPriv->SourceValidate = pScreen->SourceValidate;
321 
322     pScreenPriv->CopyWindow = pScreen->CopyWindow;
323 
324     pScreenPriv->InstallColormap = pScreen->InstallColormap;
325     pScreenPriv->StoreColors = pScreen->StoreColors;
326 
327     pScreenPriv->BlockHandler = NULL;
328 
329     pScreenPriv->pInstalledMap = NULL;
330     pScreenPriv->pColormap = NULL;
331     pScreenPriv->colors[SOURCE_COLOR].red = 0;
332     pScreenPriv->colors[SOURCE_COLOR].green = 0;
333     pScreenPriv->colors[SOURCE_COLOR].blue = 0;
334     pScreenPriv->colors[MASK_COLOR].red = 0;
335     pScreenPriv->colors[MASK_COLOR].green = 0;
336     pScreenPriv->colors[MASK_COLOR].blue = 0;
337     pScreenPriv->damageRegistered = 0;
338     pScreenPriv->numberOfCursors = 0;
339 
340     dixSetPrivate(&pScreen->devPrivates, &miSpriteScreenKeyRec, pScreenPriv);
341 
342     pScreen->CloseScreen = miSpriteCloseScreen;
343     pScreen->GetImage = miSpriteGetImage;
344     pScreen->GetSpans = miSpriteGetSpans;
345     pScreen->SourceValidate = miSpriteSourceValidate;
346 
347     pScreen->CopyWindow = miSpriteCopyWindow;
348     pScreen->InstallColormap = miSpriteInstallColormap;
349     pScreen->StoreColors = miSpriteStoreColors;
350 
351     return TRUE;
352 }
353 
354 /*
355  * Screen wrappers
356  */
357 
358 /*
359  * CloseScreen wrapper -- unwrap everything, free the private data
360  * and call the wrapped function
361  */
362 
363 static Bool
miSpriteCloseScreen(ScreenPtr pScreen)364 miSpriteCloseScreen(ScreenPtr pScreen)
365 {
366     miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen);
367 
368     pScreen->CloseScreen = pScreenPriv->CloseScreen;
369     pScreen->GetImage = pScreenPriv->GetImage;
370     pScreen->GetSpans = pScreenPriv->GetSpans;
371     pScreen->SourceValidate = pScreenPriv->SourceValidate;
372     pScreen->InstallColormap = pScreenPriv->InstallColormap;
373     pScreen->StoreColors = pScreenPriv->StoreColors;
374 
375     DamageDestroy(pScreenPriv->pDamage);
376 
377     free(pScreenPriv);
378 
379     return (*pScreen->CloseScreen) (pScreen);
380 }
381 
382 static void
miSpriteGetImage(DrawablePtr pDrawable,int sx,int sy,int w,int h,unsigned int format,unsigned long planemask,char * pdstLine)383 miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
384                  unsigned int format, unsigned long planemask, char *pdstLine)
385 {
386     ScreenPtr pScreen = pDrawable->pScreen;
387     DeviceIntPtr pDev;
388     miCursorInfoPtr pCursorInfo;
389     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
390 
391     SCREEN_PROLOGUE(pPriv, pScreen, GetImage);
392 
393     if (pDrawable->type == DRAWABLE_WINDOW) {
394         for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
395             if (DevHasCursor(pDev)) {
396                 pCursorInfo = GetSprite(pDev);
397                 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
398                     ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y,
399                                 sx, sy, w, h)) {
400                     SPRITE_DEBUG(("GetImage remove\n"));
401                     miSpriteRemoveCursor(pDev, pScreen);
402                 }
403             }
404         }
405     }
406 
407     (*pScreen->GetImage) (pDrawable, sx, sy, w, h, format, planemask, pdstLine);
408 
409     SCREEN_EPILOGUE(pPriv, pScreen, GetImage);
410 }
411 
412 static void
miSpriteGetSpans(DrawablePtr pDrawable,int wMax,DDXPointPtr ppt,int * pwidth,int nspans,char * pdstStart)413 miSpriteGetSpans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt,
414                  int *pwidth, int nspans, char *pdstStart)
415 {
416     ScreenPtr pScreen = pDrawable->pScreen;
417     DeviceIntPtr pDev;
418     miCursorInfoPtr pCursorInfo;
419     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
420 
421     SCREEN_PROLOGUE(pPriv, pScreen, GetSpans);
422 
423     if (pDrawable->type == DRAWABLE_WINDOW) {
424         for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
425             if (DevHasCursor(pDev)) {
426                 pCursorInfo = GetSprite(pDev);
427 
428                 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) {
429                     DDXPointPtr pts;
430                     int *widths;
431                     int nPts;
432                     int xorg, yorg;
433 
434                     xorg = pDrawable->x;
435                     yorg = pDrawable->y;
436 
437                     for (pts = ppt, widths = pwidth, nPts = nspans;
438                          nPts--; pts++, widths++) {
439                         if (SPN_OVERLAP(&pCursorInfo->saved, pts->y + yorg,
440                                         pts->x + xorg, *widths)) {
441                             SPRITE_DEBUG(("GetSpans remove\n"));
442                             miSpriteRemoveCursor(pDev, pScreen);
443                             break;
444                         }
445                     }
446                 }
447             }
448         }
449     }
450 
451     (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
452 
453     SCREEN_EPILOGUE(pPriv, pScreen, GetSpans);
454 }
455 
456 static void
miSpriteSourceValidate(DrawablePtr pDrawable,int x,int y,int width,int height,unsigned int subWindowMode)457 miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, int width,
458                        int height, unsigned int subWindowMode)
459 {
460     ScreenPtr pScreen = pDrawable->pScreen;
461     DeviceIntPtr pDev;
462     miCursorInfoPtr pCursorInfo;
463     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
464 
465     SCREEN_PROLOGUE(pPriv, pScreen, SourceValidate);
466 
467     if (pDrawable->type == DRAWABLE_WINDOW) {
468         for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
469             if (DevHasCursor(pDev)) {
470                 pCursorInfo = GetSprite(pDev);
471                 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
472                     ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y,
473                                 x, y, width, height)) {
474                     SPRITE_DEBUG(("SourceValidate remove\n"));
475                     miSpriteRemoveCursor(pDev, pScreen);
476                 }
477             }
478         }
479     }
480 
481     if (pScreen->SourceValidate)
482         (*pScreen->SourceValidate) (pDrawable, x, y, width, height,
483                                     subWindowMode);
484 
485     SCREEN_EPILOGUE(pPriv, pScreen, SourceValidate);
486 }
487 
488 static void
miSpriteCopyWindow(WindowPtr pWindow,DDXPointRec ptOldOrg,RegionPtr prgnSrc)489 miSpriteCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
490 {
491     ScreenPtr pScreen = pWindow->drawable.pScreen;
492     DeviceIntPtr pDev;
493     miCursorInfoPtr pCursorInfo;
494     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
495 
496     SCREEN_PROLOGUE(pPriv, pScreen, CopyWindow);
497 
498     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
499         if (DevHasCursor(pDev)) {
500             pCursorInfo = GetSprite(pDev);
501             /*
502              * Damage will take care of destination check
503              */
504             if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
505                 RegionContainsRect(prgnSrc, &pCursorInfo->saved) != rgnOUT) {
506                 SPRITE_DEBUG(("CopyWindow remove\n"));
507                 miSpriteRemoveCursor(pDev, pScreen);
508             }
509         }
510     }
511 
512     (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
513     SCREEN_EPILOGUE(pPriv, pScreen, CopyWindow);
514 }
515 
516 static void
miSpriteBlockHandler(ScreenPtr pScreen,void * timeout)517 miSpriteBlockHandler(ScreenPtr pScreen, void *timeout)
518 {
519     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
520     DeviceIntPtr pDev;
521     miCursorInfoPtr pCursorInfo;
522     Bool WorkToDo = FALSE;
523 
524     SCREEN_PROLOGUE(pPriv, pScreen, BlockHandler);
525 
526     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
527         if (DevHasCursor(pDev)) {
528             pCursorInfo = GetSprite(pDev);
529             if (pCursorInfo && !pCursorInfo->isUp
530                 && pCursorInfo->pScreen == pScreen && pCursorInfo->shouldBeUp) {
531                 SPRITE_DEBUG(("BlockHandler save"));
532                 miSpriteSaveUnderCursor(pDev, pScreen);
533             }
534         }
535     }
536     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
537         if (DevHasCursor(pDev)) {
538             pCursorInfo = GetSprite(pDev);
539             if (pCursorInfo && !pCursorInfo->isUp &&
540                 pCursorInfo->pScreen == pScreen && pCursorInfo->shouldBeUp) {
541                 SPRITE_DEBUG(("BlockHandler restore\n"));
542                 miSpriteRestoreCursor(pDev, pScreen);
543                 if (!pCursorInfo->isUp)
544                     WorkToDo = TRUE;
545             }
546         }
547     }
548 
549     (*pScreen->BlockHandler) (pScreen, timeout);
550 
551     if (WorkToDo)
552         SCREEN_EPILOGUE(pPriv, pScreen, BlockHandler);
553     else
554         pPriv->BlockHandler = NULL;
555 }
556 
557 static void
miSpriteInstallColormap(ColormapPtr pMap)558 miSpriteInstallColormap(ColormapPtr pMap)
559 {
560     ScreenPtr pScreen = pMap->pScreen;
561     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
562 
563     SCREEN_PROLOGUE(pPriv, pScreen, InstallColormap);
564 
565     (*pScreen->InstallColormap) (pMap);
566 
567     SCREEN_EPILOGUE(pPriv, pScreen, InstallColormap);
568 
569     /* InstallColormap can be called before devices are initialized. */
570     pPriv->pInstalledMap = pMap;
571     if (pPriv->pColormap != pMap) {
572         DeviceIntPtr pDev;
573         miCursorInfoPtr pCursorInfo;
574 
575         for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
576             if (DevHasCursor(pDev)) {
577                 pCursorInfo = GetSprite(pDev);
578                 pCursorInfo->checkPixels = TRUE;
579                 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
580                     miSpriteRemoveCursor(pDev, pScreen);
581             }
582         }
583 
584     }
585 }
586 
587 static void
miSpriteStoreColors(ColormapPtr pMap,int ndef,xColorItem * pdef)588 miSpriteStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef)
589 {
590     ScreenPtr pScreen = pMap->pScreen;
591     miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
592     int i;
593     int updated;
594     VisualPtr pVisual;
595     DeviceIntPtr pDev;
596     miCursorInfoPtr pCursorInfo;
597 
598     SCREEN_PROLOGUE(pPriv, pScreen, StoreColors);
599 
600     (*pScreen->StoreColors) (pMap, ndef, pdef);
601 
602     SCREEN_EPILOGUE(pPriv, pScreen, StoreColors);
603 
604     if (pPriv->pColormap == pMap) {
605         updated = 0;
606         pVisual = pMap->pVisual;
607         if (pVisual->class == DirectColor) {
608             /* Direct color - match on any of the subfields */
609 
610 #define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask)))
611 
612 #define UpdateDAC(dev, plane,dac,mask) {\
613     if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\
614 	dev->colors[plane].dac = pdef[i].dac; \
615 	updated = 1; \
616     } \
617 }
618 
619 #define CheckDirect(dev, plane) \
620 	    UpdateDAC(dev, plane,red,redMask) \
621 	    UpdateDAC(dev, plane,green,greenMask) \
622 	    UpdateDAC(dev, plane,blue,blueMask)
623 
624             for (i = 0; i < ndef; i++) {
625                 CheckDirect(pPriv, SOURCE_COLOR)
626                     CheckDirect(pPriv, MASK_COLOR)
627             }
628         }
629         else {
630             /* PseudoColor/GrayScale - match on exact pixel */
631             for (i = 0; i < ndef; i++) {
632                 if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel) {
633                     pPriv->colors[SOURCE_COLOR] = pdef[i];
634                     if (++updated == 2)
635                         break;
636                 }
637                 if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel) {
638                     pPriv->colors[MASK_COLOR] = pdef[i];
639                     if (++updated == 2)
640                         break;
641                 }
642             }
643         }
644         if (updated) {
645             for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
646                 if (DevHasCursor(pDev)) {
647                     pCursorInfo = GetSprite(pDev);
648                     pCursorInfo->checkPixels = TRUE;
649                     if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
650                         miSpriteRemoveCursor(pDev, pScreen);
651                 }
652             }
653         }
654     }
655 }
656 
657 static void
miSpriteFindColors(miCursorInfoPtr pDevCursor,ScreenPtr pScreen)658 miSpriteFindColors(miCursorInfoPtr pDevCursor, ScreenPtr pScreen)
659 {
660     miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen);
661     CursorPtr pCursor;
662     xColorItem *sourceColor, *maskColor;
663 
664     pCursor = pDevCursor->pCursor;
665     sourceColor = &pScreenPriv->colors[SOURCE_COLOR];
666     maskColor = &pScreenPriv->colors[MASK_COLOR];
667     if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap ||
668         !(pCursor->foreRed == sourceColor->red &&
669           pCursor->foreGreen == sourceColor->green &&
670           pCursor->foreBlue == sourceColor->blue &&
671           pCursor->backRed == maskColor->red &&
672           pCursor->backGreen == maskColor->green &&
673           pCursor->backBlue == maskColor->blue)) {
674         pScreenPriv->pColormap = pScreenPriv->pInstalledMap;
675         sourceColor->red = pCursor->foreRed;
676         sourceColor->green = pCursor->foreGreen;
677         sourceColor->blue = pCursor->foreBlue;
678         FakeAllocColor(pScreenPriv->pColormap, sourceColor);
679         maskColor->red = pCursor->backRed;
680         maskColor->green = pCursor->backGreen;
681         maskColor->blue = pCursor->backBlue;
682         FakeAllocColor(pScreenPriv->pColormap, maskColor);
683         /* "free" the pixels right away, don't let this confuse you */
684         FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel);
685         FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel);
686     }
687 
688     pDevCursor->checkPixels = FALSE;
689 
690 }
691 
692 /*
693  * miPointer interface routines
694  */
695 
696 #define SPRITE_PAD  8
697 
698 static Bool
miSpriteRealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)699 miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
700 {
701     miCursorInfoPtr pCursorInfo;
702 
703     if (IsFloating(pDev))
704         return FALSE;
705 
706     pCursorInfo = GetSprite(pDev);
707 
708     if (pCursor == pCursorInfo->pCursor)
709         pCursorInfo->checkPixels = TRUE;
710 
711     return miDCRealizeCursor(pScreen, pCursor);
712 }
713 
714 static Bool
miSpriteUnrealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)715 miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
716 {
717     return miDCUnrealizeCursor(pScreen, pCursor);
718 }
719 
720 static void
miSpriteSetCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)721 miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
722                   CursorPtr pCursor, int x, int y)
723 {
724     miCursorInfoPtr pPointer;
725     miSpriteScreenPtr pScreenPriv;
726 
727     if (IsFloating(pDev))
728         return;
729 
730     pPointer = GetSprite(pDev);
731     pScreenPriv = GetSpriteScreen(pScreen);
732 
733     if (!pCursor) {
734         if (pPointer->shouldBeUp)
735             --pScreenPriv->numberOfCursors;
736         pPointer->shouldBeUp = FALSE;
737         if (pPointer->isUp)
738             miSpriteRemoveCursor(pDev, pScreen);
739         if (pScreenPriv->numberOfCursors == 0)
740             miSpriteDisableDamage(pScreen, pScreenPriv);
741         pPointer->pCursor = 0;
742         return;
743     }
744     if (!pPointer->shouldBeUp)
745         pScreenPriv->numberOfCursors++;
746     pPointer->shouldBeUp = TRUE;
747     if (!pPointer->isUp)
748         miSpriteRegisterBlockHandler(pScreen, pScreenPriv);
749     if (pPointer->x == x &&
750         pPointer->y == y &&
751         pPointer->pCursor == pCursor && !pPointer->checkPixels) {
752         return;
753     }
754     pPointer->x = x;
755     pPointer->y = y;
756     if (pPointer->checkPixels || pPointer->pCursor != pCursor) {
757         pPointer->pCursor = pCursor;
758         miSpriteFindColors(pPointer, pScreen);
759     }
760     if (pPointer->isUp) {
761         /* TODO: reimplement flicker-free MoveCursor */
762         SPRITE_DEBUG(("SetCursor remove %d\n", pDev->id));
763         miSpriteRemoveCursor(pDev, pScreen);
764     }
765 
766     if (!pPointer->isUp && pPointer->pCursor) {
767         SPRITE_DEBUG(("SetCursor restore %d\n", pDev->id));
768         miSpriteSaveUnderCursor(pDev, pScreen);
769         miSpriteRestoreCursor(pDev, pScreen);
770     }
771 
772 }
773 
774 static void
miSpriteMoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)775 miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
776 {
777     CursorPtr pCursor;
778 
779     if (IsFloating(pDev))
780         return;
781 
782     pCursor = GetSprite(pDev)->pCursor;
783 
784     miSpriteSetCursor(pDev, pScreen, pCursor, x, y);
785 }
786 
787 static Bool
miSpriteDeviceCursorInitialize(DeviceIntPtr pDev,ScreenPtr pScreen)788 miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
789 {
790     int ret = miDCDeviceInitialize(pDev, pScreen);
791 
792     if (ret) {
793         miCursorInfoPtr pCursorInfo;
794 
795         pCursorInfo =
796             dixLookupPrivate(&pDev->devPrivates, &miSpriteDevPrivatesKeyRec);
797         pCursorInfo->pCursor = NULL;
798         pCursorInfo->x = 0;
799         pCursorInfo->y = 0;
800         pCursorInfo->isUp = FALSE;
801         pCursorInfo->shouldBeUp = FALSE;
802         pCursorInfo->checkPixels = TRUE;
803         pCursorInfo->pScreen = FALSE;
804     }
805 
806     return ret;
807 }
808 
809 static void
miSpriteDeviceCursorCleanup(DeviceIntPtr pDev,ScreenPtr pScreen)810 miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
811 {
812     miCursorInfoPtr pCursorInfo =
813         dixLookupPrivate(&pDev->devPrivates, &miSpriteDevPrivatesKeyRec);
814 
815     if (DevHasCursor(pDev))
816         miDCDeviceCleanup(pDev, pScreen);
817 
818     memset(pCursorInfo, 0, sizeof(miCursorInfoRec));
819 }
820 
821 /*
822  * undraw/draw cursor
823  */
824 
825 static void
miSpriteRemoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen)826 miSpriteRemoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
827 {
828     miSpriteScreenPtr pScreenPriv;
829     miCursorInfoPtr pCursorInfo;
830 
831     if (IsFloating(pDev))
832         return;
833 
834     DamageDrawInternal(pScreen, TRUE);
835     pScreenPriv = GetSpriteScreen(pScreen);
836     pCursorInfo = GetSprite(pDev);
837 
838     miSpriteIsDown(pCursorInfo);
839     miSpriteRegisterBlockHandler(pScreen, pScreenPriv);
840     miSpriteDisableDamage(pScreen, pScreenPriv);
841     if (!miDCRestoreUnderCursor(pDev,
842                                 pScreen,
843                                 pCursorInfo->saved.x1,
844                                 pCursorInfo->saved.y1,
845                                 pCursorInfo->saved.x2 -
846                                 pCursorInfo->saved.x1,
847                                 pCursorInfo->saved.y2 -
848                                 pCursorInfo->saved.y1)) {
849         miSpriteIsUp(pCursorInfo);
850     }
851     miSpriteEnableDamage(pScreen, pScreenPriv);
852     DamageDrawInternal(pScreen, FALSE);
853 }
854 
855 /*
856  * Called from the block handler, saves area under cursor
857  * before waiting for something to do.
858  */
859 
860 static void
miSpriteSaveUnderCursor(DeviceIntPtr pDev,ScreenPtr pScreen)861 miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
862 {
863     miSpriteScreenPtr pScreenPriv;
864     miCursorInfoPtr pCursorInfo;
865 
866     if (IsFloating(pDev))
867         return;
868 
869     DamageDrawInternal(pScreen, TRUE);
870     pScreenPriv = GetSpriteScreen(pScreen);
871     pCursorInfo = GetSprite(pDev);
872 
873     miSpriteComputeSaved(pDev, pScreen);
874 
875     miSpriteDisableDamage(pScreen, pScreenPriv);
876 
877     miDCSaveUnderCursor(pDev,
878                         pScreen,
879                         pCursorInfo->saved.x1,
880                         pCursorInfo->saved.y1,
881                         pCursorInfo->saved.x2 -
882                         pCursorInfo->saved.x1,
883                         pCursorInfo->saved.y2 - pCursorInfo->saved.y1);
884     SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id));
885     miSpriteEnableDamage(pScreen, pScreenPriv);
886     DamageDrawInternal(pScreen, FALSE);
887 }
888 
889 /*
890  * Called from the block handler, restores the cursor
891  * before waiting for something to do.
892  */
893 
894 static void
miSpriteRestoreCursor(DeviceIntPtr pDev,ScreenPtr pScreen)895 miSpriteRestoreCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
896 {
897     miSpriteScreenPtr pScreenPriv;
898     int x, y;
899     CursorPtr pCursor;
900     miCursorInfoPtr pCursorInfo;
901 
902     if (IsFloating(pDev))
903         return;
904 
905     DamageDrawInternal(pScreen, TRUE);
906     pScreenPriv = GetSpriteScreen(pScreen);
907     pCursorInfo = GetSprite(pDev);
908 
909     miSpriteComputeSaved(pDev, pScreen);
910     pCursor = pCursorInfo->pCursor;
911 
912     x = pCursorInfo->x - (int) pCursor->bits->xhot;
913     y = pCursorInfo->y - (int) pCursor->bits->yhot;
914     miSpriteDisableDamage(pScreen, pScreenPriv);
915     SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id));
916     if (pCursorInfo->checkPixels)
917         miSpriteFindColors(pCursorInfo, pScreen);
918     if (miDCPutUpCursor(pDev, pScreen,
919                         pCursor, x, y,
920                         pScreenPriv->colors[SOURCE_COLOR].pixel,
921                         pScreenPriv->colors[MASK_COLOR].pixel)) {
922         miSpriteIsUp(pCursorInfo);
923         pCursorInfo->pScreen = pScreen;
924     }
925     miSpriteEnableDamage(pScreen, pScreenPriv);
926     DamageDrawInternal(pScreen, FALSE);
927 }
928 
929 /*
930  * compute the desired area of the screen to save
931  */
932 
933 static void
miSpriteComputeSaved(DeviceIntPtr pDev,ScreenPtr pScreen)934 miSpriteComputeSaved(DeviceIntPtr pDev, ScreenPtr pScreen)
935 {
936     int x, y, w, h;
937     int wpad, hpad;
938     CursorPtr pCursor;
939     miCursorInfoPtr pCursorInfo;
940 
941     if (IsFloating(pDev))
942         return;
943 
944     pCursorInfo = GetSprite(pDev);
945 
946     pCursor = pCursorInfo->pCursor;
947     x = pCursorInfo->x - (int) pCursor->bits->xhot;
948     y = pCursorInfo->y - (int) pCursor->bits->yhot;
949     w = pCursor->bits->width;
950     h = pCursor->bits->height;
951     wpad = SPRITE_PAD;
952     hpad = SPRITE_PAD;
953     pCursorInfo->saved.x1 = x - wpad;
954     pCursorInfo->saved.y1 = y - hpad;
955     pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2;
956     pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2;
957 }
958