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