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