1 /**************************************************************
2 *
3 * Xplugin cursor support
4 *
5 * Copyright (c) 2001 Torrey T. Lyons and Greg Parker.
6 * Copyright (c) 2002 Apple Computer, Inc.
7 * All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the sale,
29 * use or other dealings in this Software without prior written authorization.
30 */
31
32 #include "sanitizedCarbon.h"
33
34 #ifdef HAVE_DIX_CONFIG_H
35 #include <dix-config.h>
36 #endif
37
38 #include "quartz.h"
39 #include "xpr.h"
40 #include "darwinEvents.h"
41 #include <Xplugin.h>
42
43 #include "mi.h"
44 #include "scrnintstr.h"
45 #include "cursorstr.h"
46 #include "mipointrst.h"
47 #include "windowstr.h"
48 #include "globals.h"
49 #include "servermd.h"
50 #include "dixevents.h"
51 #include "x-hash.h"
52
53 typedef struct {
54 int cursorVisible;
55 QueryBestSizeProcPtr QueryBestSize;
56 miPointerSpriteFuncPtr spriteFuncs;
57 } QuartzCursorScreenRec, *QuartzCursorScreenPtr;
58
59 static DevPrivateKeyRec darwinCursorScreenKeyRec;
60 #define darwinCursorScreenKey (&darwinCursorScreenKeyRec)
61
62 #define CURSOR_PRIV(pScreen) ((QuartzCursorScreenPtr) \
63 dixLookupPrivate(&pScreen->devPrivates, \
64 darwinCursorScreenKey))
65
66 static Bool
load_cursor(CursorPtr src,int screen)67 load_cursor(CursorPtr src, int screen)
68 {
69 uint32_t *data;
70 Bool free_data = FALSE;
71 uint32_t rowbytes;
72 int width, height;
73 int hot_x, hot_y;
74
75 uint32_t fg_color, bg_color;
76 uint8_t *srow, *sptr;
77 uint8_t *mrow, *mptr;
78 uint32_t *drow, *dptr;
79 unsigned xcount, ycount;
80
81 xp_error err;
82
83 width = src->bits->width;
84 height = src->bits->height;
85 hot_x = src->bits->xhot;
86 hot_y = src->bits->yhot;
87
88 if (src->bits->argb != NULL) {
89 #if BITMAP_BIT_ORDER == MSBFirst
90 rowbytes = src->bits->width * sizeof(CARD32);
91 data = (uint32_t *)src->bits->argb;
92 #else
93 const uint32_t *be_data = (uint32_t *)src->bits->argb;
94 unsigned i;
95 rowbytes = src->bits->width * sizeof(CARD32);
96 data = malloc(rowbytes * src->bits->height);
97 free_data = TRUE;
98 if (!data) {
99 FatalError("Failed to allocate memory in %s\n", __func__);
100 }
101 for (i = 0; i < (src->bits->width * src->bits->height); i++)
102 data[i] = ntohl(be_data[i]);
103 #endif
104 }
105 else
106 {
107 fg_color = 0xFF00 | (src->foreRed >> 8);
108 fg_color <<= 16;
109 fg_color |= src->foreGreen & 0xFF00;
110 fg_color |= src->foreBlue >> 8;
111
112 bg_color = 0xFF00 | (src->backRed >> 8);
113 bg_color <<= 16;
114 bg_color |= src->backGreen & 0xFF00;
115 bg_color |= src->backBlue >> 8;
116
117 fg_color = htonl(fg_color);
118 bg_color = htonl(bg_color);
119
120 /* round up to 8 pixel boundary so we can convert whole bytes */
121 rowbytes = ((src->bits->width * 4) + 31) & ~31;
122 data = malloc(rowbytes * src->bits->height);
123 free_data = TRUE;
124 if (!data) {
125 FatalError("Failed to allocate memory in %s\n", __func__);
126 }
127
128 if (!src->bits->emptyMask) {
129 ycount = src->bits->height;
130 srow = src->bits->source;
131 mrow = src->bits->mask;
132 drow = data;
133
134 while (ycount-- > 0)
135 {
136 xcount = bits_to_bytes(src->bits->width);
137 sptr = srow;
138 mptr = mrow;
139 dptr = drow;
140
141 while (xcount-- > 0)
142 {
143 uint8_t s, m;
144 int i;
145
146 s = *sptr++;
147 m = *mptr++;
148 for (i = 0; i < 8; i++) {
149 #if BITMAP_BIT_ORDER == MSBFirst
150 if (m & 128)
151 *dptr++ = (s & 128) ? fg_color : bg_color;
152 else
153 *dptr++ = 0;
154 s <<= 1;
155 m <<= 1;
156 #else
157 if (m & 1)
158 *dptr++ = (s & 1) ? fg_color : bg_color;
159 else
160 *dptr++ = 0;
161 s >>= 1;
162 m >>= 1;
163 #endif
164 }
165 }
166
167 srow += BitmapBytePad(src->bits->width);
168 mrow += BitmapBytePad(src->bits->width);
169 drow = (uint32_t *)((char *)drow + rowbytes);
170 }
171 }
172 else {
173 memset(data, 0, src->bits->height * rowbytes);
174 }
175 }
176
177 err = xp_set_cursor(width, height, hot_x, hot_y, data, rowbytes);
178 if (free_data)
179 free(data);
180 return err == Success;
181 }
182
183 /*
184 ===========================================================================
185
186 Pointer sprite functions
187
188 ===========================================================================
189 */
190
191 /*
192 * QuartzRealizeCursor
193 * Convert the X cursor representation to native format if possible.
194 */
195 static Bool
QuartzRealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)196 QuartzRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
197 {
198 if (pCursor == NULL || pCursor->bits == NULL)
199 return FALSE;
200
201 /* FIXME: cache ARGB8888 representation? */
202
203 return TRUE;
204 }
205
206 /*
207 * QuartzUnrealizeCursor
208 * Free the storage space associated with a realized cursor.
209 */
210 static Bool
QuartzUnrealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)211 QuartzUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
212 {
213 return TRUE;
214 }
215
216 /*
217 * QuartzSetCursor
218 * Set the cursor sprite and position.
219 */
220 static void
QuartzSetCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)221 QuartzSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor,
222 int x,
223 int y)
224 {
225 QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
226
227 if (!XQuartzServerVisible)
228 return;
229
230 if (pCursor == NULL) {
231 if (ScreenPriv->cursorVisible) {
232 xp_hide_cursor();
233 ScreenPriv->cursorVisible = FALSE;
234 }
235 }
236 else {
237 load_cursor(pCursor, pScreen->myNum);
238
239 if (!ScreenPriv->cursorVisible) {
240 xp_show_cursor();
241 ScreenPriv->cursorVisible = TRUE;
242 }
243 }
244 }
245
246 /*
247 * QuartzMoveCursor
248 * Move the cursor. This is a noop for us.
249 */
250 static void
QuartzMoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)251 QuartzMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
252 {}
253
254 /*
255 ===========================================================================
256
257 Pointer screen functions
258
259 ===========================================================================
260 */
261
262 /*
263 * QuartzCursorOffScreen
264 */
265 static Bool
QuartzCursorOffScreen(ScreenPtr * pScreen,int * x,int * y)266 QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
267 {
268 return FALSE;
269 }
270
271 /*
272 * QuartzCrossScreen
273 */
274 static void
QuartzCrossScreen(ScreenPtr pScreen,Bool entering)275 QuartzCrossScreen(ScreenPtr pScreen, Bool entering)
276 {
277 return;
278 }
279
280 /*
281 * QuartzWarpCursor
282 * Change the cursor position without generating an event or motion history.
283 * The input coordinates (x,y) are in pScreen-local X11 coordinates.
284 *
285 */
286 static void
QuartzWarpCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)287 QuartzWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
288 {
289 if (XQuartzServerVisible) {
290 int sx, sy;
291
292 sx = pScreen->x + darwinMainScreenX;
293 sy = pScreen->y + darwinMainScreenY;
294
295 CGWarpMouseCursorPosition(CGPointMake(sx + x, sy + y));
296 }
297
298 miPointerWarpCursor(pDev, pScreen, x, y);
299 miPointerUpdateSprite(pDev);
300 }
301
302 static miPointerScreenFuncRec quartzScreenFuncsRec = {
303 QuartzCursorOffScreen,
304 QuartzCrossScreen,
305 QuartzWarpCursor,
306 };
307
308 /*
309 ===========================================================================
310
311 Other screen functions
312
313 ===========================================================================
314 */
315
316 /*
317 * QuartzCursorQueryBestSize
318 * Handle queries for best cursor size
319 */
320 static void
QuartzCursorQueryBestSize(int class,unsigned short * width,unsigned short * height,ScreenPtr pScreen)321 QuartzCursorQueryBestSize(int class, unsigned short *width,
322 unsigned short *height, ScreenPtr pScreen)
323 {
324 QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
325
326 if (class == CursorShape) {
327 /* FIXME: query window server? */
328 *width = 32;
329 *height = 32;
330 }
331 else {
332 (*ScreenPriv->QueryBestSize)(class, width, height, pScreen);
333 }
334 }
335
336 /*
337 * QuartzInitCursor
338 * Initialize cursor support
339 */
340 Bool
QuartzInitCursor(ScreenPtr pScreen)341 QuartzInitCursor(ScreenPtr pScreen)
342 {
343 QuartzCursorScreenPtr ScreenPriv;
344 miPointerScreenPtr PointPriv;
345
346 /* initialize software cursor handling (always needed as backup) */
347 if (!miDCInitialize(pScreen, &quartzScreenFuncsRec))
348 return FALSE;
349
350 if (!dixRegisterPrivateKey(&darwinCursorScreenKeyRec, PRIVATE_SCREEN, 0))
351 return FALSE;
352
353 ScreenPriv = calloc(1, sizeof(QuartzCursorScreenRec));
354 if (ScreenPriv == NULL)
355 return FALSE;
356
357 /* CURSOR_PRIV(pScreen) = ScreenPriv; */
358 dixSetPrivate(&pScreen->devPrivates, darwinCursorScreenKey, ScreenPriv);
359
360 /* override some screen procedures */
361 ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
362 pScreen->QueryBestSize = QuartzCursorQueryBestSize;
363
364 PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
365
366 ScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
367
368 PointPriv->spriteFuncs->RealizeCursor = QuartzRealizeCursor;
369 PointPriv->spriteFuncs->UnrealizeCursor = QuartzUnrealizeCursor;
370 PointPriv->spriteFuncs->SetCursor = QuartzSetCursor;
371 PointPriv->spriteFuncs->MoveCursor = QuartzMoveCursor;
372
373 ScreenPriv->cursorVisible = TRUE;
374 return TRUE;
375 }
376
377 /*
378 * QuartzSuspendXCursor
379 * X server is hiding. Restore the Aqua cursor.
380 */
381 void
QuartzSuspendXCursor(ScreenPtr pScreen)382 QuartzSuspendXCursor(ScreenPtr pScreen)
383 {}
384
385 /*
386 * QuartzResumeXCursor
387 * X server is showing. Restore the X cursor.
388 */
389 void
QuartzResumeXCursor(ScreenPtr pScreen)390 QuartzResumeXCursor(ScreenPtr pScreen)
391 {
392 WindowPtr pWin;
393 CursorPtr pCursor;
394
395 /* TODO: Tablet? */
396
397 pWin = GetSpriteWindow(darwinPointer);
398 if (pWin->drawable.pScreen != pScreen)
399 return;
400
401 pCursor = GetSpriteCursor(darwinPointer);
402 if (pCursor == NULL)
403 return;
404
405 QuartzSetCursor(darwinPointer, pScreen, pCursor, /* x */ 0, /* y */ 0);
406 }
407