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