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