misprite.c revision 4642e01f
1/*
2 * misprite.c
3 *
4 * machine independent software sprite routines
5 */
6
7/*
8
9Copyright 1989, 1998  The Open Group
10
11Permission to use, copy, modify, distribute, and sell this software and its
12documentation for any purpose is hereby granted without fee, provided that
13the above copyright notice appear in all copies and that both that
14copyright notice and this permission notice appear in supporting
15documentation.
16
17The above copyright notice and this permission notice shall be included in
18all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
23OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
24AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27Except as contained in this notice, the name of The Open Group shall not be
28used in advertising or otherwise to promote the sale, use or other dealings
29in 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   "mispritest.h"
50# include   "dixfontstr.h"
51# include   <X11/fonts/fontstruct.h>
52# include   "inputstr.h"
53
54#ifdef RENDER
55# include   "mipict.h"
56#endif
57# include   "damage.h"
58
59
60
61#define SPRITE_DEBUG_ENABLE 0
62#if SPRITE_DEBUG_ENABLE
63#define SPRITE_DEBUG(x)	ErrorF x
64#else
65#define SPRITE_DEBUG(x)
66#endif
67
68
69#define MISPRITE(dev) \
70    ((DevHasCursor(dev)) ? \
71       (miCursorInfoPtr)dixLookupPrivate(&dev->devPrivates, miSpriteDevPrivatesKey) : \
72       (miCursorInfoPtr)dixLookupPrivate(&dev->u.master->devPrivates, miSpriteDevPrivatesKey))
73
74static int damageRegister = 0;
75
76static void
77miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
78{
79    if (damageRegister) {
80	DamageUnregister (&(pScreen->GetScreenPixmap(pScreen)->drawable),
81			  pScreenPriv->pDamage);
82	damageRegister = 0;
83    }
84}
85
86static void
87miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
88{
89    if (!damageRegister) {
90	damageRegister = 1;
91	DamageRegister (&(pScreen->GetScreenPixmap(pScreen)->drawable),
92			pScreenPriv->pDamage);
93    }
94}
95
96static void
97miSpriteIsUp(miCursorInfoPtr pDevCursor)
98{
99    pDevCursor->isUp = TRUE;
100}
101
102static void
103miSpriteIsDown(miCursorInfoPtr pDevCursor)
104{
105    pDevCursor->isUp = FALSE;
106}
107
108/*
109 * screen wrappers
110 */
111
112static int miSpriteScreenKeyIndex;
113static DevPrivateKey miSpriteScreenKey = &miSpriteScreenKeyIndex;
114static int mmiSpriteDevPrivatesKeyIndex;
115static DevPrivateKey miSpriteDevPrivatesKey = &mmiSpriteDevPrivatesKeyIndex;
116
117static Bool	    miSpriteCloseScreen(int i, ScreenPtr pScreen);
118static void	    miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy,
119				     int w, int h, unsigned int format,
120				     unsigned long planemask, char *pdstLine);
121static void	    miSpriteGetSpans(DrawablePtr pDrawable, int wMax,
122				     DDXPointPtr ppt, int *pwidth, int nspans,
123				     char *pdstStart);
124static void	    miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y,
125					   int width, int height);
126static void	    miSpriteCopyWindow (WindowPtr pWindow,
127					DDXPointRec ptOldOrg,
128					RegionPtr prgnSrc);
129static void	    miSpriteBlockHandler(int i, pointer blockData,
130					 pointer pTimeout,
131					 pointer pReadMask);
132static void	    miSpriteInstallColormap(ColormapPtr pMap);
133static void	    miSpriteStoreColors(ColormapPtr pMap, int ndef,
134					xColorItem *pdef);
135
136static void	    miSpriteComputeSaved(DeviceIntPtr pDev,
137                                         ScreenPtr pScreen);
138
139static Bool         miSpriteDeviceCursorInitialize(DeviceIntPtr pDev,
140                                                   ScreenPtr pScreen);
141static void         miSpriteDeviceCursorCleanup(DeviceIntPtr pDev,
142                                                ScreenPtr pScreen);
143
144#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \
145   ((miSpriteScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, \
146					miSpriteScreenKey))->field)
147#define SCREEN_EPILOGUE(pScreen, field)\
148    ((pScreen)->field = miSprite##field)
149
150/*
151 * pointer-sprite method table
152 */
153
154static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
155                                  CursorPtr pCursor);
156static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
157                                    CursorPtr pCursor);
158static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
159                              CursorPtr pCursor, int x, int y);
160static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
161                               int x, int y);
162
163_X_EXPORT miPointerSpriteFuncRec miSpritePointerFuncs = {
164    miSpriteRealizeCursor,
165    miSpriteUnrealizeCursor,
166    miSpriteSetCursor,
167    miSpriteMoveCursor,
168    miSpriteDeviceCursorInitialize,
169    miSpriteDeviceCursorCleanup,
170};
171
172/*
173 * other misc functions
174 */
175
176static void miSpriteRemoveCursor(DeviceIntPtr pDev,
177                                 ScreenPtr pScreen);
178static void miSpriteSaveUnderCursor(DeviceIntPtr pDev,
179                                 ScreenPtr pScreen);
180static void miSpriteRestoreCursor(DeviceIntPtr pDev,
181                                 ScreenPtr pScreen);
182
183static void
184miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure)
185{
186    ScreenPtr		    pScreen = closure;
187    miSpriteScreenPtr	    pScreenPriv;
188    miCursorInfoPtr         pCursorInfo;
189    DeviceIntPtr            pDev;
190
191    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
192						      miSpriteScreenKey);
193
194    for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
195    {
196        if (DevHasCursor(pDev))
197        {
198            pCursorInfo = MISPRITE(pDev);
199
200            if (pCursorInfo->isUp &&
201                pCursorInfo->pScreen == pScreen &&
202                RECT_IN_REGION (pScreen, pRegion, &pCursorInfo->saved)
203                         != rgnOUT)
204            {
205                SPRITE_DEBUG(("Damage remove\n"));
206                miSpriteRemoveCursor (pDev, pScreen);
207            }
208        }
209    }
210}
211
212/*
213 * miSpriteInitialize -- called from device-dependent screen
214 * initialization proc after all of the function pointers have
215 * been stored in the screen structure.
216 */
217
218Bool
219miSpriteInitialize (ScreenPtr               pScreen,
220                    miSpriteCursorFuncPtr   cursorFuncs,
221                    miPointerScreenFuncPtr  screenFuncs)
222{
223    miSpriteScreenPtr	pScreenPriv;
224    VisualPtr		pVisual;
225
226    if (!DamageSetup (pScreen))
227	return FALSE;
228
229    pScreenPriv = (miSpriteScreenPtr) xalloc (sizeof (miSpriteScreenRec));
230    if (!pScreenPriv)
231	return FALSE;
232
233    pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage,
234					 (DamageDestroyFunc) 0,
235					 DamageReportRawRegion,
236					 TRUE,
237					 pScreen,
238					 (void *) pScreen);
239
240    if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE))
241    {
242	xfree ((pointer) pScreenPriv);
243	return FALSE;
244    }
245    for (pVisual = pScreen->visuals;
246	 pVisual->vid != pScreen->rootVisual;
247	 pVisual++)
248	;
249    pScreenPriv->pVisual = pVisual;
250    pScreenPriv->CloseScreen = pScreen->CloseScreen;
251    pScreenPriv->GetImage = pScreen->GetImage;
252    pScreenPriv->GetSpans = pScreen->GetSpans;
253    pScreenPriv->SourceValidate = pScreen->SourceValidate;
254
255    pScreenPriv->CopyWindow = pScreen->CopyWindow;
256
257    pScreenPriv->InstallColormap = pScreen->InstallColormap;
258    pScreenPriv->StoreColors = pScreen->StoreColors;
259
260    pScreenPriv->BlockHandler = pScreen->BlockHandler;
261
262    pScreenPriv->DeviceCursorInitialize = pScreen->DeviceCursorInitialize;
263    pScreenPriv->DeviceCursorCleanup = pScreen->DeviceCursorCleanup;
264
265    pScreenPriv->pInstalledMap = NULL;
266    pScreenPriv->pColormap = NULL;
267    pScreenPriv->funcs = cursorFuncs;
268    pScreenPriv->colors[SOURCE_COLOR].red = 0;
269    pScreenPriv->colors[SOURCE_COLOR].green = 0;
270    pScreenPriv->colors[SOURCE_COLOR].blue = 0;
271    pScreenPriv->colors[MASK_COLOR].red = 0;
272    pScreenPriv->colors[MASK_COLOR].green = 0;
273    pScreenPriv->colors[MASK_COLOR].blue = 0;
274    dixSetPrivate(&pScreen->devPrivates, miSpriteScreenKey, pScreenPriv);
275
276    pScreen->CloseScreen = miSpriteCloseScreen;
277    pScreen->GetImage = miSpriteGetImage;
278    pScreen->GetSpans = miSpriteGetSpans;
279    pScreen->SourceValidate = miSpriteSourceValidate;
280
281    pScreen->CopyWindow = miSpriteCopyWindow;
282    pScreen->InstallColormap = miSpriteInstallColormap;
283    pScreen->StoreColors = miSpriteStoreColors;
284
285    pScreen->BlockHandler = miSpriteBlockHandler;
286
287    damageRegister = 0;
288
289    return TRUE;
290}
291
292/*
293 * Screen wrappers
294 */
295
296/*
297 * CloseScreen wrapper -- unwrap everything, free the private data
298 * and call the wrapped function
299 */
300
301static Bool
302miSpriteCloseScreen (int i, ScreenPtr pScreen)
303{
304    miSpriteScreenPtr   pScreenPriv;
305
306    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
307						      miSpriteScreenKey);
308    pScreen->CloseScreen = pScreenPriv->CloseScreen;
309    pScreen->GetImage = pScreenPriv->GetImage;
310    pScreen->GetSpans = pScreenPriv->GetSpans;
311    pScreen->SourceValidate = pScreenPriv->SourceValidate;
312    pScreen->BlockHandler = pScreenPriv->BlockHandler;
313    pScreen->InstallColormap = pScreenPriv->InstallColormap;
314    pScreen->StoreColors = pScreenPriv->StoreColors;
315
316    DamageDestroy (pScreenPriv->pDamage);
317
318    xfree ((pointer) pScreenPriv);
319
320    return (*pScreen->CloseScreen) (i, pScreen);
321}
322
323static void
324miSpriteGetImage (DrawablePtr pDrawable, int sx, int sy, int w, int h,
325                  unsigned int format, unsigned long planemask,
326                  char *pdstLine)
327{
328    ScreenPtr	    pScreen = pDrawable->pScreen;
329    miSpriteScreenPtr    pScreenPriv;
330    DeviceIntPtr    pDev = inputInfo.pointer;
331    miCursorInfoPtr pCursorInfo;
332
333    SCREEN_PROLOGUE (pScreen, GetImage);
334
335    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
336						      miSpriteScreenKey);
337    for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
338    {
339        if (DevHasCursor(pDev))
340        {
341             pCursorInfo = MISPRITE(pDev);
342             if (pDrawable->type == DRAWABLE_WINDOW &&
343                     pCursorInfo->isUp &&
344                     pCursorInfo->pScreen == pScreen &&
345                     ORG_OVERLAP(&pCursorInfo->saved,pDrawable->x,pDrawable->y,
346                         sx, sy, w, h))
347             {
348                 SPRITE_DEBUG (("GetImage remove\n"));
349                 miSpriteRemoveCursor (pDev, pScreen);
350             }
351        }
352    }
353
354    (*pScreen->GetImage) (pDrawable, sx, sy, w, h,
355			  format, planemask, pdstLine);
356
357    SCREEN_EPILOGUE (pScreen, GetImage);
358}
359
360static void
361miSpriteGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt,
362                  int *pwidth, int nspans, char *pdstStart)
363{
364    ScreenPtr		    pScreen = pDrawable->pScreen;
365    miSpriteScreenPtr	    pScreenPriv;
366    DeviceIntPtr            pDev = inputInfo.pointer;
367    miCursorInfoPtr         pCursorInfo;
368
369    SCREEN_PROLOGUE (pScreen, GetSpans);
370
371    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
372						      miSpriteScreenKey);
373
374    for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
375    {
376        if (DevHasCursor(pDev))
377        {
378            pCursorInfo = MISPRITE(pDev);
379
380            if (pDrawable->type == DRAWABLE_WINDOW &&
381                    pCursorInfo->isUp &&
382                    pCursorInfo->pScreen == pScreen)
383            {
384                DDXPointPtr    pts;
385                int    	       *widths;
386                int    	       nPts;
387                int    	       xorg,
388                               yorg;
389
390                xorg = pDrawable->x;
391                yorg = pDrawable->y;
392
393                for (pts = ppt, widths = pwidth, nPts = nspans;
394                        nPts--;
395                        pts++, widths++)
396                {
397                    if (SPN_OVERLAP(&pCursorInfo->saved,pts->y+yorg,
398                                pts->x+xorg,*widths))
399                    {
400                        SPRITE_DEBUG (("GetSpans remove\n"));
401                        miSpriteRemoveCursor (pDev, pScreen);
402                        break;
403                    }
404                }
405            }
406        }
407    }
408
409    (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
410
411    SCREEN_EPILOGUE (pScreen, GetSpans);
412}
413
414static void
415miSpriteSourceValidate (DrawablePtr pDrawable, int x, int y, int width,
416                        int height)
417{
418    ScreenPtr		    pScreen = pDrawable->pScreen;
419    miSpriteScreenPtr	    pScreenPriv;
420    DeviceIntPtr            pDev = inputInfo.pointer;
421    miCursorInfoPtr         pCursorInfo;
422
423    SCREEN_PROLOGUE (pScreen, SourceValidate);
424
425    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
426						      miSpriteScreenKey);
427
428    for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
429    {
430        if (DevHasCursor(pDev))
431        {
432            pCursorInfo = MISPRITE(pDev);
433            if (pDrawable->type == DRAWABLE_WINDOW && pCursorInfo->isUp &&
434                    pCursorInfo->pScreen == pScreen &&
435                    ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y,
436                        x, y, width, height))
437            {
438                SPRITE_DEBUG (("SourceValidate remove\n"));
439                miSpriteRemoveCursor (pDev, pScreen);
440            }
441        }
442    }
443
444    if (pScreen->SourceValidate)
445	(*pScreen->SourceValidate) (pDrawable, x, y, width, height);
446
447    SCREEN_EPILOGUE (pScreen, SourceValidate);
448}
449
450static void
451miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
452{
453    ScreenPtr	pScreen = pWindow->drawable.pScreen;
454    miSpriteScreenPtr	    pScreenPriv;
455    DeviceIntPtr            pDev = inputInfo.pointer;
456    miCursorInfoPtr         pCursorInfo;
457
458    SCREEN_PROLOGUE (pScreen, CopyWindow);
459
460    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
461						      miSpriteScreenKey);
462
463    for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
464    {
465        if (DevHasCursor(pDev))
466        {
467            pCursorInfo = MISPRITE(pDev);
468            /*
469             * Damage will take care of destination check
470             */
471            if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
472                    RECT_IN_REGION (pScreen, prgnSrc, &pCursorInfo->saved) != rgnOUT)
473            {
474                SPRITE_DEBUG (("CopyWindow remove\n"));
475                miSpriteRemoveCursor (pDev, pScreen);
476            }
477        }
478    }
479
480    (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
481    SCREEN_EPILOGUE (pScreen, CopyWindow);
482}
483
484static void
485miSpriteBlockHandler (int i, pointer blockData, pointer pTimeout,
486                      pointer pReadmask)
487{
488    ScreenPtr		pScreen = screenInfo.screens[i];
489    miSpriteScreenPtr	pPriv;
490    DeviceIntPtr            pDev = inputInfo.pointer;
491    miCursorInfoPtr         pCursorInfo;
492
493    pPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
494						miSpriteScreenKey);
495    SCREEN_PROLOGUE(pScreen, BlockHandler);
496
497    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
498
499    SCREEN_EPILOGUE(pScreen, BlockHandler);
500
501    for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
502    {
503        if (DevHasCursor(pDev))
504        {
505            pCursorInfo = MISPRITE(pDev);
506            if (pCursorInfo && !pCursorInfo->isUp
507                    && pCursorInfo->pScreen == pScreen
508                    && pCursorInfo->shouldBeUp)
509            {
510                SPRITE_DEBUG (("BlockHandler restore\n"));
511                miSpriteSaveUnderCursor (pDev, pScreen);
512            }
513        }
514    }
515    for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
516    {
517        if (DevHasCursor(pDev))
518        {
519            pCursorInfo = MISPRITE(pDev);
520            if (pCursorInfo && !pCursorInfo->isUp &&
521                    pCursorInfo->pScreen == pScreen &&
522                    pCursorInfo->shouldBeUp)
523            {
524                SPRITE_DEBUG (("BlockHandler restore\n"));
525                miSpriteRestoreCursor (pDev, pScreen);
526            }
527        }
528    }
529}
530
531static void
532miSpriteInstallColormap (ColormapPtr pMap)
533{
534    ScreenPtr		pScreen = pMap->pScreen;
535    miSpriteScreenPtr	pPriv;
536
537    pPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
538						miSpriteScreenKey);
539    SCREEN_PROLOGUE(pScreen, InstallColormap);
540
541    (*pScreen->InstallColormap) (pMap);
542
543    SCREEN_EPILOGUE(pScreen, InstallColormap);
544
545    /* InstallColormap can be called before devices are initialized. */
546    pPriv->pInstalledMap = pMap;
547    if (pPriv->pColormap != pMap)
548    {
549        DeviceIntPtr pDev;
550        miCursorInfoPtr     pCursorInfo;
551        for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
552        {
553            if (DevHasCursor(pDev))
554            {
555                pCursorInfo = MISPRITE(pDev);
556                pCursorInfo->checkPixels = TRUE;
557                if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
558                    miSpriteRemoveCursor(pDev, pScreen);
559            }
560        }
561
562    }
563}
564
565static void
566miSpriteStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef)
567{
568    ScreenPtr		pScreen = pMap->pScreen;
569    miSpriteScreenPtr	pPriv;
570    int			i;
571    int			updated;
572    VisualPtr		pVisual;
573    DeviceIntPtr        pDev = inputInfo.pointer;
574    miCursorInfoPtr     pCursorInfo;
575
576    pPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
577						miSpriteScreenKey);
578    SCREEN_PROLOGUE(pScreen, StoreColors);
579
580    (*pScreen->StoreColors) (pMap, ndef, pdef);
581
582    SCREEN_EPILOGUE(pScreen, StoreColors);
583
584    if (pPriv->pColormap == pMap)
585    {
586        updated = 0;
587        pVisual = pMap->pVisual;
588        if (pVisual->class == DirectColor)
589        {
590            /* Direct color - match on any of the subfields */
591
592#define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask)))
593
594#define UpdateDAC(dev, plane,dac,mask) {\
595    if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\
596	dev->colors[plane].dac = pdef[i].dac; \
597	updated = 1; \
598    } \
599}
600
601#define CheckDirect(dev, plane) \
602	    UpdateDAC(dev, plane,red,redMask) \
603	    UpdateDAC(dev, plane,green,greenMask) \
604	    UpdateDAC(dev, plane,blue,blueMask)
605
606            for (i = 0; i < ndef; i++)
607            {
608                CheckDirect (pPriv, SOURCE_COLOR)
609                CheckDirect (pPriv, MASK_COLOR)
610            }
611        }
612        else
613        {
614            /* PseudoColor/GrayScale - match on exact pixel */
615            for (i = 0; i < ndef; i++)
616            {
617                if (pdef[i].pixel ==
618                        pPriv->colors[SOURCE_COLOR].pixel)
619                {
620                    pPriv->colors[SOURCE_COLOR] = pdef[i];
621                    if (++updated == 2)
622                        break;
623                }
624                if (pdef[i].pixel ==
625                        pPriv->colors[MASK_COLOR].pixel)
626                {
627                    pPriv->colors[MASK_COLOR] = pdef[i];
628                    if (++updated == 2)
629                        break;
630                }
631            }
632        }
633        if (updated)
634        {
635            for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
636            {
637                if (DevHasCursor(pDev))
638                {
639                    pCursorInfo = MISPRITE(pDev);
640                    pCursorInfo->checkPixels = TRUE;
641                    if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
642                        miSpriteRemoveCursor (pDev, pScreen);
643                }
644            }
645        }
646    }
647}
648
649static void
650miSpriteFindColors (miCursorInfoPtr pDevCursor, ScreenPtr pScreen)
651{
652    miSpriteScreenPtr   pScreenPriv = (miSpriteScreenPtr)
653	dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey);
654    CursorPtr		pCursor;
655    xColorItem		*sourceColor, *maskColor;
656
657    pCursor = pDevCursor->pCursor;
658    sourceColor = &pScreenPriv->colors[SOURCE_COLOR];
659    maskColor = &pScreenPriv->colors[MASK_COLOR];
660    if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap ||
661	!(pCursor->foreRed == sourceColor->red &&
662	  pCursor->foreGreen == sourceColor->green &&
663          pCursor->foreBlue == sourceColor->blue &&
664	  pCursor->backRed == maskColor->red &&
665	  pCursor->backGreen == maskColor->green &&
666	  pCursor->backBlue == maskColor->blue))
667    {
668	pScreenPriv->pColormap = pScreenPriv->pInstalledMap;
669	sourceColor->red = pCursor->foreRed;
670	sourceColor->green = pCursor->foreGreen;
671	sourceColor->blue = pCursor->foreBlue;
672	FakeAllocColor (pScreenPriv->pColormap, sourceColor);
673	maskColor->red = pCursor->backRed;
674	maskColor->green = pCursor->backGreen;
675	maskColor->blue = pCursor->backBlue;
676	FakeAllocColor (pScreenPriv->pColormap, maskColor);
677	/* "free" the pixels right away, don't let this confuse you */
678	FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel);
679	FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel);
680    }
681
682    pDevCursor->checkPixels = FALSE;
683
684}
685
686/*
687 * miPointer interface routines
688 */
689
690#define SPRITE_PAD  8
691
692static Bool
693miSpriteRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
694{
695    miSpriteScreenPtr	pScreenPriv;
696    miCursorInfoPtr pCursorInfo;
697
698    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
699						      miSpriteScreenKey);
700    if (!pDev->isMaster && !pDev->u.master)
701    {
702        ErrorF("[mi] miSpriteRealizeCursor called for floating device.\n");
703        return FALSE;
704    }
705    pCursorInfo = MISPRITE(pDev);
706
707    if (pCursor == pCursorInfo->pCursor)
708	pCursorInfo->checkPixels = TRUE;
709
710    return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor);
711}
712
713static Bool
714miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
715{
716    miSpriteScreenPtr	pScreenPriv;
717
718    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
719						      miSpriteScreenKey);
720    return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor);
721}
722
723static void
724miSpriteSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen,
725                   CursorPtr pCursor, int x, int y)
726{
727    miSpriteScreenPtr	pScreenPriv;
728
729    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
730						      miSpriteScreenKey);
731    miCursorInfoPtr pPointer;
732
733    if (!pDev->isMaster && !pDev->u.master)
734    {
735        ErrorF("[mi] miSpriteSetCursor called for floating device.\n");
736        return;
737    }
738    pPointer = MISPRITE(pDev);
739
740    if (!pCursor)
741    {
742    	pPointer->shouldBeUp = FALSE;
743    	if (pPointer->isUp)
744	    miSpriteRemoveCursor (pDev, pScreen);
745	pPointer->pCursor = 0;
746	return;
747    }
748    pPointer->shouldBeUp = TRUE;
749    if (pPointer->x == x &&
750	pPointer->y == y &&
751	pPointer->pCursor == pCursor &&
752	!pPointer->checkPixels)
753    {
754	return;
755    }
756    pPointer->x = x;
757    pPointer->y = y;
758    pPointer->pCacheWin = NullWindow;
759    if (pPointer->checkPixels || pPointer->pCursor != pCursor)
760    {
761	pPointer->pCursor = pCursor;
762	miSpriteFindColors (pPointer, pScreen);
763    }
764    if (pPointer->isUp) {
765#if 0
766        /* FIXME: Disabled for MPX, should be rewritten */
767	int	sx, sy;
768	/*
769	 * check to see if the old saved region
770	 * encloses the new sprite, in which case we use
771	 * the flicker-free MoveCursor primitive.
772	 */
773	sx = pointer->x - (int)pCursor->bits->xhot;
774	sy = pointer->y - (int)pCursor->bits->yhot;
775	if (sx + (int) pCursor->bits->width >= pointer->saved.x1 &&
776	    sx < pointer->saved.x2 &&
777	    sy + (int) pCursor->bits->height >= pointer->saved.y1 &&
778	    sy < pointer->saved.y2 &&
779	    (int) pCursor->bits->width + (2 * SPRITE_PAD) ==
780		pointer->saved.x2 - pointer->saved.x1 &&
781	    (int) pCursor->bits->height + (2 * SPRITE_PAD) ==
782		pointer->saved.y2 - pointer->saved.y1
783	    )
784	{
785	    DamageDrawInternal (pScreen, TRUE);
786	    miSpriteIsDown(pCursorInfo);
787	    if (!(sx >= pointer->saved.x1 &&
788                  sx + (int)pCursor->bits->width < pointer->saved.x2
789                  && sy >= pointer->saved.y1 &&
790                  sy + (int)pCursor->bits->height <
791                                pointer->saved.y2))
792            {
793		int oldx1, oldy1, dx, dy;
794
795		oldx1 = pointer->saved.x1;
796		oldy1 = pointer->saved.y1;
797		dx = oldx1 - (sx - SPRITE_PAD);
798		dy = oldy1 - (sy - SPRITE_PAD);
799		pointer->saved.x1 -= dx;
800		pointer->saved.y1 -= dy;
801		pointer->saved.x2 -= dx;
802		pointer->saved.y2 -= dy;
803		(void) (*pScreenPriv->funcs->ChangeSave) (pScreen,
804				pointer->saved.x1,
805 				pointer->saved.y1,
806                                pointer->saved.x2 -
807                                pointer->saved.x1,
808                                pointer->saved.y2 -
809                                pointer->saved.y1,
810				dx, dy);
811	    }
812	    (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor,
813				  pointer->saved.x1,
814 				  pointer->saved.y1,
815                                  pointer->saved.x2 -
816                                  pointer->saved.x1,
817                                  pointer->saved.y2 -
818                                  pointer->saved.y1,
819				  sx - pointer->saved.x1,
820				  sy - pointer->saved.y1,
821				  pointer->colors[SOURCE_COLOR].pixel,
822				  pointer->colors[MASK_COLOR].pixel);
823	    miSpriteIsUp(pCursorInfo);
824	    DamageDrawInternal (pScreen, FALSE);
825	}
826	else
827#endif
828	{
829	    SPRITE_DEBUG (("SetCursor remove %d\n", pDev->id));
830	    miSpriteRemoveCursor (pDev, pScreen);
831	}
832    }
833
834    if (!pPointer->isUp && pPointer->pCursor)
835    {
836	SPRITE_DEBUG (("SetCursor restore %d\n", pDev->id));
837        miSpriteSaveUnderCursor(pDev, pScreen);
838	miSpriteRestoreCursor (pDev, pScreen);
839    }
840
841}
842
843static void
844miSpriteMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
845{
846    miSpriteScreenPtr	pScreenPriv;
847    CursorPtr pCursor;
848
849    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
850						      miSpriteScreenKey);
851    if (!pDev->isMaster && !pDev->u.master)
852    {
853        ErrorF("[mi] miSpriteMoveCursor called for floating device.\n");
854        return;
855    }
856    pCursor = MISPRITE(pDev)->pCursor;
857
858    miSpriteSetCursor (pDev, pScreen, pCursor, x, y);
859}
860
861
862static Bool
863miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
864{
865    miSpriteScreenPtr pScreenPriv;
866    miCursorInfoPtr pCursorInfo;
867    int ret = FALSE;
868
869    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
870						      miSpriteScreenKey);
871
872    pCursorInfo = xalloc(sizeof(miCursorInfoRec));
873    if (!pCursorInfo)
874        return FALSE;
875
876    pCursorInfo->pCursor = NULL;
877    pCursorInfo->x = 0;
878    pCursorInfo->y = 0;
879    pCursorInfo->isUp = FALSE;
880    pCursorInfo->shouldBeUp = FALSE;
881    pCursorInfo->pCacheWin = NullWindow;
882    pCursorInfo->isInCacheWin = FALSE;
883    pCursorInfo->checkPixels = TRUE;
884    pCursorInfo->pScreen = FALSE;
885
886    ret = (*pScreenPriv->funcs->DeviceCursorInitialize)(pDev, pScreen);
887    if (!ret)
888    {
889        xfree(pCursorInfo);
890        pCursorInfo = NULL;
891    }
892    dixSetPrivate(&pDev->devPrivates, miSpriteDevPrivatesKey, pCursorInfo);
893    return ret;
894}
895
896static void
897miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
898{
899    if (DevHasCursor(pDev))
900    {
901        miSpriteScreenPtr pScreenPriv;
902        pScreenPriv = (miSpriteScreenPtr)
903                dixLookupPrivate(&pScreen->devPrivates, miSpriteScreenKey);
904
905        (*pScreenPriv->funcs->DeviceCursorCleanup)(pDev, pScreen);
906    }
907}
908
909/*
910 * undraw/draw cursor
911 */
912
913static void
914miSpriteRemoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen)
915{
916    miSpriteScreenPtr   pScreenPriv;
917    miCursorInfoPtr     pCursorInfo;
918
919
920    if (!pDev->isMaster && !pDev->u.master)
921    {
922        ErrorF("[mi] miSpriteRemoveCursor called for floating device.\n");
923        return;
924    }
925    DamageDrawInternal (pScreen, TRUE);
926    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
927						      miSpriteScreenKey);
928    pCursorInfo = MISPRITE(pDev);
929
930    miSpriteIsDown(pCursorInfo);
931    pCursorInfo->pCacheWin = NullWindow;
932    miSpriteDisableDamage(pScreen, pScreenPriv);
933    if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pDev,
934                                         pScreen,
935					 pCursorInfo->saved.x1,
936                                         pCursorInfo->saved.y1,
937                                         pCursorInfo->saved.x2 -
938                                         pCursorInfo->saved.x1,
939                                         pCursorInfo->saved.y2 -
940                                         pCursorInfo->saved.y1))
941    {
942	miSpriteIsUp(pCursorInfo);
943    }
944    miSpriteEnableDamage(pScreen, pScreenPriv);
945    DamageDrawInternal (pScreen, FALSE);
946}
947
948/*
949 * Called from the block handler, saves area under cursor
950 * before waiting for something to do.
951 */
952
953static void
954miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
955{
956    miSpriteScreenPtr   pScreenPriv;
957    int			x, y;
958    CursorPtr		pCursor;
959    miCursorInfoPtr     pCursorInfo;
960
961    if (!pDev->isMaster && !pDev->u.master)
962    {
963        ErrorF("[mi] miSpriteSaveUnderCursor called for floating device.\n");
964        return;
965    }
966    DamageDrawInternal (pScreen, TRUE);
967    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
968						      miSpriteScreenKey);
969    pCursorInfo = MISPRITE(pDev);
970
971    miSpriteComputeSaved (pDev, pScreen);
972    pCursor = pCursorInfo->pCursor;
973
974    x = pCursorInfo->x - (int)pCursor->bits->xhot;
975    y = pCursorInfo->y - (int)pCursor->bits->yhot;
976    miSpriteDisableDamage(pScreen, pScreenPriv);
977
978    (*pScreenPriv->funcs->SaveUnderCursor) (pDev,
979                                      pScreen,
980				      pCursorInfo->saved.x1,
981				      pCursorInfo->saved.y1,
982                                      pCursorInfo->saved.x2 -
983                                      pCursorInfo->saved.x1,
984                                      pCursorInfo->saved.y2 -
985                                      pCursorInfo->saved.y1);
986    SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id));
987    miSpriteEnableDamage(pScreen, pScreenPriv);
988    DamageDrawInternal (pScreen, FALSE);
989}
990
991
992/*
993 * Called from the block handler, restores the cursor
994 * before waiting for something to do.
995 */
996
997static void
998miSpriteRestoreCursor (DeviceIntPtr pDev, ScreenPtr pScreen)
999{
1000    miSpriteScreenPtr   pScreenPriv;
1001    int			x, y;
1002    CursorPtr		pCursor;
1003    miCursorInfoPtr     pCursorInfo;
1004
1005    if (!pDev->isMaster && !pDev->u.master)
1006    {
1007        ErrorF("[mi] miSpriteRestoreCursor called for floating device.\n");
1008        return;
1009    }
1010
1011    DamageDrawInternal (pScreen, TRUE);
1012    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
1013						      miSpriteScreenKey);
1014    pCursorInfo = MISPRITE(pDev);
1015
1016    miSpriteComputeSaved (pDev, pScreen);
1017    pCursor = pCursorInfo->pCursor;
1018
1019    x = pCursorInfo->x - (int)pCursor->bits->xhot;
1020    y = pCursorInfo->y - (int)pCursor->bits->yhot;
1021    miSpriteDisableDamage(pScreen, pScreenPriv);
1022    SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id));
1023    if (pCursorInfo->checkPixels)
1024        miSpriteFindColors (pCursorInfo, pScreen);
1025    if ((*pScreenPriv->funcs->PutUpCursor) (pDev, pScreen,
1026                pCursor, x, y,
1027                pScreenPriv->colors[SOURCE_COLOR].pixel,
1028                pScreenPriv->colors[MASK_COLOR].pixel))
1029    {
1030        miSpriteIsUp(pCursorInfo);
1031        pCursorInfo->pScreen = pScreen;
1032    }
1033    miSpriteEnableDamage(pScreen, pScreenPriv);
1034    DamageDrawInternal (pScreen, FALSE);
1035}
1036
1037/*
1038 * compute the desired area of the screen to save
1039 */
1040
1041static void
1042miSpriteComputeSaved (DeviceIntPtr pDev, ScreenPtr pScreen)
1043{
1044    miSpriteScreenPtr   pScreenPriv;
1045    int		    x, y, w, h;
1046    int		    wpad, hpad;
1047    CursorPtr	    pCursor;
1048    miCursorInfoPtr pCursorInfo;
1049
1050    if (!pDev->isMaster && !pDev->u.master)
1051    {
1052        ErrorF("[mi] miSpriteComputeSaved called for floating device.\n");
1053        return;
1054    }
1055    pScreenPriv = (miSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
1056						      miSpriteScreenKey);
1057    pCursorInfo = MISPRITE(pDev);
1058
1059    pCursor = pCursorInfo->pCursor;
1060    x = pCursorInfo->x - (int)pCursor->bits->xhot;
1061    y = pCursorInfo->y - (int)pCursor->bits->yhot;
1062    w = pCursor->bits->width;
1063    h = pCursor->bits->height;
1064    wpad = SPRITE_PAD;
1065    hpad = SPRITE_PAD;
1066    pCursorInfo->saved.x1 = x - wpad;
1067    pCursorInfo->saved.y1 = y - hpad;
1068    pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2;
1069    pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2;
1070}
1071
1072