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