Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | |
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 | #ifdef ARGB_CURSOR | |
89 | if (src->bits->argb != NULL) { | |
90 | #if BITMAP_BIT_ORDER == MSBFirst | |
91 | rowbytes = src->bits->width * sizeof(CARD32); | |
92 | data = (uint32_t *)src->bits->argb; | |
93 | #else | |
94 | const uint32_t *be_data = (uint32_t *)src->bits->argb; | |
95 | unsigned i; | |
96 | rowbytes = src->bits->width * sizeof(CARD32); | |
97 | data = malloc(rowbytes * src->bits->height); | |
98 | free_data = TRUE; | |
99 | if (!data) { | |
100 | FatalError("Failed to allocate memory in %s\n", __func__); | |
101 | } | |
102 | for (i = 0; i < (src->bits->width * src->bits->height); i++) | |
103 | data[i] = ntohl(be_data[i]); | |
104 | #endif | |
105 | } | |
106 | else | |
107 | #endif | |
108 | { | |
109 | fg_color = 0xFF00 | (src->foreRed >> 8); | |
110 | fg_color <<= 16; | |
111 | fg_color |= src->foreGreen & 0xFF00; | |
112 | fg_color |= src->foreBlue >> 8; | |
113 | ||
114 | bg_color = 0xFF00 | (src->backRed >> 8); | |
115 | bg_color <<= 16; | |
116 | bg_color |= src->backGreen & 0xFF00; | |
117 | bg_color |= src->backBlue >> 8; | |
118 | ||
119 | fg_color = htonl(fg_color); | |
120 | bg_color = htonl(bg_color); | |
121 | ||
122 | /* round up to 8 pixel boundary so we can convert whole bytes */ | |
123 | rowbytes = ((src->bits->width * 4) + 31) & ~31; | |
124 | data = malloc(rowbytes * src->bits->height); | |
125 | free_data = TRUE; | |
126 | if (!data) { | |
127 | FatalError("Failed to allocate memory in %s\n", __func__); | |
128 | } | |
129 | ||
130 | if (!src->bits->emptyMask) { | |
131 | ycount = src->bits->height; | |
132 | srow = src->bits->source; | |
133 | mrow = src->bits->mask; | |
134 | drow = data; | |
135 | ||
136 | while (ycount-- > 0) | |
137 | { | |
138 | xcount = bits_to_bytes(src->bits->width); | |
139 | sptr = srow; | |
140 | mptr = mrow; | |
141 | dptr = drow; | |
142 | ||
143 | while (xcount-- > 0) | |
144 | { | |
145 | uint8_t s, m; | |
146 | int i; | |
147 | ||
148 | s = *sptr++; | |
149 | m = *mptr++; | |
150 | for (i = 0; i < 8; i++) { | |
151 | #if BITMAP_BIT_ORDER == MSBFirst | |
152 | if (m & 128) | |
153 | *dptr++ = (s & 128) ? fg_color : bg_color; | |
154 | else | |
155 | *dptr++ = 0; | |
156 | s <<= 1; | |
157 | m <<= 1; | |
158 | #else | |
159 | if (m & 1) | |
160 | *dptr++ = (s & 1) ? fg_color : bg_color; | |
161 | else | |
162 | *dptr++ = 0; | |
163 | s >>= 1; | |
164 | m >>= 1; | |
165 | #endif | |
166 | } | |
167 | } | |
168 | ||
169 | srow += BitmapBytePad(src->bits->width); | |
170 | mrow += BitmapBytePad(src->bits->width); | |
171 | drow = (uint32_t *)((char *)drow + rowbytes); | |
172 | } | |
173 | } | |
174 | else { | |
175 | memset(data, 0, src->bits->height * rowbytes); | |
176 | } | |
177 | } | |
178 | ||
179 | err = xp_set_cursor(width, height, hot_x, hot_y, data, rowbytes); | |
180 | if (free_data) | |
181 | free(data); | |
182 | return err == Success; | |
183 | } | |
184 | ||
185 | /* | |
186 | =========================================================================== | |
187 | ||
188 | Pointer sprite functions | |
189 | ||
190 | =========================================================================== | |
191 | */ | |
192 | ||
193 | /* | |
194 | * QuartzRealizeCursor | |
195 | * Convert the X cursor representation to native format if possible. | |
196 | */ | |
197 | static Bool | |
198 | QuartzRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) | |
199 | { | |
200 | if (pCursor == NULL || pCursor->bits == NULL) | |
201 | return FALSE; | |
202 | ||
203 | /* FIXME: cache ARGB8888 representation? */ | |
204 | ||
205 | return TRUE; | |
206 | } | |
207 | ||
208 | /* | |
209 | * QuartzUnrealizeCursor | |
210 | * Free the storage space associated with a realized cursor. | |
211 | */ | |
212 | static Bool | |
213 | QuartzUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) | |
214 | { | |
215 | return TRUE; | |
216 | } | |
217 | ||
218 | /* | |
219 | * QuartzSetCursor | |
220 | * Set the cursor sprite and position. | |
221 | */ | |
222 | static void | |
223 | QuartzSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, | |
224 | int x, | |
225 | int y) | |
226 | { | |
227 | QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); | |
228 | ||
229 | if (!XQuartzServerVisible) | |
230 | return; | |
231 | ||
232 | if (pCursor == NULL) { | |
233 | if (ScreenPriv->cursorVisible) { | |
234 | xp_hide_cursor(); | |
235 | ScreenPriv->cursorVisible = FALSE; | |
236 | } | |
237 | } | |
238 | else { | |
239 | load_cursor(pCursor, pScreen->myNum); | |
240 | ||
241 | if (!ScreenPriv->cursorVisible) { | |
242 | xp_show_cursor(); | |
243 | ScreenPriv->cursorVisible = TRUE; | |
244 | } | |
245 | } | |
246 | } | |
247 | ||
248 | /* | |
249 | * QuartzMoveCursor | |
250 | * Move the cursor. This is a noop for us. | |
251 | */ | |
252 | static void | |
253 | QuartzMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) | |
254 | {} | |
255 | ||
256 | /* | |
257 | =========================================================================== | |
258 | ||
259 | Pointer screen functions | |
260 | ||
261 | =========================================================================== | |
262 | */ | |
263 | ||
264 | /* | |
265 | * QuartzCursorOffScreen | |
266 | */ | |
267 | static Bool | |
268 | QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y) | |
269 | { | |
270 | return FALSE; | |
271 | } | |
272 | ||
273 | /* | |
274 | * QuartzCrossScreen | |
275 | */ | |
276 | static void | |
277 | QuartzCrossScreen(ScreenPtr pScreen, Bool entering) | |
278 | { | |
279 | return; | |
280 | } | |
281 | ||
282 | /* | |
283 | * QuartzWarpCursor | |
284 | * Change the cursor position without generating an event or motion history. | |
285 | * The input coordinates (x,y) are in pScreen-local X11 coordinates. | |
286 | * | |
287 | */ | |
288 | static void | |
289 | QuartzWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) | |
290 | { | |
291 | if (XQuartzServerVisible) { | |
292 | int sx, sy; | |
293 | ||
294 | sx = pScreen->x + darwinMainScreenX; | |
295 | sy = pScreen->y + darwinMainScreenY; | |
296 | ||
297 | CGWarpMouseCursorPosition(CGPointMake(sx + x, sy + y)); | |
298 | } | |
299 | ||
300 | miPointerWarpCursor(pDev, pScreen, x, y); | |
301 | miPointerUpdateSprite(pDev); | |
302 | } | |
303 | ||
304 | static miPointerScreenFuncRec quartzScreenFuncsRec = { | |
305 | QuartzCursorOffScreen, | |
306 | QuartzCrossScreen, | |
307 | QuartzWarpCursor, | |
308 | }; | |
309 | ||
310 | /* | |
311 | =========================================================================== | |
312 | ||
313 | Other screen functions | |
314 | ||
315 | =========================================================================== | |
316 | */ | |
317 | ||
318 | /* | |
319 | * QuartzCursorQueryBestSize | |
320 | * Handle queries for best cursor size | |
321 | */ | |
322 | static void | |
323 | QuartzCursorQueryBestSize(int class, unsigned short *width, | |
324 | unsigned short *height, ScreenPtr pScreen) | |
325 | { | |
326 | QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); | |
327 | ||
328 | if (class == CursorShape) { | |
329 | /* FIXME: query window server? */ | |
330 | *width = 32; | |
331 | *height = 32; | |
332 | } | |
333 | else { | |
334 | (*ScreenPriv->QueryBestSize)(class, width, height, pScreen); | |
335 | } | |
336 | } | |
337 | ||
338 | /* | |
339 | * QuartzInitCursor | |
340 | * Initialize cursor support | |
341 | */ | |
342 | Bool | |
343 | QuartzInitCursor(ScreenPtr pScreen) | |
344 | { | |
345 | QuartzCursorScreenPtr ScreenPriv; | |
346 | miPointerScreenPtr PointPriv; | |
347 | ||
348 | /* initialize software cursor handling (always needed as backup) */ | |
349 | if (!miDCInitialize(pScreen, &quartzScreenFuncsRec)) | |
350 | return FALSE; | |
351 | ||
352 | if (!dixRegisterPrivateKey(&darwinCursorScreenKeyRec, PRIVATE_SCREEN, 0)) | |
353 | return FALSE; | |
354 | ||
355 | ScreenPriv = calloc(1, sizeof(QuartzCursorScreenRec)); | |
356 | if (ScreenPriv == NULL) | |
357 | return FALSE; | |
358 | ||
359 | /* CURSOR_PRIV(pScreen) = ScreenPriv; */ | |
360 | dixSetPrivate(&pScreen->devPrivates, darwinCursorScreenKey, ScreenPriv); | |
361 | ||
362 | /* override some screen procedures */ | |
363 | ScreenPriv->QueryBestSize = pScreen->QueryBestSize; | |
364 | pScreen->QueryBestSize = QuartzCursorQueryBestSize; | |
365 | ||
366 | PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); | |
367 | ||
368 | ScreenPriv->spriteFuncs = PointPriv->spriteFuncs; | |
369 | ||
370 | PointPriv->spriteFuncs->RealizeCursor = QuartzRealizeCursor; | |
371 | PointPriv->spriteFuncs->UnrealizeCursor = QuartzUnrealizeCursor; | |
372 | PointPriv->spriteFuncs->SetCursor = QuartzSetCursor; | |
373 | PointPriv->spriteFuncs->MoveCursor = QuartzMoveCursor; | |
374 | ||
375 | ScreenPriv->cursorVisible = TRUE; | |
376 | return TRUE; | |
377 | } | |
378 | ||
379 | /* | |
380 | * QuartzSuspendXCursor | |
381 | * X server is hiding. Restore the Aqua cursor. | |
382 | */ | |
383 | void | |
384 | QuartzSuspendXCursor(ScreenPtr pScreen) | |
385 | {} | |
386 | ||
387 | /* | |
388 | * QuartzResumeXCursor | |
389 | * X server is showing. Restore the X cursor. | |
390 | */ | |
391 | void | |
392 | QuartzResumeXCursor(ScreenPtr pScreen) | |
393 | { | |
394 | WindowPtr pWin; | |
395 | CursorPtr pCursor; | |
396 | ||
397 | /* TODO: Tablet? */ | |
398 | ||
399 | pWin = GetSpriteWindow(darwinPointer); | |
400 | if (pWin->drawable.pScreen != pScreen) | |
401 | return; | |
402 | ||
403 | pCursor = GetSpriteCursor(darwinPointer); | |
404 | if (pCursor == NULL) | |
405 | return; | |
406 | ||
407 | QuartzSetCursor(darwinPointer, pScreen, pCursor, /* x */ 0, /* y */ 0); | |
408 | } |