First import
[xorg_rtime.git] / xorg-server-1.4 / hw / darwin / quartz / quartzCursor.c
blob6ed6a76773a33056ac4e18f4b2902fb7f1167b5a
1 /**************************************************************
3 * Support for using the Quartz Window Manager cursor
5 **************************************************************/
6 /*
7 * Copyright (c) 2001-2003 Torrey T. Lyons and Greg Parker.
8 * All Rights Reserved.
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
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
23 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
28 * Except as contained in this notice, the name(s) of the above copyright
29 * holders shall not be used in advertising or otherwise to promote the sale,
30 * use or other dealings in this Software without prior written authorization.
33 #ifdef HAVE_XORG_CONFIG_H
34 #include <xorg-config.h>
35 #endif
36 #include "quartzCommon.h"
37 #include "quartzCursor.h"
38 #include "darwin.h"
40 #include <pthread.h>
42 #include "mi.h"
43 #include "scrnintstr.h"
44 #include "cursorstr.h"
45 #include "mipointrst.h"
46 #include "globals.h"
48 // Size of the QuickDraw cursor
49 #define CURSORWIDTH 16
50 #define CURSORHEIGHT 16
52 typedef struct {
53 int qdCursorMode;
54 int qdCursorVisible;
55 int useQDCursor;
56 QueryBestSizeProcPtr QueryBestSize;
57 miPointerSpriteFuncPtr spriteFuncs;
58 } QuartzCursorScreenRec, *QuartzCursorScreenPtr;
60 static int darwinCursorScreenIndex = -1;
61 static unsigned long darwinCursorGeneration = 0;
62 static CursorPtr quartzLatentCursor = NULL;
63 static QD_Cursor gQDArrow; // QuickDraw arrow cursor
65 // Cursor for the main thread to set (NULL = arrow cursor).
66 static CCrsrHandle currentCursor = NULL;
67 static pthread_mutex_t cursorMutex;
68 static pthread_cond_t cursorCondition;
70 #define CURSOR_PRIV(pScreen) \
71 ((QuartzCursorScreenPtr)pScreen->devPrivates[darwinCursorScreenIndex].ptr)
73 #define HIDE_QD_CURSOR(pScreen, visible) \
74 if (visible) { \
75 int ix; \
76 for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) { \
77 CGDisplayHideCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]); \
78 } \
79 visible = FALSE; \
80 } ((void)0)
82 #define SHOW_QD_CURSOR(pScreen, visible) \
83 { \
84 int ix; \
85 for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) { \
86 CGDisplayShowCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]); \
87 } \
88 visible = TRUE; \
89 } ((void)0)
91 #define CHANGE_QD_CURSOR(cursorH) \
92 if (!quartzServerQuitting) { \
93 /* Acquire lock and tell the main thread to change cursor */ \
94 pthread_mutex_lock(&cursorMutex); \
95 currentCursor = (CCrsrHandle) (cursorH); \
96 #ifndef INXQUARTZ
97 QuartzMessageMainThread(kQuartzCursorUpdate, NULL, 0); \
98 #endif
100 /* Wait for the main thread to change the cursor */ \
101 pthread_cond_wait(&cursorCondition, &cursorMutex); \
102 pthread_mutex_unlock(&cursorMutex); \
103 } ((void)0)
107 * MakeQDCursor helpers: CTAB_ENTER, interleave
110 // Add a color entry to a ctab
111 #define CTAB_ENTER(ctab, index, r, g, b) \
112 ctab->ctTable[index].value = index; \
113 ctab->ctTable[index].rgb.red = r; \
114 ctab->ctTable[index].rgb.green = g; \
115 ctab->ctTable[index].rgb.blue = b
117 // Make an unsigned short by interleaving the bits of bytes c1 and c2.
118 // High bit of c1 is first; low bit of c2 is last.
119 // Interleave is a built-in INTERCAL operator.
120 static unsigned short
121 interleave(
122 unsigned char c1,
123 unsigned char c2 )
125 return
126 ((c1 & 0x80) << 8) | ((c2 & 0x80) << 7) |
127 ((c1 & 0x40) << 7) | ((c2 & 0x40) << 6) |
128 ((c1 & 0x20) << 6) | ((c2 & 0x20) << 5) |
129 ((c1 & 0x10) << 5) | ((c2 & 0x10) << 4) |
130 ((c1 & 0x08) << 4) | ((c2 & 0x08) << 3) |
131 ((c1 & 0x04) << 3) | ((c2 & 0x04) << 2) |
132 ((c1 & 0x02) << 2) | ((c2 & 0x02) << 1) |
133 ((c1 & 0x01) << 1) | ((c2 & 0x01) << 0) ;
137 * MakeQDCursor
138 * Make a QuickDraw color cursor from the given X11 cursor.
139 * Warning: This code is nasty. Color cursors were meant to be read
140 * from resources; constructing the structures programmatically is messy.
143 QuickDraw cursor representation:
144 Our color cursor is a 2 bit per pixel pixmap.
145 Each pixel's bits are (source<<1 | mask) from the original X cursor pixel.
146 The cursor's color table maps the colors like this:
147 (2-bit value | X result | colortable | Mac result)
148 00 | transparent | white | transparent (white outside mask)
149 01 | back color | back color | back color
150 10 | undefined | black | invert background (just for fun)
151 11 | fore color | fore color | fore color
153 static CCrsrHandle
154 MakeQDCursor(
155 CursorPtr pCursor )
157 CCrsrHandle result;
158 CCrsrPtr curs;
159 int i, w, h;
160 unsigned short rowMask;
161 PixMap *pix;
162 ColorTable *ctab;
163 unsigned short *image;
165 result = (CCrsrHandle) NewHandleClear(sizeof(CCrsr));
166 if (!result) return NULL;
167 HLock((Handle)result);
168 curs = *result;
170 // Initialize CCrsr
171 curs->crsrType = 0x8001; // 0x8000 = b&w, 0x8001 = color
172 curs->crsrMap = (PixMapHandle) NewHandleClear(sizeof(PixMap));
173 if (!curs->crsrMap) goto pixAllocFailed;
174 HLock((Handle)curs->crsrMap);
175 pix = *curs->crsrMap;
176 curs->crsrData = NULL; // raw cursor image data (set below)
177 curs->crsrXData = NULL; // QD's processed data
178 curs->crsrXValid = 0; // zero means QD must re-process cursor data
179 curs->crsrXHandle = NULL; // reserved
180 memset(curs->crsr1Data, 0, CURSORWIDTH*CURSORHEIGHT/8); // b&w data
181 memset(curs->crsrMask, 0, CURSORWIDTH*CURSORHEIGHT/8); // b&w & color mask
182 curs->crsrHotSpot.h = min(CURSORWIDTH, pCursor->bits->xhot); // hot spot
183 curs->crsrHotSpot.v = min(CURSORHEIGHT, pCursor->bits->yhot); // hot spot
184 curs->crsrXTable = 0; // reserved
185 curs->crsrID = GetCTSeed(); // unique ID from Color Manager
187 // Set the b&w data and mask
188 w = min(pCursor->bits->width, CURSORWIDTH);
189 h = min(pCursor->bits->height, CURSORHEIGHT);
190 rowMask = ~((1 << (CURSORWIDTH - w)) - 1);
191 for (i = 0; i < h; i++) {
192 curs->crsr1Data[i] = rowMask &
193 ((pCursor->bits->source[i*4]<<8) | pCursor->bits->source[i*4+1]);
194 curs->crsrMask[i] = rowMask &
195 ((pCursor->bits->mask[i*4]<<8) | pCursor->bits->mask[i*4+1]);
198 // Set the color data and mask
199 // crsrMap: defines bit depth and size and colortable only
200 pix->rowBytes = (CURSORWIDTH * 2 / 8) | 0x8000; // last bit on means PixMap
201 SetRect(&pix->bounds, 0, 0, CURSORWIDTH, CURSORHEIGHT); // see TN 1020
202 pix->pixelSize = 2;
203 pix->cmpCount = 1;
204 pix->cmpSize = 2;
205 // pix->pmTable set below
207 // crsrData is the pixel data. crsrMap's baseAddr is not used.
208 curs->crsrData = NewHandleClear(CURSORWIDTH*CURSORHEIGHT * 2 / 8);
209 if (!curs->crsrData) goto imageAllocFailed;
210 HLock((Handle)curs->crsrData);
211 image = (unsigned short *) *curs->crsrData;
212 // Pixel data is just 1-bit data and mask interleaved (see above)
213 for (i = 0; i < h; i++) {
214 unsigned char s, m;
215 s = pCursor->bits->source[i*4] & (rowMask >> 8);
216 m = pCursor->bits->mask[i*4] & (rowMask >> 8);
217 image[2*i] = interleave(s, m);
218 s = pCursor->bits->source[i*4+1] & (rowMask & 0x00ff);
219 m = pCursor->bits->mask[i*4+1] & (rowMask & 0x00ff);
220 image[2*i+1] = interleave(s, m);
223 // Build the color table (entries described above)
224 // NewPixMap allocates a color table handle.
225 pix->pmTable = (CTabHandle) NewHandleClear(sizeof(ColorTable) + 3
226 * sizeof(ColorSpec));
227 if (!pix->pmTable) goto ctabAllocFailed;
228 HLock((Handle)pix->pmTable);
229 ctab = *pix->pmTable;
230 ctab->ctSeed = GetCTSeed();
231 ctab->ctFlags = 0;
232 ctab->ctSize = 3; // color count - 1
233 CTAB_ENTER(ctab, 0, 0xffff, 0xffff, 0xffff);
234 CTAB_ENTER(ctab, 1, pCursor->backRed, pCursor->backGreen,
235 pCursor->backBlue);
236 CTAB_ENTER(ctab, 2, 0x0000, 0x0000, 0x0000);
237 CTAB_ENTER(ctab, 3, pCursor->foreRed, pCursor->foreGreen,
238 pCursor->foreBlue);
240 HUnlock((Handle)pix->pmTable); // ctab
241 HUnlock((Handle)curs->crsrData); // image data
242 HUnlock((Handle)curs->crsrMap); // pix
243 HUnlock((Handle)result); // cursor
245 return result;
247 // "What we have here is a failure to allocate"
248 ctabAllocFailed:
249 HUnlock((Handle)curs->crsrData);
250 DisposeHandle((Handle)curs->crsrData);
251 imageAllocFailed:
252 HUnlock((Handle)curs->crsrMap);
253 DisposeHandle((Handle)curs->crsrMap);
254 pixAllocFailed:
255 HUnlock((Handle)result);
256 DisposeHandle((Handle)result);
257 return NULL;
262 * FreeQDCursor
263 * Destroy a QuickDraw color cursor created with MakeQDCursor().
264 * The cursor must not currently be on screen.
266 static void FreeQDCursor(CCrsrHandle cursHandle)
268 CCrsrPtr curs;
269 PixMap *pix;
271 HLock((Handle)cursHandle);
272 curs = *cursHandle;
273 HLock((Handle)curs->crsrMap);
274 pix = *curs->crsrMap;
275 DisposeHandle((Handle)pix->pmTable);
276 HUnlock((Handle)curs->crsrMap);
277 DisposeHandle((Handle)curs->crsrMap);
278 DisposeHandle((Handle)curs->crsrData);
279 HUnlock((Handle)cursHandle);
280 DisposeHandle((Handle)cursHandle);
285 ===========================================================================
287 Pointer sprite functions
289 ===========================================================================
293 * QuartzRealizeCursor
294 * Convert the X cursor representation to QuickDraw format if possible.
296 Bool
297 QuartzRealizeCursor(
298 ScreenPtr pScreen,
299 CursorPtr pCursor )
301 CCrsrHandle qdCursor;
302 QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
304 if(!pCursor || !pCursor->bits)
305 return FALSE;
307 // if the cursor is too big we use a software cursor
308 if ((pCursor->bits->height > CURSORHEIGHT) ||
309 (pCursor->bits->width > CURSORWIDTH) || !ScreenPriv->useQDCursor)
311 if (quartzRootless) {
312 // rootless can't use a software cursor
313 return TRUE;
314 } else {
315 return (*ScreenPriv->spriteFuncs->RealizeCursor)
316 (pScreen, pCursor);
320 // make new cursor image
321 qdCursor = MakeQDCursor(pCursor);
322 if (!qdCursor) return FALSE;
324 // save the result
325 pCursor->devPriv[pScreen->myNum] = (pointer) qdCursor;
327 return TRUE;
332 * QuartzUnrealizeCursor
333 * Free the storage space associated with a realized cursor.
335 Bool
336 QuartzUnrealizeCursor(
337 ScreenPtr pScreen,
338 CursorPtr pCursor )
340 QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
342 if ((pCursor->bits->height > CURSORHEIGHT) ||
343 (pCursor->bits->width > CURSORWIDTH) || !ScreenPriv->useQDCursor)
345 if (quartzRootless) {
346 return TRUE;
347 } else {
348 return (*ScreenPriv->spriteFuncs->UnrealizeCursor)
349 (pScreen, pCursor);
351 } else {
352 CCrsrHandle oldCursor = (CCrsrHandle) pCursor->devPriv[pScreen->myNum];
354 if (currentCursor != oldCursor) {
355 // This should only fail when quitting, in which case we just leak.
356 FreeQDCursor(oldCursor);
358 pCursor->devPriv[pScreen->myNum] = NULL;
359 return TRUE;
365 * QuartzSetCursor
366 * Set the cursor sprite and position.
367 * Use QuickDraw cursor if possible.
369 static void
370 QuartzSetCursor(
371 ScreenPtr pScreen,
372 CursorPtr pCursor,
373 int x,
374 int y)
376 QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
378 quartzLatentCursor = pCursor;
380 // Don't touch Mac OS cursor if X is hidden!
381 if (!quartzServerVisible)
382 return;
384 if (!pCursor) {
385 // Remove the cursor completely.
386 HIDE_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
387 if (! ScreenPriv->qdCursorMode)
388 (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y);
390 else if ((pCursor->bits->height <= CURSORHEIGHT) &&
391 (pCursor->bits->width <= CURSORWIDTH) && ScreenPriv->useQDCursor)
393 // Cursor is small enough to use QuickDraw directly.
394 if (! ScreenPriv->qdCursorMode) // remove the X cursor
395 (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y);
396 ScreenPriv->qdCursorMode = TRUE;
398 CHANGE_QD_CURSOR(pCursor->devPriv[pScreen->myNum]);
399 SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
401 else if (quartzRootless) {
402 // Rootless can't use a software cursor, so we just use Mac OS arrow.
403 CHANGE_QD_CURSOR(NULL);
404 SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
406 else {
407 // Cursor is too big for QuickDraw. Use X software cursor.
408 HIDE_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
409 ScreenPriv->qdCursorMode = FALSE;
410 (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, pCursor, x, y);
416 * QuartzReallySetCursor
417 * Set the QuickDraw cursor. Called from the main thread since changing the
418 * cursor with QuickDraw is not thread safe on dual processor machines.
420 void
421 QuartzReallySetCursor()
423 pthread_mutex_lock(&cursorMutex);
425 if (currentCursor) {
426 SetCCursor(currentCursor);
427 } else {
428 SetCursor(&gQDArrow);
431 pthread_cond_signal(&cursorCondition);
432 pthread_mutex_unlock(&cursorMutex);
437 * QuartzMoveCursor
438 * Move the cursor. This is a noop for QuickDraw.
440 static void
441 QuartzMoveCursor(
442 ScreenPtr pScreen,
443 int x,
444 int y)
446 QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
448 // only the X cursor needs to be explicitly moved
449 if (!ScreenPriv->qdCursorMode)
450 (*ScreenPriv->spriteFuncs->MoveCursor)(pScreen, x, y);
454 static miPointerSpriteFuncRec quartzSpriteFuncsRec = {
455 QuartzRealizeCursor,
456 QuartzUnrealizeCursor,
457 QuartzSetCursor,
458 QuartzMoveCursor
463 ===========================================================================
465 Pointer screen functions
467 ===========================================================================
471 * QuartzCursorOffScreen
473 static Bool QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
475 return FALSE;
480 * QuartzCrossScreen
482 static void QuartzCrossScreen(ScreenPtr pScreen, Bool entering)
484 return;
489 * QuartzWarpCursor
490 * Change the cursor position without generating an event or motion history.
491 * The input coordinates (x,y) are in pScreen-local X11 coordinates.
494 static void
495 QuartzWarpCursor(
496 ScreenPtr pScreen,
497 int x,
498 int y)
500 static int neverMoved = TRUE;
502 if (neverMoved) {
503 // Don't move the cursor the first time. This is the jump-to-center
504 // initialization, and it's annoying because we may still be in MacOS.
505 neverMoved = FALSE;
506 return;
509 if (quartzServerVisible) {
510 CGDisplayErr cgErr;
511 CGPoint cgPoint;
512 // Only need to do this for one display. Any display will do.
513 CGDirectDisplayID cgID = QUARTZ_PRIV(pScreen)->displayIDs[0];
514 CGRect cgRect = CGDisplayBounds(cgID);
516 // Convert (x,y) to CoreGraphics screen-local CG coordinates.
517 // This is necessary because the X11 screen and CG screen may not
518 // coincide. (e.g. X11 screen may be moved to dodge the menu bar)
520 // Make point in X11 global coordinates
521 cgPoint = CGPointMake(x + dixScreenOrigins[pScreen->myNum].x,
522 y + dixScreenOrigins[pScreen->myNum].y);
523 // Shift to CoreGraphics global screen coordinates
524 cgPoint.x += darwinMainScreenX;
525 cgPoint.y += darwinMainScreenY;
526 // Shift to CoreGraphics screen-local coordinates
527 cgPoint.x -= cgRect.origin.x;
528 cgPoint.y -= cgRect.origin.y;
530 cgErr = CGDisplayMoveCursorToPoint(cgID, cgPoint);
531 if (cgErr != CGDisplayNoErr) {
532 ErrorF("Could not set cursor position with error code 0x%x.\n",
533 cgErr);
537 miPointerWarpCursor(pScreen, x, y);
538 miPointerUpdate();
542 static miPointerScreenFuncRec quartzScreenFuncsRec = {
543 QuartzCursorOffScreen,
544 QuartzCrossScreen,
545 QuartzWarpCursor,
546 DarwinEQPointerPost,
547 DarwinEQSwitchScreen
552 ===========================================================================
554 Other screen functions
556 ===========================================================================
560 * QuartzCursorQueryBestSize
561 * Handle queries for best cursor size
563 static void
564 QuartzCursorQueryBestSize(
565 int class,
566 unsigned short *width,
567 unsigned short *height,
568 ScreenPtr pScreen)
570 QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
572 if (class == CursorShape) {
573 *width = CURSORWIDTH;
574 *height = CURSORHEIGHT;
575 } else {
576 (*ScreenPriv->QueryBestSize)(class, width, height, pScreen);
582 * QuartzInitCursor
583 * Initialize cursor support
585 Bool
586 QuartzInitCursor(
587 ScreenPtr pScreen )
589 QuartzCursorScreenPtr ScreenPriv;
590 miPointerScreenPtr PointPriv;
591 DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
593 // initialize software cursor handling (always needed as backup)
594 if (!miDCInitialize(pScreen, &quartzScreenFuncsRec)) {
595 return FALSE;
598 // allocate private storage for this screen's QuickDraw cursor info
599 if (darwinCursorGeneration != serverGeneration) {
600 if ((darwinCursorScreenIndex = AllocateScreenPrivateIndex()) < 0)
601 return FALSE;
602 darwinCursorGeneration = serverGeneration;
605 ScreenPriv = xcalloc( 1, sizeof(QuartzCursorScreenRec) );
606 if (!ScreenPriv) return FALSE;
608 CURSOR_PRIV(pScreen) = ScreenPriv;
610 // override some screen procedures
611 ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
612 pScreen->QueryBestSize = QuartzCursorQueryBestSize;
614 // initialize QuickDraw cursor handling
615 GetQDGlobalsArrow(&gQDArrow);
616 PointPriv = (miPointerScreenPtr)
617 pScreen->devPrivates[miPointerScreenIndex].ptr;
619 ScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
620 PointPriv->spriteFuncs = &quartzSpriteFuncsRec;
622 if (!quartzRootless)
623 ScreenPriv->useQDCursor = QuartzFSUseQDCursor(dfb->colorBitsPerPixel);
624 else
625 ScreenPriv->useQDCursor = TRUE;
626 ScreenPriv->qdCursorMode = TRUE;
627 ScreenPriv->qdCursorVisible = TRUE;
629 // initialize cursor mutex lock
630 pthread_mutex_init(&cursorMutex, NULL);
632 // initialize condition for waiting
633 pthread_cond_init(&cursorCondition, NULL);
635 return TRUE;
639 // X server is hiding. Restore the Aqua cursor.
640 void QuartzSuspendXCursor(
641 ScreenPtr pScreen )
643 QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
645 CHANGE_QD_CURSOR(NULL);
646 SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
650 // X server is showing. Restore the X cursor.
651 void QuartzResumeXCursor(
652 ScreenPtr pScreen,
653 int x,
654 int y )
656 QuartzSetCursor(pScreen, quartzLatentCursor, x, y);