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