1 /*
2  * midispcur.c
3  *
4  * machine independent cursor display routines
5  */
6 
7 /*
8 
9 Copyright 1989, 1998  The Open Group
10 
11 Permission to use, copy, modify, distribute, and sell this software and its
12 documentation for any purpose is hereby granted without fee, provided that
13 the above copyright notice appear in all copies and that both that
14 copyright notice and this permission notice appear in supporting
15 documentation.
16 
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
23 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
24 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 
27 Except as contained in this notice, the name of The Open Group shall not be
28 used in advertising or otherwise to promote the sale, use or other dealings
29 in 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   "misc.h"
38 #include   "input.h"
39 #include   "cursorstr.h"
40 #include   "windowstr.h"
41 #include   "regionstr.h"
42 #include   "dixstruct.h"
43 #include   "scrnintstr.h"
44 #include   "servermd.h"
45 #include   "mipointer.h"
46 #include   "misprite.h"
47 #include   "gcstruct.h"
48 
49 #include   "picturestr.h"
50 
51 #include "inputstr.h"
52 
53 /* per-screen private data */
54 static DevPrivateKeyRec miDCScreenKeyRec;
55 
56 #define miDCScreenKey (&miDCScreenKeyRec)
57 
58 static DevScreenPrivateKeyRec miDCDeviceKeyRec;
59 
60 #define miDCDeviceKey (&miDCDeviceKeyRec)
61 
62 static Bool miDCCloseScreen(ScreenPtr pScreen);
63 
64 /* per device private data */
65 typedef struct {
66     GCPtr pSourceGC, pMaskGC;
67     GCPtr pSaveGC, pRestoreGC;
68     PixmapPtr pSave;
69     PicturePtr pRootPicture;
70 } miDCBufferRec, *miDCBufferPtr;
71 
72 #define miGetDCDevice(dev, screen) \
73  ((DevHasCursor(dev)) ? \
74   (miDCBufferPtr)dixLookupScreenPrivate(&dev->devPrivates, miDCDeviceKey, screen) : \
75   (miDCBufferPtr)dixLookupScreenPrivate(&GetMaster(dev, MASTER_POINTER)->devPrivates, miDCDeviceKey, screen))
76 
77 /*
78  * The core pointer buffer will point to the index of the virtual pointer
79  * in the pCursorBuffers array.
80  */
81 typedef struct {
82     CloseScreenProcPtr CloseScreen;
83     PixmapPtr sourceBits;       /* source bits */
84     PixmapPtr maskBits;         /* mask bits */
85     PicturePtr pPicture;
86     CursorPtr pCursor;
87 } miDCScreenRec, *miDCScreenPtr;
88 
89 #define miGetDCScreen(s)	((miDCScreenPtr)(dixLookupPrivate(&(s)->devPrivates, miDCScreenKey)))
90 
91 Bool
miDCInitialize(ScreenPtr pScreen,miPointerScreenFuncPtr screenFuncs)92 miDCInitialize(ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs)
93 {
94     miDCScreenPtr pScreenPriv;
95 
96     if (!dixRegisterPrivateKey(&miDCScreenKeyRec, PRIVATE_SCREEN, 0) ||
97         !dixRegisterScreenPrivateKey(&miDCDeviceKeyRec, pScreen, PRIVATE_DEVICE,
98                                      0))
99         return FALSE;
100 
101     pScreenPriv = calloc(1, sizeof(miDCScreenRec));
102     if (!pScreenPriv)
103         return FALSE;
104 
105     pScreenPriv->CloseScreen = pScreen->CloseScreen;
106     pScreen->CloseScreen = miDCCloseScreen;
107 
108     dixSetPrivate(&pScreen->devPrivates, miDCScreenKey, pScreenPriv);
109 
110     if (!miSpriteInitialize(pScreen, screenFuncs)) {
111         free((void *) pScreenPriv);
112         return FALSE;
113     }
114     return TRUE;
115 }
116 
117 static void
miDCSwitchScreenCursor(ScreenPtr pScreen,CursorPtr pCursor,PixmapPtr sourceBits,PixmapPtr maskBits,PicturePtr pPicture)118 miDCSwitchScreenCursor(ScreenPtr pScreen, CursorPtr pCursor, PixmapPtr sourceBits, PixmapPtr maskBits, PicturePtr pPicture)
119 {
120     miDCScreenPtr pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miDCScreenKey);
121 
122     if (pScreenPriv->sourceBits)
123         (*pScreen->DestroyPixmap)(pScreenPriv->sourceBits);
124     pScreenPriv->sourceBits = sourceBits;
125 
126     if (pScreenPriv->maskBits)
127         (*pScreen->DestroyPixmap)(pScreenPriv->maskBits);
128     pScreenPriv->maskBits = maskBits;
129 
130     if (pScreenPriv->pPicture)
131         FreePicture(pScreenPriv->pPicture, 0);
132     pScreenPriv->pPicture = pPicture;
133 
134     pScreenPriv->pCursor = pCursor;
135 }
136 
137 static Bool
miDCCloseScreen(ScreenPtr pScreen)138 miDCCloseScreen(ScreenPtr pScreen)
139 {
140     miDCScreenPtr pScreenPriv;
141 
142     pScreenPriv = (miDCScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
143                                                    miDCScreenKey);
144     pScreen->CloseScreen = pScreenPriv->CloseScreen;
145 
146     miDCSwitchScreenCursor(pScreen, NULL, NULL, NULL, NULL);
147     free((void *) pScreenPriv);
148     return (*pScreen->CloseScreen) (pScreen);
149 }
150 
151 Bool
miDCRealizeCursor(ScreenPtr pScreen,CursorPtr pCursor)152 miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
153 {
154     return TRUE;
155 }
156 
157 #define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win))
158 
159 static PicturePtr
miDCMakePicture(PicturePtr * ppPicture,DrawablePtr pDraw,WindowPtr pWin)160 miDCMakePicture(PicturePtr * ppPicture, DrawablePtr pDraw, WindowPtr pWin)
161 {
162     PictFormatPtr pFormat;
163     XID subwindow_mode = IncludeInferiors;
164     PicturePtr pPicture;
165     int error;
166 
167     pFormat = PictureWindowFormat(pWin);
168     if (!pFormat)
169         return 0;
170     pPicture = CreatePicture(0, pDraw, pFormat,
171                              CPSubwindowMode, &subwindow_mode,
172                              serverClient, &error);
173     *ppPicture = pPicture;
174     return pPicture;
175 }
176 
177 static Bool
miDCRealize(ScreenPtr pScreen,CursorPtr pCursor)178 miDCRealize(ScreenPtr pScreen, CursorPtr pCursor)
179 {
180     miDCScreenPtr pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miDCScreenKey);
181     GCPtr pGC;
182     ChangeGCVal gcvals;
183     PixmapPtr   sourceBits, maskBits;
184 
185     if (pScreenPriv->pCursor == pCursor)
186         return TRUE;
187 
188     if (pCursor->bits->argb) {
189         PixmapPtr pPixmap;
190         PictFormatPtr pFormat;
191         int error;
192         PicturePtr  pPicture;
193 
194         pFormat = PictureMatchFormat(pScreen, 32, PICT_a8r8g8b8);
195         if (!pFormat)
196             return FALSE;
197 
198         pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
199                                             pCursor->bits->height, 32,
200                                             CREATE_PIXMAP_USAGE_SCRATCH);
201         if (!pPixmap)
202             return FALSE;
203 
204         pGC = GetScratchGC(32, pScreen);
205         if (!pGC) {
206             (*pScreen->DestroyPixmap) (pPixmap);
207             return FALSE;
208         }
209         ValidateGC(&pPixmap->drawable, pGC);
210         (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32,
211                                0, 0, pCursor->bits->width,
212                                pCursor->bits->height,
213                                0, ZPixmap, (char *) pCursor->bits->argb);
214         FreeScratchGC(pGC);
215         pPicture = CreatePicture(0, &pPixmap->drawable,
216                                  pFormat, 0, 0, serverClient, &error);
217         (*pScreen->DestroyPixmap) (pPixmap);
218         if (!pPicture)
219             return FALSE;
220 
221         miDCSwitchScreenCursor(pScreen, pCursor, NULL, NULL, pPicture);
222         return TRUE;
223     }
224 
225     sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
226                                            pCursor->bits->height, 1, 0);
227     if (!sourceBits)
228         return FALSE;
229 
230     maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
231                                          pCursor->bits->height, 1, 0);
232     if (!maskBits) {
233         (*pScreen->DestroyPixmap) (sourceBits);
234         return FALSE;
235     }
236 
237     /* create the two sets of bits, clipping as appropriate */
238 
239     pGC = GetScratchGC(1, pScreen);
240     if (!pGC) {
241         (*pScreen->DestroyPixmap) (sourceBits);
242         (*pScreen->DestroyPixmap) (maskBits);
243         return FALSE;
244     }
245 
246     ValidateGC((DrawablePtr) sourceBits, pGC);
247     (*pGC->ops->PutImage) ((DrawablePtr) sourceBits, pGC, 1,
248                            0, 0, pCursor->bits->width, pCursor->bits->height,
249                            0, XYPixmap, (char *) pCursor->bits->source);
250     gcvals.val = GXand;
251     ChangeGC(NullClient, pGC, GCFunction, &gcvals);
252     ValidateGC((DrawablePtr) sourceBits, pGC);
253     (*pGC->ops->PutImage) ((DrawablePtr) sourceBits, pGC, 1,
254                            0, 0, pCursor->bits->width, pCursor->bits->height,
255                            0, XYPixmap, (char *) pCursor->bits->mask);
256 
257     /* mask bits -- pCursor->mask & ~pCursor->source */
258     gcvals.val = GXcopy;
259     ChangeGC(NullClient, pGC, GCFunction, &gcvals);
260     ValidateGC((DrawablePtr) maskBits, pGC);
261     (*pGC->ops->PutImage) ((DrawablePtr) maskBits, pGC, 1,
262                            0, 0, pCursor->bits->width, pCursor->bits->height,
263                            0, XYPixmap, (char *) pCursor->bits->mask);
264     gcvals.val = GXandInverted;
265     ChangeGC(NullClient, pGC, GCFunction, &gcvals);
266     ValidateGC((DrawablePtr) maskBits, pGC);
267     (*pGC->ops->PutImage) ((DrawablePtr) maskBits, pGC, 1,
268                            0, 0, pCursor->bits->width, pCursor->bits->height,
269                            0, XYPixmap, (char *) pCursor->bits->source);
270     FreeScratchGC(pGC);
271 
272     miDCSwitchScreenCursor(pScreen, pCursor, sourceBits, maskBits, NULL);
273     return TRUE;
274 }
275 
276 Bool
miDCUnrealizeCursor(ScreenPtr pScreen,CursorPtr pCursor)277 miDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
278 {
279     miDCScreenPtr pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miDCScreenKey);
280 
281     if (pCursor == pScreenPriv->pCursor)
282         miDCSwitchScreenCursor(pScreen, NULL, NULL, NULL, NULL);
283     return TRUE;
284 }
285 
286 static void
miDCPutBits(DrawablePtr pDrawable,GCPtr sourceGC,GCPtr maskGC,int x_org,int y_org,unsigned w,unsigned h,unsigned long source,unsigned long mask)287 miDCPutBits(DrawablePtr pDrawable,
288             GCPtr sourceGC,
289             GCPtr maskGC,
290             int x_org,
291             int y_org,
292             unsigned w, unsigned h, unsigned long source, unsigned long mask)
293 {
294     miDCScreenPtr pScreenPriv = dixLookupPrivate(&pDrawable->pScreen->devPrivates, miDCScreenKey);
295     ChangeGCVal gcval;
296     int x, y;
297 
298     if (sourceGC->fgPixel != source) {
299         gcval.val = source;
300         ChangeGC(NullClient, sourceGC, GCForeground, &gcval);
301     }
302     if (sourceGC->serialNumber != pDrawable->serialNumber)
303         ValidateGC(pDrawable, sourceGC);
304 
305     if (sourceGC->miTranslate) {
306         x = pDrawable->x + x_org;
307         y = pDrawable->y + y_org;
308     }
309     else {
310         x = x_org;
311         y = y_org;
312     }
313 
314     (*sourceGC->ops->PushPixels) (sourceGC, pScreenPriv->sourceBits, pDrawable, w, h,
315                                   x, y);
316     if (maskGC->fgPixel != mask) {
317         gcval.val = mask;
318         ChangeGC(NullClient, maskGC, GCForeground, &gcval);
319     }
320     if (maskGC->serialNumber != pDrawable->serialNumber)
321         ValidateGC(pDrawable, maskGC);
322 
323     if (maskGC->miTranslate) {
324         x = pDrawable->x + x_org;
325         y = pDrawable->y + y_org;
326     }
327     else {
328         x = x_org;
329         y = y_org;
330     }
331 
332     (*maskGC->ops->PushPixels) (maskGC, pScreenPriv->maskBits, pDrawable, w, h, x, y);
333 }
334 
335 static GCPtr
miDCMakeGC(WindowPtr pWin)336 miDCMakeGC(WindowPtr pWin)
337 {
338     GCPtr pGC;
339     int status;
340     XID gcvals[2];
341 
342     gcvals[0] = IncludeInferiors;
343     gcvals[1] = FALSE;
344     pGC = CreateGC((DrawablePtr) pWin,
345                    GCSubwindowMode | GCGraphicsExposures, gcvals, &status,
346                    (XID) 0, serverClient);
347     return pGC;
348 }
349 
350 Bool
miDCPutUpCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y,unsigned long source,unsigned long mask)351 miDCPutUpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor,
352                 int x, int y, unsigned long source, unsigned long mask)
353 {
354     miDCScreenPtr pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, miDCScreenKey);
355     miDCBufferPtr pBuffer;
356     WindowPtr pWin;
357 
358     if (!miDCRealize(pScreen, pCursor))
359         return FALSE;
360 
361     pWin = pScreen->root;
362     pBuffer = miGetDCDevice(pDev, pScreen);
363 
364     if (pScreenPriv->pPicture) {
365         if (!EnsurePicture(pBuffer->pRootPicture, &pWin->drawable, pWin))
366             return FALSE;
367         CompositePicture(PictOpOver,
368                          pScreenPriv->pPicture,
369                          NULL,
370                          pBuffer->pRootPicture,
371                          0, 0, 0, 0,
372                          x, y, pCursor->bits->width, pCursor->bits->height);
373     }
374     else
375     {
376         miDCPutBits((DrawablePtr) pWin,
377                     pBuffer->pSourceGC, pBuffer->pMaskGC,
378                     x, y, pCursor->bits->width, pCursor->bits->height,
379                     source, mask);
380     }
381     return TRUE;
382 }
383 
384 Bool
miDCSaveUnderCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y,int w,int h)385 miDCSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
386                     int x, int y, int w, int h)
387 {
388     miDCBufferPtr pBuffer;
389     PixmapPtr pSave;
390     WindowPtr pWin;
391     GCPtr pGC;
392 
393     pBuffer = miGetDCDevice(pDev, pScreen);
394 
395     pSave = pBuffer->pSave;
396     pWin = pScreen->root;
397     if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) {
398         if (pSave)
399             (*pScreen->DestroyPixmap) (pSave);
400         pBuffer->pSave = pSave =
401             (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth, 0);
402         if (!pSave)
403             return FALSE;
404     }
405 
406     pGC = pBuffer->pSaveGC;
407     if (pSave->drawable.serialNumber != pGC->serialNumber)
408         ValidateGC((DrawablePtr) pSave, pGC);
409     (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
410                            x, y, w, h, 0, 0);
411     return TRUE;
412 }
413 
414 Bool
miDCRestoreUnderCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y,int w,int h)415 miDCRestoreUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
416                        int x, int y, int w, int h)
417 {
418     miDCBufferPtr pBuffer;
419     PixmapPtr pSave;
420     WindowPtr pWin;
421     GCPtr pGC;
422 
423     pBuffer = miGetDCDevice(pDev, pScreen);
424     pSave = pBuffer->pSave;
425 
426     pWin = pScreen->root;
427     if (!pSave)
428         return FALSE;
429 
430     pGC = pBuffer->pRestoreGC;
431     if (pWin->drawable.serialNumber != pGC->serialNumber)
432         ValidateGC((DrawablePtr) pWin, pGC);
433     (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
434                            0, 0, w, h, x, y);
435     return TRUE;
436 }
437 
438 Bool
miDCDeviceInitialize(DeviceIntPtr pDev,ScreenPtr pScreen)439 miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
440 {
441     miDCBufferPtr pBuffer;
442     WindowPtr pWin;
443     int i;
444 
445     if (!DevHasCursor(pDev))
446         return TRUE;
447 
448     for (i = 0; i < screenInfo.numScreens; i++) {
449         pScreen = screenInfo.screens[i];
450 
451         pBuffer = calloc(1, sizeof(miDCBufferRec));
452         if (!pBuffer)
453             goto failure;
454 
455         dixSetScreenPrivate(&pDev->devPrivates, miDCDeviceKey, pScreen,
456                             pBuffer);
457         pWin = pScreen->root;
458 
459         pBuffer->pSourceGC = miDCMakeGC(pWin);
460         if (!pBuffer->pSourceGC)
461             goto failure;
462 
463         pBuffer->pMaskGC = miDCMakeGC(pWin);
464         if (!pBuffer->pMaskGC)
465             goto failure;
466 
467         pBuffer->pSaveGC = miDCMakeGC(pWin);
468         if (!pBuffer->pSaveGC)
469             goto failure;
470 
471         pBuffer->pRestoreGC = miDCMakeGC(pWin);
472         if (!pBuffer->pRestoreGC)
473             goto failure;
474 
475         pBuffer->pRootPicture = NULL;
476 
477         /* (re)allocated lazily depending on the cursor size */
478         pBuffer->pSave = NULL;
479     }
480 
481     return TRUE;
482 
483  failure:
484 
485     miDCDeviceCleanup(pDev, pScreen);
486 
487     return FALSE;
488 }
489 
490 void
miDCDeviceCleanup(DeviceIntPtr pDev,ScreenPtr pScreen)491 miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
492 {
493     miDCBufferPtr pBuffer;
494     int i;
495 
496     if (DevHasCursor(pDev)) {
497         for (i = 0; i < screenInfo.numScreens; i++) {
498             pScreen = screenInfo.screens[i];
499 
500             pBuffer = miGetDCDevice(pDev, pScreen);
501 
502             if (pBuffer) {
503                 if (pBuffer->pSourceGC)
504                     FreeGC(pBuffer->pSourceGC, (GContext) 0);
505                 if (pBuffer->pMaskGC)
506                     FreeGC(pBuffer->pMaskGC, (GContext) 0);
507                 if (pBuffer->pSaveGC)
508                     FreeGC(pBuffer->pSaveGC, (GContext) 0);
509                 if (pBuffer->pRestoreGC)
510                     FreeGC(pBuffer->pRestoreGC, (GContext) 0);
511 
512                 /* If a pRootPicture was allocated for a root window, it
513                  * is freed when that root window is destroyed, so don't
514                  * free it again here. */
515 
516                 if (pBuffer->pSave)
517                     (*pScreen->DestroyPixmap) (pBuffer->pSave);
518 
519                 free(pBuffer);
520                 dixSetScreenPrivate(&pDev->devPrivates, miDCDeviceKey, pScreen,
521                                     NULL);
522             }
523         }
524     }
525 }
526