midispcur.c revision 35c4bbdf
1/*
2 * midispcur.c
3 *
4 * machine independent cursor display routines
5 */
6
7/*
8
9Copyright 1989, 1998  The Open Group
10
11Permission to use, copy, modify, distribute, and sell this software and its
12documentation for any purpose is hereby granted without fee, provided that
13the above copyright notice appear in all copies and that both that
14copyright notice and this permission notice appear in supporting
15documentation.
16
17The above copyright notice and this permission notice shall be included in
18all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
23OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
24AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27Except as contained in this notice, the name of The Open Group shall not be
28used in advertising or otherwise to promote the sale, use or other dealings
29in 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 */
54static DevPrivateKeyRec miDCScreenKeyRec;
55
56#define miDCScreenKey (&miDCScreenKeyRec)
57
58static DevScreenPrivateKeyRec miDCDeviceKeyRec;
59
60#define miDCDeviceKey (&miDCDeviceKeyRec)
61
62static Bool miDCCloseScreen(ScreenPtr pScreen);
63
64/* per device private data */
65typedef 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 */
81typedef 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
91Bool
92miDCInitialize(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
117static void
118miDCSwitchScreenCursor(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
137static Bool
138miDCCloseScreen(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
151Bool
152miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
153{
154    return TRUE;
155}
156
157#define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win))
158
159static PicturePtr
160miDCMakePicture(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
177static Bool
178miDCRealize(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
276Bool
277miDCUnrealizeCursor(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
286static void
287miDCPutBits(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
335static GCPtr
336miDCMakeGC(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
350Bool
351miDCPutUpCursor(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
384Bool
385miDCSaveUnderCursor(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
414Bool
415miDCRestoreUnderCursor(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
438Bool
439miDCDeviceInitialize(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
490void
491miDCDeviceCleanup(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