misprite.c revision 05b261ec
1/*
2 * misprite.c
3 *
4 * machine independent software sprite routines
5 */
6
7
8/*
9
10Copyright 1989, 1998  The Open Group
11
12Permission to use, copy, modify, distribute, and sell this software and its
13documentation for any purpose is hereby granted without fee, provided that
14the above copyright notice appear in all copies and that both that
15copyright notice and this permission notice appear in supporting
16documentation.
17
18The above copyright notice and this permission notice shall be included in
19all copies or substantial portions of the Software.
20
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
25AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28Except as contained in this notice, the name of The Open Group shall not be
29used in advertising or otherwise to promote the sale, use or other dealings
30in this Software without prior written authorization from The Open Group.
31*/
32
33#ifdef HAVE_DIX_CONFIG_H
34#include <dix-config.h>
35#endif
36
37# include   <X11/X.h>
38# include   <X11/Xproto.h>
39# include   "misc.h"
40# include   "pixmapstr.h"
41# include   "input.h"
42# include   "mi.h"
43# include   "cursorstr.h"
44# include   <X11/fonts/font.h>
45# include   "scrnintstr.h"
46# include   "colormapst.h"
47# include   "windowstr.h"
48# include   "gcstruct.h"
49# include   "mipointer.h"
50# include   "mispritest.h"
51# include   "dixfontstr.h"
52# include   <X11/fonts/fontstruct.h>
53
54#ifdef RENDER
55# include   "mipict.h"
56#endif
57# include   "damage.h"
58
59#define SPRITE_DEBUG_ENABLE 0
60#if SPRITE_DEBUG_ENABLE
61#define SPRITE_DEBUG(x)	ErrorF x
62#else
63#define SPRITE_DEBUG(x)
64#endif
65
66/*
67 * screen wrappers
68 */
69
70static int  miSpriteScreenIndex;
71static unsigned long miSpriteGeneration = 0;
72
73static Bool	    miSpriteCloseScreen(int i, ScreenPtr pScreen);
74static void	    miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy,
75				     int w, int h, unsigned int format,
76				     unsigned long planemask, char *pdstLine);
77static void	    miSpriteGetSpans(DrawablePtr pDrawable, int wMax,
78				     DDXPointPtr ppt, int *pwidth, int nspans,
79				     char *pdstStart);
80static void	    miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y,
81					   int width, int height);
82static void	    miSpriteCopyWindow (WindowPtr pWindow,
83					DDXPointRec ptOldOrg,
84					RegionPtr prgnSrc);
85static void	    miSpriteBlockHandler(int i, pointer blockData,
86					 pointer pTimeout,
87					 pointer pReadMask);
88static void	    miSpriteInstallColormap(ColormapPtr pMap);
89static void	    miSpriteStoreColors(ColormapPtr pMap, int ndef,
90					xColorItem *pdef);
91
92static void	    miSpriteSaveDoomedAreas(WindowPtr pWin,
93					    RegionPtr pObscured, int dx,
94					    int dy);
95static void	    miSpriteComputeSaved(ScreenPtr pScreen);
96
97#define SCREEN_PROLOGUE(pScreen, field)\
98  ((pScreen)->field = \
99   ((miSpriteScreenPtr) (pScreen)->devPrivates[miSpriteScreenIndex].ptr)->field)
100
101#define SCREEN_EPILOGUE(pScreen, field)\
102    ((pScreen)->field = miSprite##field)
103
104/*
105 * pointer-sprite method table
106 */
107
108static Bool miSpriteRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
109static Bool miSpriteUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
110static void miSpriteSetCursor(ScreenPtr pScreen, CursorPtr pCursor,
111			      int x, int y);
112static void miSpriteMoveCursor(ScreenPtr pScreen, int x, int y);
113
114_X_EXPORT miPointerSpriteFuncRec miSpritePointerFuncs = {
115    miSpriteRealizeCursor,
116    miSpriteUnrealizeCursor,
117    miSpriteSetCursor,
118    miSpriteMoveCursor,
119};
120
121/*
122 * other misc functions
123 */
124
125static void miSpriteRemoveCursor(ScreenPtr pScreen);
126static void miSpriteRestoreCursor(ScreenPtr pScreen);
127
128static void
129miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure)
130{
131    ScreenPtr		    pScreen = closure;
132    miSpriteScreenPtr	    pScreenPriv;
133
134    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
135
136    if (pScreenPriv->isUp &&
137	RECT_IN_REGION (pScreen, pRegion, &pScreenPriv->saved) != rgnOUT)
138    {
139	SPRITE_DEBUG(("Damage remove\n"));
140	miSpriteRemoveCursor (pScreen);
141    }
142}
143
144/*
145 * miSpriteInitialize -- called from device-dependent screen
146 * initialization proc after all of the function pointers have
147 * been stored in the screen structure.
148 */
149
150Bool
151miSpriteInitialize (pScreen, cursorFuncs, screenFuncs)
152    ScreenPtr		    pScreen;
153    miSpriteCursorFuncPtr   cursorFuncs;
154    miPointerScreenFuncPtr  screenFuncs;
155{
156    miSpriteScreenPtr	pScreenPriv;
157    VisualPtr		pVisual;
158
159    if (!DamageSetup (pScreen))
160	return FALSE;
161
162    if (miSpriteGeneration != serverGeneration)
163    {
164	miSpriteScreenIndex = AllocateScreenPrivateIndex ();
165	if (miSpriteScreenIndex < 0)
166	    return FALSE;
167	miSpriteGeneration = serverGeneration;
168    }
169
170    pScreenPriv = (miSpriteScreenPtr) xalloc (sizeof (miSpriteScreenRec));
171    if (!pScreenPriv)
172	return FALSE;
173
174    pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage,
175					 (DamageDestroyFunc) 0,
176					 DamageReportRawRegion,
177					 TRUE,
178					 pScreen,
179					 (void *) pScreen);
180
181    if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE))
182    {
183	xfree ((pointer) pScreenPriv);
184	return FALSE;
185    }
186    for (pVisual = pScreen->visuals;
187	 pVisual->vid != pScreen->rootVisual;
188	 pVisual++)
189	;
190    pScreenPriv->pVisual = pVisual;
191    pScreenPriv->CloseScreen = pScreen->CloseScreen;
192    pScreenPriv->GetImage = pScreen->GetImage;
193    pScreenPriv->GetSpans = pScreen->GetSpans;
194    pScreenPriv->SourceValidate = pScreen->SourceValidate;
195
196    pScreenPriv->CopyWindow = pScreen->CopyWindow;
197
198    pScreenPriv->SaveDoomedAreas = pScreen->SaveDoomedAreas;
199
200    pScreenPriv->InstallColormap = pScreen->InstallColormap;
201    pScreenPriv->StoreColors = pScreen->StoreColors;
202
203    pScreenPriv->BlockHandler = pScreen->BlockHandler;
204
205    pScreenPriv->pCursor = NULL;
206    pScreenPriv->x = 0;
207    pScreenPriv->y = 0;
208    pScreenPriv->isUp = FALSE;
209    pScreenPriv->shouldBeUp = FALSE;
210    pScreenPriv->pCacheWin = NullWindow;
211    pScreenPriv->isInCacheWin = FALSE;
212    pScreenPriv->checkPixels = TRUE;
213    pScreenPriv->pInstalledMap = NULL;
214    pScreenPriv->pColormap = NULL;
215    pScreenPriv->funcs = cursorFuncs;
216    pScreenPriv->colors[SOURCE_COLOR].red = 0;
217    pScreenPriv->colors[SOURCE_COLOR].green = 0;
218    pScreenPriv->colors[SOURCE_COLOR].blue = 0;
219    pScreenPriv->colors[MASK_COLOR].red = 0;
220    pScreenPriv->colors[MASK_COLOR].green = 0;
221    pScreenPriv->colors[MASK_COLOR].blue = 0;
222    pScreen->devPrivates[miSpriteScreenIndex].ptr = (pointer) pScreenPriv;
223
224    pScreen->CloseScreen = miSpriteCloseScreen;
225    pScreen->GetImage = miSpriteGetImage;
226    pScreen->GetSpans = miSpriteGetSpans;
227    pScreen->SourceValidate = miSpriteSourceValidate;
228
229    pScreen->CopyWindow = miSpriteCopyWindow;
230
231    pScreen->SaveDoomedAreas = miSpriteSaveDoomedAreas;
232
233    pScreen->InstallColormap = miSpriteInstallColormap;
234    pScreen->StoreColors = miSpriteStoreColors;
235
236    pScreen->BlockHandler = miSpriteBlockHandler;
237
238    return TRUE;
239}
240
241/*
242 * Screen wrappers
243 */
244
245/*
246 * CloseScreen wrapper -- unwrap everything, free the private data
247 * and call the wrapped function
248 */
249
250static Bool
251miSpriteCloseScreen (i, pScreen)
252    int i;
253    ScreenPtr	pScreen;
254{
255    miSpriteScreenPtr   pScreenPriv;
256
257    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
258
259    pScreen->CloseScreen = pScreenPriv->CloseScreen;
260    pScreen->GetImage = pScreenPriv->GetImage;
261    pScreen->GetSpans = pScreenPriv->GetSpans;
262    pScreen->SourceValidate = pScreenPriv->SourceValidate;
263    pScreen->BlockHandler = pScreenPriv->BlockHandler;
264    pScreen->InstallColormap = pScreenPriv->InstallColormap;
265    pScreen->StoreColors = pScreenPriv->StoreColors;
266
267    pScreen->SaveDoomedAreas = pScreenPriv->SaveDoomedAreas;
268    miSpriteIsUpFALSE (pScreen, pScreenPriv);
269    DamageDestroy (pScreenPriv->pDamage);
270
271    xfree ((pointer) pScreenPriv);
272
273    return (*pScreen->CloseScreen) (i, pScreen);
274}
275
276static void
277miSpriteGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine)
278    DrawablePtr	    pDrawable;
279    int		    sx, sy, w, h;
280    unsigned int    format;
281    unsigned long   planemask;
282    char	    *pdstLine;
283{
284    ScreenPtr	    pScreen = pDrawable->pScreen;
285    miSpriteScreenPtr    pScreenPriv;
286
287    SCREEN_PROLOGUE (pScreen, GetImage);
288
289    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
290
291    if (pDrawable->type == DRAWABLE_WINDOW &&
292        pScreenPriv->isUp &&
293	ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, sx, sy, w, h))
294    {
295	SPRITE_DEBUG (("GetImage remove\n"));
296	miSpriteRemoveCursor (pScreen);
297    }
298
299    (*pScreen->GetImage) (pDrawable, sx, sy, w, h,
300			  format, planemask, pdstLine);
301
302    SCREEN_EPILOGUE (pScreen, GetImage);
303}
304
305static void
306miSpriteGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart)
307    DrawablePtr	pDrawable;
308    int		wMax;
309    DDXPointPtr	ppt;
310    int		*pwidth;
311    int		nspans;
312    char	*pdstStart;
313{
314    ScreenPtr		    pScreen = pDrawable->pScreen;
315    miSpriteScreenPtr	    pScreenPriv;
316
317    SCREEN_PROLOGUE (pScreen, GetSpans);
318
319    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
320
321    if (pDrawable->type == DRAWABLE_WINDOW && pScreenPriv->isUp)
322    {
323	DDXPointPtr    	pts;
324	int    		*widths;
325	int    		nPts;
326	int    		xorg,
327			yorg;
328
329	xorg = pDrawable->x;
330	yorg = pDrawable->y;
331
332	for (pts = ppt, widths = pwidth, nPts = nspans;
333	     nPts--;
334	     pts++, widths++)
335 	{
336	    if (SPN_OVERLAP(&pScreenPriv->saved,pts->y+yorg,
337			     pts->x+xorg,*widths))
338	    {
339		SPRITE_DEBUG (("GetSpans remove\n"));
340		miSpriteRemoveCursor (pScreen);
341		break;
342	    }
343	}
344    }
345
346    (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
347
348    SCREEN_EPILOGUE (pScreen, GetSpans);
349}
350
351static void
352miSpriteSourceValidate (pDrawable, x, y, width, height)
353    DrawablePtr	pDrawable;
354    int		x, y, width, height;
355{
356    ScreenPtr		    pScreen = pDrawable->pScreen;
357    miSpriteScreenPtr	    pScreenPriv;
358
359    SCREEN_PROLOGUE (pScreen, SourceValidate);
360
361    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
362
363    if (pDrawable->type == DRAWABLE_WINDOW && pScreenPriv->isUp &&
364	ORG_OVERLAP(&pScreenPriv->saved, pDrawable->x, pDrawable->y,
365		    x, y, width, height))
366    {
367	SPRITE_DEBUG (("SourceValidate remove\n"));
368	miSpriteRemoveCursor (pScreen);
369    }
370
371    if (pScreen->SourceValidate)
372	(*pScreen->SourceValidate) (pDrawable, x, y, width, height);
373
374    SCREEN_EPILOGUE (pScreen, SourceValidate);
375}
376
377static void
378miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
379{
380    ScreenPtr	pScreen = pWindow->drawable.pScreen;
381    miSpriteScreenPtr	    pScreenPriv;
382
383    SCREEN_PROLOGUE (pScreen, CopyWindow);
384
385    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
386    /*
387     * Damage will take care of destination check
388     */
389    if (pScreenPriv->isUp &&
390	RECT_IN_REGION (pScreen, prgnSrc, &pScreenPriv->saved) != rgnOUT)
391    {
392	SPRITE_DEBUG (("CopyWindow remove\n"));
393	miSpriteRemoveCursor (pScreen);
394    }
395
396    (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
397    SCREEN_EPILOGUE (pScreen, CopyWindow);
398}
399
400static void
401miSpriteBlockHandler (i, blockData, pTimeout, pReadmask)
402    int	i;
403    pointer	blockData;
404    pointer	pTimeout;
405    pointer	pReadmask;
406{
407    ScreenPtr		pScreen = screenInfo.screens[i];
408    miSpriteScreenPtr	pPriv;
409
410    pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
411
412    SCREEN_PROLOGUE(pScreen, BlockHandler);
413
414    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
415
416    SCREEN_EPILOGUE(pScreen, BlockHandler);
417
418    if (!pPriv->isUp && pPriv->shouldBeUp)
419    {
420	SPRITE_DEBUG (("BlockHandler restore\n"));
421	miSpriteRestoreCursor (pScreen);
422    }
423}
424
425static void
426miSpriteInstallColormap (pMap)
427    ColormapPtr	pMap;
428{
429    ScreenPtr		pScreen = pMap->pScreen;
430    miSpriteScreenPtr	pPriv;
431
432    pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
433
434    SCREEN_PROLOGUE(pScreen, InstallColormap);
435
436    (*pScreen->InstallColormap) (pMap);
437
438    SCREEN_EPILOGUE(pScreen, InstallColormap);
439
440    pPriv->pInstalledMap = pMap;
441    if (pPriv->pColormap != pMap)
442    {
443    	pPriv->checkPixels = TRUE;
444	if (pPriv->isUp)
445	    miSpriteRemoveCursor (pScreen);
446    }
447}
448
449static void
450miSpriteStoreColors (pMap, ndef, pdef)
451    ColormapPtr	pMap;
452    int		ndef;
453    xColorItem	*pdef;
454{
455    ScreenPtr		pScreen = pMap->pScreen;
456    miSpriteScreenPtr	pPriv;
457    int			i;
458    int			updated;
459    VisualPtr		pVisual;
460
461    pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
462
463    SCREEN_PROLOGUE(pScreen, StoreColors);
464
465    (*pScreen->StoreColors) (pMap, ndef, pdef);
466
467    SCREEN_EPILOGUE(pScreen, StoreColors);
468
469    if (pPriv->pColormap == pMap)
470    {
471	updated = 0;
472	pVisual = pMap->pVisual;
473	if (pVisual->class == DirectColor)
474	{
475	    /* Direct color - match on any of the subfields */
476
477#define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask)))
478
479#define UpdateDAC(plane,dac,mask) {\
480    if (MaskMatch (pPriv->colors[plane].pixel,pdef[i].pixel,mask)) {\
481	pPriv->colors[plane].dac = pdef[i].dac; \
482	updated = 1; \
483    } \
484}
485
486#define CheckDirect(plane) \
487	    UpdateDAC(plane,red,redMask) \
488	    UpdateDAC(plane,green,greenMask) \
489	    UpdateDAC(plane,blue,blueMask)
490
491	    for (i = 0; i < ndef; i++)
492	    {
493		CheckDirect (SOURCE_COLOR)
494		CheckDirect (MASK_COLOR)
495	    }
496	}
497	else
498	{
499	    /* PseudoColor/GrayScale - match on exact pixel */
500	    for (i = 0; i < ndef; i++)
501	    {
502	    	if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel)
503	    	{
504		    pPriv->colors[SOURCE_COLOR] = pdef[i];
505		    if (++updated == 2)
506		    	break;
507	    	}
508	    	if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel)
509	    	{
510		    pPriv->colors[MASK_COLOR] = pdef[i];
511		    if (++updated == 2)
512		    	break;
513	    	}
514	    }
515	}
516    	if (updated)
517    	{
518	    pPriv->checkPixels = TRUE;
519	    if (pPriv->isUp)
520	    	miSpriteRemoveCursor (pScreen);
521    	}
522    }
523}
524
525static void
526miSpriteFindColors (ScreenPtr pScreen)
527{
528    miSpriteScreenPtr	pScreenPriv = (miSpriteScreenPtr)
529			    pScreen->devPrivates[miSpriteScreenIndex].ptr;
530    CursorPtr		pCursor;
531    xColorItem		*sourceColor, *maskColor;
532
533    pCursor = pScreenPriv->pCursor;
534    sourceColor = &pScreenPriv->colors[SOURCE_COLOR];
535    maskColor = &pScreenPriv->colors[MASK_COLOR];
536    if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap ||
537	!(pCursor->foreRed == sourceColor->red &&
538	  pCursor->foreGreen == sourceColor->green &&
539          pCursor->foreBlue == sourceColor->blue &&
540	  pCursor->backRed == maskColor->red &&
541	  pCursor->backGreen == maskColor->green &&
542	  pCursor->backBlue == maskColor->blue))
543    {
544	pScreenPriv->pColormap = pScreenPriv->pInstalledMap;
545	sourceColor->red = pCursor->foreRed;
546	sourceColor->green = pCursor->foreGreen;
547	sourceColor->blue = pCursor->foreBlue;
548	FakeAllocColor (pScreenPriv->pColormap, sourceColor);
549	maskColor->red = pCursor->backRed;
550	maskColor->green = pCursor->backGreen;
551	maskColor->blue = pCursor->backBlue;
552	FakeAllocColor (pScreenPriv->pColormap, maskColor);
553	/* "free" the pixels right away, don't let this confuse you */
554	FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel);
555	FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel);
556    }
557    pScreenPriv->checkPixels = FALSE;
558}
559
560/*
561 * BackingStore wrappers
562 */
563
564static void
565miSpriteSaveDoomedAreas (pWin, pObscured, dx, dy)
566    WindowPtr	pWin;
567    RegionPtr	pObscured;
568    int		dx, dy;
569{
570    ScreenPtr		pScreen;
571    miSpriteScreenPtr   pScreenPriv;
572    BoxRec		cursorBox;
573
574    pScreen = pWin->drawable.pScreen;
575
576    SCREEN_PROLOGUE (pScreen, SaveDoomedAreas);
577
578    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
579    if (pScreenPriv->isUp)
580    {
581	cursorBox = pScreenPriv->saved;
582
583	if (dx || dy)
584 	{
585	    cursorBox.x1 += dx;
586	    cursorBox.y1 += dy;
587	    cursorBox.x2 += dx;
588	    cursorBox.y2 += dy;
589	}
590	if (RECT_IN_REGION( pScreen, pObscured, &cursorBox) != rgnOUT)
591	    miSpriteRemoveCursor (pScreen);
592    }
593
594    (*pScreen->SaveDoomedAreas) (pWin, pObscured, dx, dy);
595
596    SCREEN_EPILOGUE (pScreen, SaveDoomedAreas);
597}
598
599/*
600 * miPointer interface routines
601 */
602
603#define SPRITE_PAD  8
604
605static Bool
606miSpriteRealizeCursor (pScreen, pCursor)
607    ScreenPtr	pScreen;
608    CursorPtr	pCursor;
609{
610    miSpriteScreenPtr	pScreenPriv;
611
612    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
613    if (pCursor == pScreenPriv->pCursor)
614	pScreenPriv->checkPixels = TRUE;
615    return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor);
616}
617
618static Bool
619miSpriteUnrealizeCursor (pScreen, pCursor)
620    ScreenPtr	pScreen;
621    CursorPtr	pCursor;
622{
623    miSpriteScreenPtr	pScreenPriv;
624
625    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
626    return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor);
627}
628
629static void
630miSpriteSetCursor (pScreen, pCursor, x, y)
631    ScreenPtr	pScreen;
632    CursorPtr	pCursor;
633    int		x;
634    int		y;
635{
636    miSpriteScreenPtr	pScreenPriv;
637
638    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
639    if (!pCursor)
640    {
641    	pScreenPriv->shouldBeUp = FALSE;
642    	if (pScreenPriv->isUp)
643	    miSpriteRemoveCursor (pScreen);
644	pScreenPriv->pCursor = 0;
645	return;
646    }
647    pScreenPriv->shouldBeUp = TRUE;
648    if (pScreenPriv->x == x &&
649	pScreenPriv->y == y &&
650	pScreenPriv->pCursor == pCursor &&
651	!pScreenPriv->checkPixels)
652    {
653	return;
654    }
655    pScreenPriv->x = x;
656    pScreenPriv->y = y;
657    pScreenPriv->pCacheWin = NullWindow;
658    if (pScreenPriv->checkPixels || pScreenPriv->pCursor != pCursor)
659    {
660	pScreenPriv->pCursor = pCursor;
661	miSpriteFindColors (pScreen);
662    }
663    if (pScreenPriv->isUp) {
664	int	sx, sy;
665	/*
666	 * check to see if the old saved region
667	 * encloses the new sprite, in which case we use
668	 * the flicker-free MoveCursor primitive.
669	 */
670	sx = pScreenPriv->x - (int)pCursor->bits->xhot;
671	sy = pScreenPriv->y - (int)pCursor->bits->yhot;
672	if (sx + (int) pCursor->bits->width >= pScreenPriv->saved.x1 &&
673	    sx < pScreenPriv->saved.x2 &&
674	    sy + (int) pCursor->bits->height >= pScreenPriv->saved.y1 &&
675	    sy < pScreenPriv->saved.y2 &&
676	    (int) pCursor->bits->width + (2 * SPRITE_PAD) ==
677		pScreenPriv->saved.x2 - pScreenPriv->saved.x1 &&
678	    (int) pCursor->bits->height + (2 * SPRITE_PAD) ==
679		pScreenPriv->saved.y2 - pScreenPriv->saved.y1
680	    )
681	{
682	    DamageDrawInternal (pScreen, TRUE);
683	    miSpriteIsUpFALSE (pScreen, pScreenPriv);
684	    if (!(sx >= pScreenPriv->saved.x1 &&
685	      	  sx + (int)pCursor->bits->width < pScreenPriv->saved.x2 &&
686	      	  sy >= pScreenPriv->saved.y1 &&
687	      	  sy + (int)pCursor->bits->height < pScreenPriv->saved.y2))
688	    {
689		int oldx1, oldy1, dx, dy;
690
691		oldx1 = pScreenPriv->saved.x1;
692		oldy1 = pScreenPriv->saved.y1;
693		dx = oldx1 - (sx - SPRITE_PAD);
694		dy = oldy1 - (sy - SPRITE_PAD);
695		pScreenPriv->saved.x1 -= dx;
696		pScreenPriv->saved.y1 -= dy;
697		pScreenPriv->saved.x2 -= dx;
698		pScreenPriv->saved.y2 -= dy;
699		(void) (*pScreenPriv->funcs->ChangeSave) (pScreen,
700				pScreenPriv->saved.x1,
701 				pScreenPriv->saved.y1,
702				pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
703				pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
704				dx, dy);
705	    }
706	    (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor,
707				  pScreenPriv->saved.x1,
708 				  pScreenPriv->saved.y1,
709				  pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
710				  pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
711				  sx - pScreenPriv->saved.x1,
712				  sy - pScreenPriv->saved.y1,
713				  pScreenPriv->colors[SOURCE_COLOR].pixel,
714				  pScreenPriv->colors[MASK_COLOR].pixel);
715	    miSpriteIsUpTRUE (pScreen, pScreenPriv);
716	    DamageDrawInternal (pScreen, FALSE);
717	}
718	else
719	{
720	    SPRITE_DEBUG (("SetCursor remove\n"));
721	    miSpriteRemoveCursor (pScreen);
722	}
723    }
724    if (!pScreenPriv->isUp && pScreenPriv->pCursor)
725    {
726	SPRITE_DEBUG (("SetCursor restore\n"));
727	miSpriteRestoreCursor (pScreen);
728    }
729}
730
731static void
732miSpriteMoveCursor (pScreen, x, y)
733    ScreenPtr	pScreen;
734    int		x, y;
735{
736    miSpriteScreenPtr	pScreenPriv;
737
738    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
739    miSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y);
740}
741
742/*
743 * undraw/draw cursor
744 */
745
746static void
747miSpriteRemoveCursor (pScreen)
748    ScreenPtr	pScreen;
749{
750    miSpriteScreenPtr   pScreenPriv;
751
752    DamageDrawInternal (pScreen, TRUE);
753    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
754    miSpriteIsUpFALSE (pScreen, pScreenPriv);
755    pScreenPriv->pCacheWin = NullWindow;
756    if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pScreen,
757					 pScreenPriv->saved.x1,
758					 pScreenPriv->saved.y1,
759					 pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
760					 pScreenPriv->saved.y2 - pScreenPriv->saved.y1))
761    {
762	miSpriteIsUpTRUE (pScreen, pScreenPriv);
763    }
764    DamageDrawInternal (pScreen, FALSE);
765}
766
767/*
768 * Called from the block handler, restores the cursor
769 * before waiting for something to do.
770 */
771
772static void
773miSpriteRestoreCursor (pScreen)
774    ScreenPtr	pScreen;
775{
776    miSpriteScreenPtr   pScreenPriv;
777    int			x, y;
778    CursorPtr		pCursor;
779
780    DamageDrawInternal (pScreen, TRUE);
781    miSpriteComputeSaved (pScreen);
782    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
783    pCursor = pScreenPriv->pCursor;
784    x = pScreenPriv->x - (int)pCursor->bits->xhot;
785    y = pScreenPriv->y - (int)pCursor->bits->yhot;
786    if ((*pScreenPriv->funcs->SaveUnderCursor) (pScreen,
787				      pScreenPriv->saved.x1,
788				      pScreenPriv->saved.y1,
789				      pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
790				      pScreenPriv->saved.y2 - pScreenPriv->saved.y1))
791    {
792	if (pScreenPriv->checkPixels)
793	    miSpriteFindColors (pScreen);
794	if ((*pScreenPriv->funcs->PutUpCursor) (pScreen, pCursor, x, y,
795				  pScreenPriv->colors[SOURCE_COLOR].pixel,
796				  pScreenPriv->colors[MASK_COLOR].pixel))
797	{
798	    miSpriteIsUpTRUE (pScreen, pScreenPriv);
799	}
800    }
801    DamageDrawInternal (pScreen, FALSE);
802}
803
804/*
805 * compute the desired area of the screen to save
806 */
807
808static void
809miSpriteComputeSaved (pScreen)
810    ScreenPtr	pScreen;
811{
812    miSpriteScreenPtr   pScreenPriv;
813    int		    x, y, w, h;
814    int		    wpad, hpad;
815    CursorPtr	    pCursor;
816
817    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
818    pCursor = pScreenPriv->pCursor;
819    x = pScreenPriv->x - (int)pCursor->bits->xhot;
820    y = pScreenPriv->y - (int)pCursor->bits->yhot;
821    w = pCursor->bits->width;
822    h = pCursor->bits->height;
823    wpad = SPRITE_PAD;
824    hpad = SPRITE_PAD;
825    pScreenPriv->saved.x1 = x - wpad;
826    pScreenPriv->saved.y1 = y - hpad;
827    pScreenPriv->saved.x2 = pScreenPriv->saved.x1 + w + wpad * 2;
828    pScreenPriv->saved.y2 = pScreenPriv->saved.y1 + h + hpad * 2;
829}
830