midispcur.c revision 05b261ec
1/*
2 * midispcur.c
3 *
4 * machine independent cursor display 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#define NEED_EVENTS
38# include   <X11/X.h>
39# include   "misc.h"
40# include   "input.h"
41# include   "cursorstr.h"
42# include   "windowstr.h"
43# include   "regionstr.h"
44# include   "dixstruct.h"
45# include   "scrnintstr.h"
46# include   "servermd.h"
47# include   "mipointer.h"
48# include   "misprite.h"
49# include   "gcstruct.h"
50
51#ifdef ARGB_CURSOR
52# include   "picturestr.h"
53#endif
54
55/* per-screen private data */
56
57static int	miDCScreenIndex;
58static unsigned long miDCGeneration = 0;
59
60static Bool	miDCCloseScreen(int index, ScreenPtr pScreen);
61
62typedef struct {
63    GCPtr	    pSourceGC, pMaskGC;
64    GCPtr	    pSaveGC, pRestoreGC;
65    GCPtr	    pMoveGC;
66    GCPtr	    pPixSourceGC, pPixMaskGC;
67    CloseScreenProcPtr CloseScreen;
68    PixmapPtr	    pSave, pTemp;
69#ifdef ARGB_CURSOR
70    PicturePtr	    pRootPicture;
71    PicturePtr	    pTempPicture;
72#endif
73} miDCScreenRec, *miDCScreenPtr;
74
75/* per-cursor per-screen private data */
76typedef struct {
77    PixmapPtr		sourceBits;	    /* source bits */
78    PixmapPtr		maskBits;	    /* mask bits */
79#ifdef ARGB_CURSOR
80    PicturePtr		pPicture;
81#endif
82} miDCCursorRec, *miDCCursorPtr;
83
84/*
85 * sprite/cursor method table
86 */
87
88static Bool	miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
89static Bool	miDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
90static Bool	miDCPutUpCursor(ScreenPtr pScreen, CursorPtr pCursor,
91				int x, int y, unsigned long source,
92				unsigned long mask);
93static Bool	miDCSaveUnderCursor(ScreenPtr pScreen, int x, int y,
94				    int w, int h);
95static Bool	miDCRestoreUnderCursor(ScreenPtr pScreen, int x, int y,
96				       int w, int h);
97static Bool	miDCMoveCursor(ScreenPtr pScreen, CursorPtr pCursor,
98			       int x, int y, int w, int h, int dx, int dy,
99			       unsigned long source, unsigned long mask);
100static Bool	miDCChangeSave(ScreenPtr pScreen, int x, int y, int w, int h,
101			       int dx, int dy);
102
103static miSpriteCursorFuncRec miDCFuncs = {
104    miDCRealizeCursor,
105    miDCUnrealizeCursor,
106    miDCPutUpCursor,
107    miDCSaveUnderCursor,
108    miDCRestoreUnderCursor,
109    miDCMoveCursor,
110    miDCChangeSave,
111};
112
113_X_EXPORT Bool
114miDCInitialize (pScreen, screenFuncs)
115    ScreenPtr		    pScreen;
116    miPointerScreenFuncPtr  screenFuncs;
117{
118    miDCScreenPtr   pScreenPriv;
119
120    if (miDCGeneration != serverGeneration)
121    {
122	miDCScreenIndex = AllocateScreenPrivateIndex ();
123	if (miDCScreenIndex < 0)
124	    return FALSE;
125	miDCGeneration = serverGeneration;
126    }
127    pScreenPriv = (miDCScreenPtr) xalloc (sizeof (miDCScreenRec));
128    if (!pScreenPriv)
129	return FALSE;
130
131    /*
132     * initialize the entire private structure to zeros
133     */
134
135    pScreenPriv->pSourceGC =
136	pScreenPriv->pMaskGC =
137	pScreenPriv->pSaveGC =
138 	pScreenPriv->pRestoreGC =
139 	pScreenPriv->pMoveGC =
140 	pScreenPriv->pPixSourceGC =
141	pScreenPriv->pPixMaskGC = NULL;
142#ifdef ARGB_CURSOR
143    pScreenPriv->pRootPicture = NULL;
144    pScreenPriv->pTempPicture = NULL;
145#endif
146
147    pScreenPriv->pSave = pScreenPriv->pTemp = NULL;
148
149    pScreenPriv->CloseScreen = pScreen->CloseScreen;
150    pScreen->CloseScreen = miDCCloseScreen;
151
152    pScreen->devPrivates[miDCScreenIndex].ptr = (pointer) pScreenPriv;
153
154    if (!miSpriteInitialize (pScreen, &miDCFuncs, screenFuncs))
155    {
156	xfree ((pointer) pScreenPriv);
157	return FALSE;
158    }
159    return TRUE;
160}
161
162#define tossGC(gc)  (gc ? FreeGC (gc, (GContext) 0) : 0)
163#define tossPix(pix)	(pix ? (*pScreen->DestroyPixmap) (pix) : TRUE)
164#define tossPict(pict)	(pict ? FreePicture (pict, 0) : 0)
165
166static Bool
167miDCCloseScreen (index, pScreen)
168    int		index;
169    ScreenPtr	pScreen;
170{
171    miDCScreenPtr   pScreenPriv;
172
173    pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
174    pScreen->CloseScreen = pScreenPriv->CloseScreen;
175    tossGC (pScreenPriv->pSourceGC);
176    tossGC (pScreenPriv->pMaskGC);
177    tossGC (pScreenPriv->pSaveGC);
178    tossGC (pScreenPriv->pRestoreGC);
179    tossGC (pScreenPriv->pMoveGC);
180    tossGC (pScreenPriv->pPixSourceGC);
181    tossGC (pScreenPriv->pPixMaskGC);
182    tossPix (pScreenPriv->pSave);
183    tossPix (pScreenPriv->pTemp);
184#ifdef ARGB_CURSOR
185#if 0				/* This has been free()d before */
186    tossPict (pScreenPriv->pRootPicture);
187#endif
188    tossPict (pScreenPriv->pTempPicture);
189#endif
190    xfree ((pointer) pScreenPriv);
191    return (*pScreen->CloseScreen) (index, pScreen);
192}
193
194static Bool
195miDCRealizeCursor (pScreen, pCursor)
196    ScreenPtr	pScreen;
197    CursorPtr	pCursor;
198{
199    if (pCursor->bits->refcnt <= 1)
200	pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL;
201    return TRUE;
202}
203
204#ifdef ARGB_CURSOR
205#define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win))
206
207static VisualPtr
208miDCGetWindowVisual (WindowPtr pWin)
209{
210    ScreenPtr	    pScreen = pWin->drawable.pScreen;
211    VisualID	    vid = wVisual (pWin);
212    int		    i;
213
214    for (i = 0; i < pScreen->numVisuals; i++)
215	if (pScreen->visuals[i].vid == vid)
216	    return &pScreen->visuals[i];
217    return 0;
218}
219
220static PicturePtr
221miDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin)
222{
223    ScreenPtr	    pScreen = pDraw->pScreen;
224    VisualPtr	    pVisual;
225    PictFormatPtr   pFormat;
226    XID		    subwindow_mode = IncludeInferiors;
227    PicturePtr	    pPicture;
228    int		    error;
229
230    pVisual = miDCGetWindowVisual (pWin);
231    if (!pVisual)
232	return 0;
233    pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual);
234    if (!pFormat)
235	return 0;
236    pPicture = CreatePicture (0, pDraw, pFormat,
237			      CPSubwindowMode, &subwindow_mode,
238			      serverClient, &error);
239    *ppPicture = pPicture;
240    return pPicture;
241}
242#endif
243
244static miDCCursorPtr
245miDCRealize (
246    ScreenPtr	pScreen,
247    CursorPtr	pCursor)
248{
249    miDCCursorPtr   pPriv;
250    GCPtr	    pGC;
251    XID		    gcvals[3];
252
253    pPriv = (miDCCursorPtr) xalloc (sizeof (miDCCursorRec));
254    if (!pPriv)
255	return (miDCCursorPtr)NULL;
256#ifdef ARGB_CURSOR
257    if (pCursor->bits->argb)
258    {
259	PixmapPtr	pPixmap;
260	PictFormatPtr	pFormat;
261	int		error;
262
263	pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
264	if (!pFormat)
265	{
266	    xfree ((pointer) pPriv);
267	    return (miDCCursorPtr)NULL;
268	}
269
270	pPriv->sourceBits = 0;
271	pPriv->maskBits = 0;
272	pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
273					    pCursor->bits->height, 32);
274	if (!pPixmap)
275	{
276	    xfree ((pointer) pPriv);
277	    return (miDCCursorPtr)NULL;
278	}
279	pGC = GetScratchGC (32, pScreen);
280	if (!pGC)
281	{
282	    (*pScreen->DestroyPixmap) (pPixmap);
283	    xfree ((pointer) pPriv);
284	    return (miDCCursorPtr)NULL;
285	}
286	ValidateGC (&pPixmap->drawable, pGC);
287	(*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32,
288			       0, 0, pCursor->bits->width,
289			       pCursor->bits->height,
290			       0, ZPixmap, (char *) pCursor->bits->argb);
291	FreeScratchGC (pGC);
292	pPriv->pPicture = CreatePicture (0, &pPixmap->drawable,
293					pFormat, 0, 0, serverClient, &error);
294        (*pScreen->DestroyPixmap) (pPixmap);
295	if (!pPriv->pPicture)
296	{
297	    xfree ((pointer) pPriv);
298	    return (miDCCursorPtr)NULL;
299	}
300	pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv;
301	return pPriv;
302    }
303    pPriv->pPicture = 0;
304#endif
305    pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1);
306    if (!pPriv->sourceBits)
307    {
308	xfree ((pointer) pPriv);
309	return (miDCCursorPtr)NULL;
310    }
311    pPriv->maskBits =  (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1);
312    if (!pPriv->maskBits)
313    {
314	(*pScreen->DestroyPixmap) (pPriv->sourceBits);
315	xfree ((pointer) pPriv);
316	return (miDCCursorPtr)NULL;
317    }
318    pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv;
319
320    /* create the two sets of bits, clipping as appropriate */
321
322    pGC = GetScratchGC (1, pScreen);
323    if (!pGC)
324    {
325	(void) miDCUnrealizeCursor (pScreen, pCursor);
326	return (miDCCursorPtr)NULL;
327    }
328
329    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
330    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
331			   0, 0, pCursor->bits->width, pCursor->bits->height,
332 			   0, XYPixmap, (char *)pCursor->bits->source);
333    gcvals[0] = GXand;
334    ChangeGC (pGC, GCFunction, gcvals);
335    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
336    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
337			   0, 0, pCursor->bits->width, pCursor->bits->height,
338 			   0, XYPixmap, (char *)pCursor->bits->mask);
339
340    /* mask bits -- pCursor->mask & ~pCursor->source */
341    gcvals[0] = GXcopy;
342    ChangeGC (pGC, GCFunction, gcvals);
343    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
344    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
345			   0, 0, pCursor->bits->width, pCursor->bits->height,
346 			   0, XYPixmap, (char *)pCursor->bits->mask);
347    gcvals[0] = GXandInverted;
348    ChangeGC (pGC, GCFunction, gcvals);
349    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
350    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
351			   0, 0, pCursor->bits->width, pCursor->bits->height,
352 			   0, XYPixmap, (char *)pCursor->bits->source);
353    FreeScratchGC (pGC);
354    return pPriv;
355}
356
357static Bool
358miDCUnrealizeCursor (pScreen, pCursor)
359    ScreenPtr	pScreen;
360    CursorPtr	pCursor;
361{
362    miDCCursorPtr   pPriv;
363
364    pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
365    if (pPriv && (pCursor->bits->refcnt <= 1))
366    {
367	if (pPriv->sourceBits)
368	    (*pScreen->DestroyPixmap) (pPriv->sourceBits);
369	if (pPriv->maskBits)
370	    (*pScreen->DestroyPixmap) (pPriv->maskBits);
371#ifdef ARGB_CURSOR
372	if (pPriv->pPicture)
373	    FreePicture (pPriv->pPicture, 0);
374#endif
375	xfree ((pointer) pPriv);
376	pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL;
377    }
378    return TRUE;
379}
380
381static void
382miDCPutBits (
383    DrawablePtr	    pDrawable,
384    miDCCursorPtr   pPriv,
385    GCPtr	    sourceGC,
386    GCPtr	    maskGC,
387    int             x_org,
388    int             y_org,
389    unsigned        w,
390    unsigned        h,
391    unsigned long   source,
392    unsigned long   mask)
393{
394    XID	    gcvals[1];
395    int     x, y;
396
397    if (sourceGC->fgPixel != source)
398    {
399	gcvals[0] = source;
400	DoChangeGC (sourceGC, GCForeground, gcvals, 0);
401    }
402    if (sourceGC->serialNumber != pDrawable->serialNumber)
403	ValidateGC (pDrawable, sourceGC);
404
405    if(sourceGC->miTranslate)
406    {
407        x = pDrawable->x + x_org;
408        y = pDrawable->y + y_org;
409    }
410    else
411    {
412        x = x_org;
413        y = y_org;
414    }
415
416    (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y);
417    if (maskGC->fgPixel != mask)
418    {
419	gcvals[0] = mask;
420	DoChangeGC (maskGC, GCForeground, gcvals, 0);
421    }
422    if (maskGC->serialNumber != pDrawable->serialNumber)
423	ValidateGC (pDrawable, maskGC);
424
425    if(maskGC->miTranslate)
426    {
427        x = pDrawable->x + x_org;
428        y = pDrawable->y + y_org;
429    }
430    else
431    {
432        x = x_org;
433        y = y_org;
434    }
435
436    (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y);
437}
438
439#define EnsureGC(gc,win) (gc || miDCMakeGC(&gc, win))
440
441static GCPtr
442miDCMakeGC(
443    GCPtr	*ppGC,
444    WindowPtr	pWin)
445{
446    GCPtr pGC;
447    int   status;
448    XID   gcvals[2];
449
450    gcvals[0] = IncludeInferiors;
451    gcvals[1] = FALSE;
452    pGC = CreateGC((DrawablePtr)pWin,
453		   GCSubwindowMode|GCGraphicsExposures, gcvals, &status);
454    if (pGC && pWin->drawable.pScreen->DrawGuarantee)
455	(*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack);
456    *ppGC = pGC;
457    return pGC;
458}
459
460
461static Bool
462miDCPutUpCursor (pScreen, pCursor, x, y, source, mask)
463    ScreenPtr	    pScreen;
464    CursorPtr	    pCursor;
465    int		    x, y;
466    unsigned long   source, mask;
467{
468    miDCScreenPtr   pScreenPriv;
469    miDCCursorPtr   pPriv;
470    WindowPtr	    pWin;
471
472    pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
473    if (!pPriv)
474    {
475	pPriv = miDCRealize(pScreen, pCursor);
476	if (!pPriv)
477	    return FALSE;
478    }
479    pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
480    pWin = WindowTable[pScreen->myNum];
481#ifdef ARGB_CURSOR
482    if (pPriv->pPicture)
483    {
484	if (!EnsurePicture(pScreenPriv->pRootPicture, &pWin->drawable, pWin))
485	    return FALSE;
486	CompositePicture (PictOpOver,
487			  pPriv->pPicture,
488			  NULL,
489			  pScreenPriv->pRootPicture,
490			  0, 0, 0, 0,
491			  x, y,
492			  pCursor->bits->width,
493			  pCursor->bits->height);
494    }
495    else
496#endif
497    {
498	if (!EnsureGC(pScreenPriv->pSourceGC, pWin))
499	    return FALSE;
500	if (!EnsureGC(pScreenPriv->pMaskGC, pWin))
501	{
502	    FreeGC (pScreenPriv->pSourceGC, (GContext) 0);
503	    pScreenPriv->pSourceGC = 0;
504	    return FALSE;
505	}
506	miDCPutBits ((DrawablePtr)pWin, pPriv,
507		     pScreenPriv->pSourceGC, pScreenPriv->pMaskGC,
508		     x, y, pCursor->bits->width, pCursor->bits->height,
509		     source, mask);
510    }
511    return TRUE;
512}
513
514static Bool
515miDCSaveUnderCursor (pScreen, x, y, w, h)
516    ScreenPtr	pScreen;
517    int		x, y, w, h;
518{
519    miDCScreenPtr   pScreenPriv;
520    PixmapPtr	    pSave;
521    WindowPtr	    pWin;
522    GCPtr	    pGC;
523
524    pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
525    pSave = pScreenPriv->pSave;
526    pWin = WindowTable[pScreen->myNum];
527    if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h)
528    {
529	if (pSave)
530	    (*pScreen->DestroyPixmap) (pSave);
531	pScreenPriv->pSave = pSave =
532		(*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth);
533	if (!pSave)
534	    return FALSE;
535    }
536    if (!EnsureGC(pScreenPriv->pSaveGC, pWin))
537	return FALSE;
538    pGC = pScreenPriv->pSaveGC;
539    if (pSave->drawable.serialNumber != pGC->serialNumber)
540	ValidateGC ((DrawablePtr) pSave, pGC);
541    (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
542			    x, y, w, h, 0, 0);
543    return TRUE;
544}
545
546static Bool
547miDCRestoreUnderCursor (pScreen, x, y, w, h)
548    ScreenPtr	pScreen;
549    int		x, y, w, h;
550{
551    miDCScreenPtr   pScreenPriv;
552    PixmapPtr	    pSave;
553    WindowPtr	    pWin;
554    GCPtr	    pGC;
555
556    pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
557    pSave = pScreenPriv->pSave;
558    pWin = WindowTable[pScreen->myNum];
559    if (!pSave)
560	return FALSE;
561    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
562	return FALSE;
563    pGC = pScreenPriv->pRestoreGC;
564    if (pWin->drawable.serialNumber != pGC->serialNumber)
565	ValidateGC ((DrawablePtr) pWin, pGC);
566    (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
567			    0, 0, w, h, x, y);
568    return TRUE;
569}
570
571static Bool
572miDCChangeSave (pScreen, x, y, w, h, dx, dy)
573    ScreenPtr	    pScreen;
574    int		    x, y, w, h, dx, dy;
575{
576    miDCScreenPtr   pScreenPriv;
577    PixmapPtr	    pSave;
578    WindowPtr	    pWin;
579    GCPtr	    pGC;
580    int		    sourcex, sourcey, destx, desty, copyw, copyh;
581
582    pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
583    pSave = pScreenPriv->pSave;
584    pWin = WindowTable[pScreen->myNum];
585    /*
586     * restore the bits which are about to get trashed
587     */
588    if (!pSave)
589	return FALSE;
590    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
591	return FALSE;
592    pGC = pScreenPriv->pRestoreGC;
593    if (pWin->drawable.serialNumber != pGC->serialNumber)
594	ValidateGC ((DrawablePtr) pWin, pGC);
595    /*
596     * copy the old bits to the screen.
597     */
598    if (dy > 0)
599    {
600	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
601			       0, h - dy, w, dy, x + dx, y + h);
602    }
603    else if (dy < 0)
604    {
605	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
606			       0, 0, w, -dy, x + dx, y + dy);
607    }
608    if (dy >= 0)
609    {
610	desty = y + dy;
611	sourcey = 0;
612	copyh = h - dy;
613    }
614    else
615    {
616	desty = y;
617	sourcey = - dy;
618	copyh = h + dy;
619    }
620    if (dx > 0)
621    {
622	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
623			       w - dx, sourcey, dx, copyh, x + w, desty);
624    }
625    else if (dx < 0)
626    {
627	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
628			       0, sourcey, -dx, copyh, x + dx, desty);
629    }
630    if (!EnsureGC(pScreenPriv->pSaveGC, pWin))
631	return FALSE;
632    pGC = pScreenPriv->pSaveGC;
633    if (pSave->drawable.serialNumber != pGC->serialNumber)
634	ValidateGC ((DrawablePtr) pSave, pGC);
635    /*
636     * move the bits that are still valid within the pixmap
637     */
638    if (dx >= 0)
639    {
640	sourcex = 0;
641	destx = dx;
642	copyw = w - dx;
643    }
644    else
645    {
646	destx = 0;
647	sourcex = - dx;
648	copyw = w + dx;
649    }
650    if (dy >= 0)
651    {
652	sourcey = 0;
653	desty = dy;
654	copyh = h - dy;
655    }
656    else
657    {
658	desty = 0;
659	sourcey = -dy;
660	copyh = h + dy;
661    }
662    (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pSave, pGC,
663			   sourcex, sourcey, copyw, copyh, destx, desty);
664    /*
665     * copy the new bits from the screen into the remaining areas of the
666     * pixmap
667     */
668    if (dy > 0)
669    {
670	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
671			       x, y, w, dy, 0, 0);
672    }
673    else if (dy < 0)
674    {
675	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
676			       x, y + h + dy, w, -dy, 0, h + dy);
677    }
678    if (dy >= 0)
679    {
680	desty = dy;
681	sourcey = y + dy;
682	copyh = h - dy;
683    }
684    else
685    {
686	desty = 0;
687	sourcey = y;
688	copyh = h + dy;
689    }
690    if (dx > 0)
691    {
692	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
693			       x, sourcey, dx, copyh, 0, desty);
694    }
695    else if (dx < 0)
696    {
697	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
698			       x + w + dx, sourcey, -dx, copyh, w + dx, desty);
699    }
700    return TRUE;
701}
702
703static Bool
704miDCMoveCursor (pScreen, pCursor, x, y, w, h, dx, dy, source, mask)
705    ScreenPtr	    pScreen;
706    CursorPtr	    pCursor;
707    int		    x, y, w, h, dx, dy;
708    unsigned long   source, mask;
709{
710    miDCCursorPtr   pPriv;
711    miDCScreenPtr   pScreenPriv;
712    int		    status;
713    WindowPtr	    pWin;
714    GCPtr	    pGC;
715    XID		    gcval = FALSE;
716    PixmapPtr	    pTemp;
717
718    pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
719    if (!pPriv)
720    {
721	pPriv = miDCRealize(pScreen, pCursor);
722	if (!pPriv)
723	    return FALSE;
724    }
725    pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
726    pWin = WindowTable[pScreen->myNum];
727    pTemp = pScreenPriv->pTemp;
728    if (!pTemp ||
729	pTemp->drawable.width != pScreenPriv->pSave->drawable.width ||
730	pTemp->drawable.height != pScreenPriv->pSave->drawable.height)
731    {
732	if (pTemp)
733	    (*pScreen->DestroyPixmap) (pTemp);
734#ifdef ARGB_CURSOR
735	if (pScreenPriv->pTempPicture)
736	{
737	    FreePicture (pScreenPriv->pTempPicture, 0);
738	    pScreenPriv->pTempPicture = 0;
739	}
740#endif
741	pScreenPriv->pTemp = pTemp = (*pScreen->CreatePixmap)
742	    (pScreen, w, h, pScreenPriv->pSave->drawable.depth);
743	if (!pTemp)
744	    return FALSE;
745    }
746    if (!pScreenPriv->pMoveGC)
747    {
748	pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp,
749	    GCGraphicsExposures, &gcval, &status);
750	if (!pScreenPriv->pMoveGC)
751	    return FALSE;
752    }
753    /*
754     * copy the saved area to a temporary pixmap
755     */
756    pGC = pScreenPriv->pMoveGC;
757    if (pGC->serialNumber != pTemp->drawable.serialNumber)
758	ValidateGC ((DrawablePtr) pTemp, pGC);
759    (*pGC->ops->CopyArea)((DrawablePtr)pScreenPriv->pSave,
760			  (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0);
761
762    /*
763     * draw the cursor in the temporary pixmap
764     */
765#ifdef ARGB_CURSOR
766    if (pPriv->pPicture)
767    {
768	if (!EnsurePicture(pScreenPriv->pTempPicture, &pTemp->drawable, pWin))
769	    return FALSE;
770	CompositePicture (PictOpOver,
771			  pPriv->pPicture,
772			  NULL,
773			  pScreenPriv->pTempPicture,
774			  0, 0, 0, 0,
775			  dx, dy,
776			  pCursor->bits->width,
777			  pCursor->bits->height);
778    }
779    else
780#endif
781    {
782	if (!pScreenPriv->pPixSourceGC)
783	{
784	    pScreenPriv->pPixSourceGC = CreateGC ((DrawablePtr)pTemp,
785		GCGraphicsExposures, &gcval, &status);
786	    if (!pScreenPriv->pPixSourceGC)
787		return FALSE;
788	}
789	if (!pScreenPriv->pPixMaskGC)
790	{
791	    pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp,
792		GCGraphicsExposures, &gcval, &status);
793	    if (!pScreenPriv->pPixMaskGC)
794		return FALSE;
795	}
796	miDCPutBits ((DrawablePtr)pTemp, pPriv,
797		     pScreenPriv->pPixSourceGC, pScreenPriv->pPixMaskGC,
798		     dx, dy, pCursor->bits->width, pCursor->bits->height,
799		     source, mask);
800    }
801
802    /*
803     * copy the temporary pixmap onto the screen
804     */
805
806    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
807	return FALSE;
808    pGC = pScreenPriv->pRestoreGC;
809    if (pWin->drawable.serialNumber != pGC->serialNumber)
810	ValidateGC ((DrawablePtr) pWin, pGC);
811
812    (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin,
813			    pGC,
814			    0, 0, w, h, x, y);
815    return TRUE;
816}
817