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