1 /**************************************************************
3 * Support for using the Quartz Window Manager cursor
5 **************************************************************/
7 * Copyright (c) 2001-2003 Torrey T. Lyons and Greg Parker.
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>
36 #include "quartzCommon.h"
37 #include "quartzCursor.h"
43 #include "scrnintstr.h"
44 #include "cursorstr.h"
45 #include "mipointrst.h"
48 // Size of the QuickDraw cursor
49 #define CURSORWIDTH 16
50 #define CURSORHEIGHT 16
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) \
76 for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) { \
77 CGDisplayHideCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]); \
82 #define SHOW_QD_CURSOR(pScreen, visible) \
85 for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) { \
86 CGDisplayShowCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]); \
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); \
97 QuartzMessageMainThread(kQuartzCursorUpdate
, NULL
, 0); \
100 /* Wait for the main thread to change the cursor */ \
101 pthread_cond_wait(&cursorCondition
, &cursorMutex
); \
102 pthread_mutex_unlock(&cursorMutex
); \
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
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) ;
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
160 unsigned short rowMask
;
163 unsigned short *image
;
165 result
= (CCrsrHandle
) NewHandleClear(sizeof(CCrsr
));
166 if (!result
) return NULL
;
167 HLock((Handle
)result
);
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
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
++) {
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();
232 ctab
->ctSize
= 3; // color count - 1
233 CTAB_ENTER(ctab
, 0, 0xffff, 0xffff, 0xffff);
234 CTAB_ENTER(ctab
, 1, pCursor
->backRed
, pCursor
->backGreen
,
236 CTAB_ENTER(ctab
, 2, 0x0000, 0x0000, 0x0000);
237 CTAB_ENTER(ctab
, 3, pCursor
->foreRed
, pCursor
->foreGreen
,
240 HUnlock((Handle
)pix
->pmTable
); // ctab
241 HUnlock((Handle
)curs
->crsrData
); // image data
242 HUnlock((Handle
)curs
->crsrMap
); // pix
243 HUnlock((Handle
)result
); // cursor
247 // "What we have here is a failure to allocate"
249 HUnlock((Handle
)curs
->crsrData
);
250 DisposeHandle((Handle
)curs
->crsrData
);
252 HUnlock((Handle
)curs
->crsrMap
);
253 DisposeHandle((Handle
)curs
->crsrMap
);
255 HUnlock((Handle
)result
);
256 DisposeHandle((Handle
)result
);
263 * Destroy a QuickDraw color cursor created with MakeQDCursor().
264 * The cursor must not currently be on screen.
266 static void FreeQDCursor(CCrsrHandle cursHandle
)
271 HLock((Handle
)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.
301 CCrsrHandle qdCursor
;
302 QuartzCursorScreenPtr ScreenPriv
= CURSOR_PRIV(pScreen
);
304 if(!pCursor
|| !pCursor
->bits
)
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
315 return (*ScreenPriv
->spriteFuncs
->RealizeCursor
)
320 // make new cursor image
321 qdCursor
= MakeQDCursor(pCursor
);
322 if (!qdCursor
) return FALSE
;
325 pCursor
->devPriv
[pScreen
->myNum
] = (pointer
) qdCursor
;
332 * QuartzUnrealizeCursor
333 * Free the storage space associated with a realized cursor.
336 QuartzUnrealizeCursor(
340 QuartzCursorScreenPtr ScreenPriv
= CURSOR_PRIV(pScreen
);
342 if ((pCursor
->bits
->height
> CURSORHEIGHT
) ||
343 (pCursor
->bits
->width
> CURSORWIDTH
) || !ScreenPriv
->useQDCursor
)
345 if (quartzRootless
) {
348 return (*ScreenPriv
->spriteFuncs
->UnrealizeCursor
)
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
;
366 * Set the cursor sprite and position.
367 * Use QuickDraw cursor if possible.
376 QuartzCursorScreenPtr ScreenPriv
= CURSOR_PRIV(pScreen
);
378 quartzLatentCursor
= pCursor
;
380 // Don't touch Mac OS cursor if X is hidden!
381 if (!quartzServerVisible
)
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
);
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.
421 QuartzReallySetCursor()
423 pthread_mutex_lock(&cursorMutex
);
426 SetCCursor(currentCursor
);
428 SetCursor(&gQDArrow
);
431 pthread_cond_signal(&cursorCondition
);
432 pthread_mutex_unlock(&cursorMutex
);
438 * Move the cursor. This is a noop for QuickDraw.
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
= {
456 QuartzUnrealizeCursor
,
463 ===========================================================================
465 Pointer screen functions
467 ===========================================================================
471 * QuartzCursorOffScreen
473 static Bool
QuartzCursorOffScreen(ScreenPtr
*pScreen
, int *x
, int *y
)
482 static void QuartzCrossScreen(ScreenPtr pScreen
, Bool entering
)
490 * Change the cursor position without generating an event or motion history.
491 * The input coordinates (x,y) are in pScreen-local X11 coordinates.
500 static int neverMoved
= TRUE
;
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.
509 if (quartzServerVisible
) {
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",
537 miPointerWarpCursor(pScreen
, x
, y
);
542 static miPointerScreenFuncRec quartzScreenFuncsRec
= {
543 QuartzCursorOffScreen
,
552 ===========================================================================
554 Other screen functions
556 ===========================================================================
560 * QuartzCursorQueryBestSize
561 * Handle queries for best cursor size
564 QuartzCursorQueryBestSize(
566 unsigned short *width
,
567 unsigned short *height
,
570 QuartzCursorScreenPtr ScreenPriv
= CURSOR_PRIV(pScreen
);
572 if (class == CursorShape
) {
573 *width
= CURSORWIDTH
;
574 *height
= CURSORHEIGHT
;
576 (*ScreenPriv
->QueryBestSize
)(class, width
, height
, pScreen
);
583 * Initialize cursor support
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
)) {
598 // allocate private storage for this screen's QuickDraw cursor info
599 if (darwinCursorGeneration
!= serverGeneration
) {
600 if ((darwinCursorScreenIndex
= AllocateScreenPrivateIndex()) < 0)
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
;
623 ScreenPriv
->useQDCursor
= QuartzFSUseQDCursor(dfb
->colorBitsPerPixel
);
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
);
639 // X server is hiding. Restore the Aqua cursor.
640 void QuartzSuspendXCursor(
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(
656 QuartzSetCursor(pScreen
, quartzLatentCursor
, x
, y
);