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