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# include   <X11/X.h>
38# include   "misc.h"
39# include   "input.h"
40# include   "cursorstr.h"
41# include   "windowstr.h"
42# include   "regionstr.h"
43# include   "dixstruct.h"
44# include   "scrnintstr.h"
45# include   "servermd.h"
46# include   "mipointer.h"
47# include   "misprite.h"
48# include   "gcstruct.h"
49
50#ifdef ARGB_CURSOR
51# include   "picturestr.h"
52#endif
53
54# include "inputstr.h"
55
56/* per-screen private data */
57static DevPrivateKeyRec miDCScreenKeyRec;
58#define miDCScreenKey (&miDCScreenKeyRec)
59static DevScreenPrivateKeyRec miDCCursorBitsKeyRec;
60#define miDCCursorBitsKey (&miDCCursorBitsKeyRec)
61static DevScreenPrivateKeyRec miDCDeviceKeyRec;
62#define miDCDeviceKey (&miDCDeviceKeyRec)
63
64static Bool	miDCCloseScreen(int index, ScreenPtr pScreen);
65
66/* per device private data */
67typedef struct {
68    GCPtr	    pSourceGC, pMaskGC;
69    GCPtr	    pSaveGC, pRestoreGC;
70    PixmapPtr	    pSave;
71#ifdef ARGB_CURSOR
72    PicturePtr	    pRootPicture;
73#endif
74} miDCBufferRec, *miDCBufferPtr;
75
76#define miGetDCDevice(dev, screen) \
77 ((DevHasCursor(dev)) ? \
78  (miDCBufferPtr)dixLookupScreenPrivate(&dev->devPrivates, miDCDeviceKey, screen) : \
79  (miDCBufferPtr)dixLookupScreenPrivate(&dev->u.master->devPrivates, miDCDeviceKey, screen))
80
81/*
82 * The core pointer buffer will point to the index of the virtual core pointer
83 * in the pCursorBuffers array.
84 */
85typedef struct {
86    CloseScreenProcPtr	CloseScreen;
87} miDCScreenRec, *miDCScreenPtr;
88
89#define miGetDCScreen(s)	((miDCScreenPtr)(dixLookupPrivate(&(s)->devPrivates, miDCScreenKey)))
90
91/* per-cursor per-screen private data */
92typedef struct {
93    PixmapPtr		sourceBits;	    /* source bits */
94    PixmapPtr		maskBits;	    /* mask bits */
95#ifdef ARGB_CURSOR
96    PicturePtr		pPicture;
97#endif
98} miDCCursorRec, *miDCCursorPtr;
99
100Bool
101miDCInitialize (ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs)
102{
103    miDCScreenPtr   pScreenPriv;
104
105    if (!dixRegisterPrivateKey(&miDCScreenKeyRec, PRIVATE_SCREEN, 0) ||
106        !dixRegisterScreenPrivateKey(&miDCCursorBitsKeyRec, pScreen, PRIVATE_CURSOR_BITS, 0) ||
107        !dixRegisterScreenPrivateKey(&miDCDeviceKeyRec, pScreen, PRIVATE_DEVICE, 0))
108	return FALSE;
109
110    pScreenPriv = malloc(sizeof (miDCScreenRec));
111    if (!pScreenPriv)
112	return FALSE;
113
114    pScreenPriv->CloseScreen = pScreen->CloseScreen;
115    pScreen->CloseScreen = miDCCloseScreen;
116
117    dixSetPrivate(&pScreen->devPrivates, miDCScreenKey, pScreenPriv);
118
119    if (!miSpriteInitialize (pScreen, screenFuncs))
120    {
121	free((pointer) pScreenPriv);
122	return FALSE;
123    }
124    return TRUE;
125}
126
127static Bool
128miDCCloseScreen (int index, ScreenPtr pScreen)
129{
130    miDCScreenPtr   pScreenPriv;
131
132    pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
133						  miDCScreenKey);
134    pScreen->CloseScreen = pScreenPriv->CloseScreen;
135    free((pointer) pScreenPriv);
136    return (*pScreen->CloseScreen) (index, pScreen);
137}
138
139Bool
140miDCRealizeCursor (ScreenPtr pScreen, CursorPtr pCursor)
141{
142    if (pCursor->bits->refcnt <= 1)
143	dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, NULL);
144    return TRUE;
145}
146
147#ifdef ARGB_CURSOR
148#define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win))
149
150static VisualPtr
151miDCGetWindowVisual (WindowPtr pWin)
152{
153    ScreenPtr	    pScreen = pWin->drawable.pScreen;
154    VisualID	    vid = wVisual (pWin);
155    int		    i;
156
157    for (i = 0; i < pScreen->numVisuals; i++)
158	if (pScreen->visuals[i].vid == vid)
159	    return &pScreen->visuals[i];
160    return 0;
161}
162
163static PicturePtr
164miDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin)
165{
166    ScreenPtr	    pScreen = pDraw->pScreen;
167    VisualPtr	    pVisual;
168    PictFormatPtr   pFormat;
169    XID		    subwindow_mode = IncludeInferiors;
170    PicturePtr	    pPicture;
171    int		    error;
172
173    pVisual = miDCGetWindowVisual (pWin);
174    if (!pVisual)
175	return 0;
176    pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual);
177    if (!pFormat)
178	return 0;
179    pPicture = CreatePicture (0, pDraw, pFormat,
180			      CPSubwindowMode, &subwindow_mode,
181			      serverClient, &error);
182    *ppPicture = pPicture;
183    return pPicture;
184}
185#endif
186
187static miDCCursorPtr
188miDCRealize (ScreenPtr pScreen, CursorPtr pCursor)
189{
190    miDCCursorPtr   pPriv;
191    GCPtr	    pGC;
192    ChangeGCVal	    gcvals;
193
194    pPriv = malloc(sizeof (miDCCursorRec));
195    if (!pPriv)
196	return NULL;
197#ifdef ARGB_CURSOR
198    if (pCursor->bits->argb)
199    {
200	PixmapPtr	pPixmap;
201	PictFormatPtr	pFormat;
202	int		error;
203
204	pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
205	if (!pFormat)
206	{
207	    free((pointer) pPriv);
208	    return NULL;
209	}
210
211	pPriv->sourceBits = 0;
212	pPriv->maskBits = 0;
213	pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
214					    pCursor->bits->height, 32,
215					    CREATE_PIXMAP_USAGE_SCRATCH);
216	if (!pPixmap)
217	{
218	    free((pointer) pPriv);
219	    return NULL;
220	}
221	pGC = GetScratchGC (32, pScreen);
222	if (!pGC)
223	{
224	    (*pScreen->DestroyPixmap) (pPixmap);
225	    free((pointer) pPriv);
226	    return NULL;
227	}
228	ValidateGC (&pPixmap->drawable, pGC);
229	(*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32,
230			       0, 0, pCursor->bits->width,
231			       pCursor->bits->height,
232			       0, ZPixmap, (char *) pCursor->bits->argb);
233	FreeScratchGC (pGC);
234	pPriv->pPicture = CreatePicture (0, &pPixmap->drawable,
235					pFormat, 0, 0, serverClient, &error);
236        (*pScreen->DestroyPixmap) (pPixmap);
237	if (!pPriv->pPicture)
238	{
239	    free((pointer) pPriv);
240	    return NULL;
241	}
242	dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, pPriv);
243	return pPriv;
244    }
245    pPriv->pPicture = 0;
246#endif
247    pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0);
248    if (!pPriv->sourceBits)
249    {
250	free((pointer) pPriv);
251	return NULL;
252    }
253    pPriv->maskBits =  (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0);
254    if (!pPriv->maskBits)
255    {
256	(*pScreen->DestroyPixmap) (pPriv->sourceBits);
257	free((pointer) pPriv);
258	return NULL;
259    }
260    dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, pPriv);
261
262    /* create the two sets of bits, clipping as appropriate */
263
264    pGC = GetScratchGC (1, pScreen);
265    if (!pGC)
266    {
267	(void) miDCUnrealizeCursor (pScreen, pCursor);
268	return NULL;
269    }
270
271    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
272    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
273			   0, 0, pCursor->bits->width, pCursor->bits->height,
274 			   0, XYPixmap, (char *)pCursor->bits->source);
275    gcvals.val = GXand;
276    ChangeGC (NullClient, pGC, GCFunction, &gcvals);
277    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
278    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
279			   0, 0, pCursor->bits->width, pCursor->bits->height,
280 			   0, XYPixmap, (char *)pCursor->bits->mask);
281
282    /* mask bits -- pCursor->mask & ~pCursor->source */
283    gcvals.val = GXcopy;
284    ChangeGC (NullClient, pGC, GCFunction, &gcvals);
285    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
286    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
287			   0, 0, pCursor->bits->width, pCursor->bits->height,
288 			   0, XYPixmap, (char *)pCursor->bits->mask);
289    gcvals.val = GXandInverted;
290    ChangeGC (NullClient, pGC, GCFunction, &gcvals);
291    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
292    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
293			   0, 0, pCursor->bits->width, pCursor->bits->height,
294 			   0, XYPixmap, (char *)pCursor->bits->source);
295    FreeScratchGC (pGC);
296    return pPriv;
297}
298
299Bool
300miDCUnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor)
301{
302    miDCCursorPtr   pPriv;
303
304    pPriv = (miDCCursorPtr)dixLookupScreenPrivate(&pCursor->bits->devPrivates,
305						  miDCCursorBitsKey, pScreen);
306    if (pPriv && (pCursor->bits->refcnt <= 1))
307    {
308	if (pPriv->sourceBits)
309	    (*pScreen->DestroyPixmap) (pPriv->sourceBits);
310	if (pPriv->maskBits)
311	    (*pScreen->DestroyPixmap) (pPriv->maskBits);
312#ifdef ARGB_CURSOR
313	if (pPriv->pPicture)
314	    FreePicture (pPriv->pPicture, 0);
315#endif
316	free((pointer) pPriv);
317	dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, NULL);
318    }
319    return TRUE;
320}
321
322static void
323miDCPutBits (
324    DrawablePtr	    pDrawable,
325    miDCCursorPtr   pPriv,
326    GCPtr	    sourceGC,
327    GCPtr	    maskGC,
328    int             x_org,
329    int             y_org,
330    unsigned        w,
331    unsigned        h,
332    unsigned long   source,
333    unsigned long   mask)
334{
335    ChangeGCVal gcval;
336    int     x, y;
337
338    if (sourceGC->fgPixel != source)
339    {
340	gcval.val = source;
341	ChangeGC (NullClient, sourceGC, GCForeground, &gcval);
342    }
343    if (sourceGC->serialNumber != pDrawable->serialNumber)
344	ValidateGC (pDrawable, sourceGC);
345
346    if(sourceGC->miTranslate)
347    {
348        x = pDrawable->x + x_org;
349        y = pDrawable->y + y_org;
350    }
351    else
352    {
353        x = x_org;
354        y = y_org;
355    }
356
357    (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y);
358    if (maskGC->fgPixel != mask)
359    {
360	gcval.val = mask;
361	ChangeGC (NullClient, maskGC, GCForeground, &gcval);
362    }
363    if (maskGC->serialNumber != pDrawable->serialNumber)
364	ValidateGC (pDrawable, maskGC);
365
366    if(maskGC->miTranslate)
367    {
368        x = pDrawable->x + x_org;
369        y = pDrawable->y + y_org;
370    }
371    else
372    {
373        x = x_org;
374        y = y_org;
375    }
376
377    (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y);
378}
379
380static GCPtr
381miDCMakeGC(WindowPtr pWin)
382{
383    GCPtr pGC;
384    int   status;
385    XID   gcvals[2];
386
387    gcvals[0] = IncludeInferiors;
388    gcvals[1] = FALSE;
389    pGC = CreateGC((DrawablePtr)pWin,
390		   GCSubwindowMode|GCGraphicsExposures, gcvals, &status,
391		   (XID)0, serverClient);
392    return pGC;
393}
394
395
396Bool
397miDCPutUpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor,
398                 int x, int y, unsigned long source, unsigned long mask)
399{
400    miDCCursorPtr   pPriv;
401    miDCBufferPtr   pBuffer;
402    WindowPtr	    pWin;
403
404    pPriv = (miDCCursorPtr)dixLookupScreenPrivate(&pCursor->bits->devPrivates,
405						  miDCCursorBitsKey, pScreen);
406    if (!pPriv)
407    {
408	pPriv = miDCRealize(pScreen, pCursor);
409	if (!pPriv)
410	    return FALSE;
411    }
412
413    pWin = pScreen->root;
414    pBuffer = miGetDCDevice(pDev, pScreen);
415
416#ifdef ARGB_CURSOR
417    if (pPriv->pPicture)
418    {
419	if (!EnsurePicture(pBuffer->pRootPicture, &pWin->drawable, pWin))
420	    return FALSE;
421	CompositePicture (PictOpOver,
422			  pPriv->pPicture,
423			  NULL,
424			  pBuffer->pRootPicture,
425			  0, 0, 0, 0,
426			  x, y,
427			  pCursor->bits->width,
428			  pCursor->bits->height);
429    }
430    else
431#endif
432    {
433	miDCPutBits ((DrawablePtr)pWin, pPriv,
434		     pBuffer->pSourceGC, pBuffer->pMaskGC,
435		     x, y, pCursor->bits->width, pCursor->bits->height,
436		     source, mask);
437    }
438    return TRUE;
439}
440
441Bool
442miDCSaveUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen,
443                     int x, int y, int w, int h)
444{
445    miDCBufferPtr   pBuffer;
446    PixmapPtr	    pSave;
447    WindowPtr	    pWin;
448    GCPtr	    pGC;
449
450    pBuffer = miGetDCDevice(pDev, pScreen);
451
452    pSave = pBuffer->pSave;
453    pWin = pScreen->root;
454    if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h)
455    {
456	if (pSave)
457	    (*pScreen->DestroyPixmap) (pSave);
458	pBuffer->pSave = pSave =
459		(*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth, 0);
460	if (!pSave)
461	    return FALSE;
462    }
463
464    pGC = pBuffer->pSaveGC;
465    if (pSave->drawable.serialNumber != pGC->serialNumber)
466	ValidateGC ((DrawablePtr) pSave, pGC);
467    (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
468			    x, y, w, h, 0, 0);
469    return TRUE;
470}
471
472Bool
473miDCRestoreUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen,
474                        int x, int y, int w, int h)
475{
476    miDCBufferPtr   pBuffer;
477    PixmapPtr	    pSave;
478    WindowPtr	    pWin;
479    GCPtr	    pGC;
480
481    pBuffer = miGetDCDevice(pDev, pScreen);
482    pSave = pBuffer->pSave;
483
484    pWin = pScreen->root;
485    if (!pSave)
486	return FALSE;
487
488    pGC = pBuffer->pRestoreGC;
489    if (pWin->drawable.serialNumber != pGC->serialNumber)
490	ValidateGC ((DrawablePtr) pWin, pGC);
491    (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
492			    0, 0, w, h, x, y);
493    return TRUE;
494}
495
496Bool
497miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
498{
499    miDCBufferPtr   pBuffer;
500    WindowPtr       pWin;
501    int             i;
502
503    if (!DevHasCursor(pDev))
504        return TRUE;
505
506    for (i = 0; i < screenInfo.numScreens; i++)
507    {
508        pScreen = screenInfo.screens[i];
509
510        pBuffer = calloc(1, sizeof(miDCBufferRec));
511        if (!pBuffer)
512            goto failure;
513
514        dixSetScreenPrivate(&pDev->devPrivates, miDCDeviceKey, pScreen, pBuffer);
515        pWin = pScreen->root;
516
517        pBuffer->pSourceGC = miDCMakeGC(pWin);
518        if (!pBuffer->pSourceGC)
519            goto failure;
520
521        pBuffer->pMaskGC = miDCMakeGC(pWin);
522        if (!pBuffer->pMaskGC)
523            goto failure;
524
525        pBuffer->pSaveGC = miDCMakeGC(pWin);
526        if (!pBuffer->pSaveGC)
527            goto failure;
528
529        pBuffer->pRestoreGC = miDCMakeGC(pWin);
530        if (!pBuffer->pRestoreGC)
531            goto failure;
532
533#ifdef ARGB_CURSOR
534        pBuffer->pRootPicture = NULL;
535#endif
536
537        /* (re)allocated lazily depending on the cursor size */
538        pBuffer->pSave = NULL;
539    }
540
541    return TRUE;
542
543failure:
544
545    miDCDeviceCleanup(pDev, pScreen);
546
547    return FALSE;
548}
549
550void
551miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
552{
553    miDCBufferPtr   pBuffer;
554    int             i;
555
556    if (DevHasCursor(pDev))
557    {
558        for (i = 0; i < screenInfo.numScreens; i++)
559        {
560            pScreen = screenInfo.screens[i];
561
562            pBuffer = miGetDCDevice(pDev, pScreen);
563
564            if (pBuffer)
565            {
566                if (pBuffer->pSourceGC) FreeGC(pBuffer->pSourceGC, (GContext) 0);
567                if (pBuffer->pMaskGC) FreeGC(pBuffer->pMaskGC, (GContext) 0);
568                if (pBuffer->pSaveGC) FreeGC(pBuffer->pSaveGC, (GContext) 0);
569                if (pBuffer->pRestoreGC) FreeGC(pBuffer->pRestoreGC, (GContext) 0);
570
571#ifdef ARGB_CURSOR
572                /* If a pRootPicture was allocated for a root window, it
573                 * is freed when that root window is destroyed, so don't
574                 * free it again here. */
575#endif
576
577                if (pBuffer->pSave) (*pScreen->DestroyPixmap)(pBuffer->pSave);
578
579                free(pBuffer);
580                dixSetScreenPrivate(&pDev->devPrivates, miDCDeviceKey, pScreen, NULL);
581            }
582        }
583    }
584}
585