654 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			654 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
| /**************************************************************
 | |
|  *
 | |
|  * Support for using the Quartz Window Manager cursor
 | |
|  *
 | |
|  **************************************************************/
 | |
| /*
 | |
|  * Copyright (c) 2001-2003 Torrey T. Lyons and Greg Parker.
 | |
|  *                 All Rights Reserved.
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a
 | |
|  * copy of this software and associated documentation files (the "Software"),
 | |
|  * to deal in the Software without restriction, including without limitation
 | |
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | |
|  * and/or sell copies of the Software, and to permit persons to whom the
 | |
|  * Software is furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be included in
 | |
|  * all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | |
|  * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | |
|  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | |
|  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | |
|  * DEALINGS IN THE SOFTWARE.
 | |
|  *
 | |
|  * Except as contained in this notice, the name(s) of the above copyright
 | |
|  * holders shall not be used in advertising or otherwise to promote the sale,
 | |
|  * use or other dealings in this Software without prior written authorization.
 | |
|  */
 | |
| /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzCursor.c,v 1.4 2002/11/19 23:01:30 torrey Exp $ */
 | |
| 
 | |
| #include "quartzCommon.h"
 | |
| #include "quartzCursor.h"
 | |
| #include "darwin.h"
 | |
| 
 | |
| #include <pthread.h>
 | |
| 
 | |
| #include "mi.h"
 | |
| #include "scrnintstr.h"
 | |
| #include "cursorstr.h"
 | |
| #include "mipointrst.h"
 | |
| #include "globals.h"
 | |
| 
 | |
| // Size of the QuickDraw cursor
 | |
| #define CURSORWIDTH 16
 | |
| #define CURSORHEIGHT 16
 | |
| 
 | |
| typedef struct {
 | |
|     int                     qdCursorMode;
 | |
|     int                     qdCursorVisible;
 | |
|     int                     useQDCursor;
 | |
|     QueryBestSizeProcPtr    QueryBestSize;
 | |
|     miPointerSpriteFuncPtr  spriteFuncs;
 | |
| } QuartzCursorScreenRec, *QuartzCursorScreenPtr;
 | |
| 
 | |
| static int darwinCursorScreenIndex = -1;
 | |
| static unsigned long darwinCursorGeneration = 0;
 | |
| static CursorPtr quartzLatentCursor = NULL;
 | |
| static QD_Cursor gQDArrow; // QuickDraw arrow cursor
 | |
| 
 | |
| // Cursor for the main thread to set (NULL = arrow cursor).
 | |
| static CCrsrHandle currentCursor = NULL;
 | |
| static pthread_mutex_t cursorMutex;
 | |
| static pthread_cond_t cursorCondition;
 | |
| 
 | |
| #define CURSOR_PRIV(pScreen) \
 | |
|     ((QuartzCursorScreenPtr)pScreen->devPrivates[darwinCursorScreenIndex].ptr)
 | |
| 
 | |
| #define HIDE_QD_CURSOR(pScreen, visible)                                \
 | |
|     if (visible) {                                                      \
 | |
|         int ix;                                                         \
 | |
|         for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) {   \
 | |
|             CGDisplayHideCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]);  \
 | |
|         }                                                               \
 | |
|         visible = FALSE;                                                \
 | |
|     } ((void)0)
 | |
| 
 | |
| #define SHOW_QD_CURSOR(pScreen, visible)                                \
 | |
|     {                                                                   \
 | |
|         int ix;                                                         \
 | |
|         for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) {   \
 | |
|             CGDisplayShowCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]);  \
 | |
|         }                                                               \
 | |
|         visible = TRUE;                                                 \
 | |
|     } ((void)0)
 | |
| 
 | |
| #define CHANGE_QD_CURSOR(cursorH)                                       \
 | |
|     if (!quartzServerQuitting) {                                        \
 | |
|         /* Acquire lock and tell the main thread to change cursor */    \
 | |
|         pthread_mutex_lock(&cursorMutex);                               \
 | |
|         currentCursor = (CCrsrHandle) (cursorH);                        \
 | |
|         QuartzMessageMainThread(kQuartzCursorUpdate, NULL, 0);          \
 | |
|                                                                         \
 | |
|         /* Wait for the main thread to change the cursor */             \
 | |
|         pthread_cond_wait(&cursorCondition, &cursorMutex);              \
 | |
|         pthread_mutex_unlock(&cursorMutex);                             \
 | |
|     } ((void)0)
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * MakeQDCursor helpers: CTAB_ENTER, interleave
 | |
|  */
 | |
| 
 | |
| // Add a color entry to a ctab
 | |
| #define CTAB_ENTER(ctab, index, r, g, b)                                \
 | |
|     ctab->ctTable[index].value = index;                                 \
 | |
|     ctab->ctTable[index].rgb.red = r;                                   \
 | |
|     ctab->ctTable[index].rgb.green = g;                                 \
 | |
|     ctab->ctTable[index].rgb.blue = b
 | |
| 
 | |
| // Make an unsigned short by interleaving the bits of bytes c1 and c2.
 | |
| // High bit of c1 is first; low bit of c2 is last.
 | |
| // Interleave is a built-in INTERCAL operator.
 | |
| static unsigned short
 | |
| interleave(
 | |
|     unsigned char c1,
 | |
|     unsigned char c2 )
 | |
| {
 | |
|     return
 | |
|         ((c1 & 0x80) << 8) | ((c2 & 0x80) << 7) |
 | |
|         ((c1 & 0x40) << 7) | ((c2 & 0x40) << 6) |
 | |
|         ((c1 & 0x20) << 6) | ((c2 & 0x20) << 5) |
 | |
|         ((c1 & 0x10) << 5) | ((c2 & 0x10) << 4) |
 | |
|         ((c1 & 0x08) << 4) | ((c2 & 0x08) << 3) |
 | |
|         ((c1 & 0x04) << 3) | ((c2 & 0x04) << 2) |
 | |
|         ((c1 & 0x02) << 2) | ((c2 & 0x02) << 1) |
 | |
|         ((c1 & 0x01) << 1) | ((c2 & 0x01) << 0) ;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * MakeQDCursor
 | |
|  * Make a QuickDraw color cursor from the given X11 cursor.
 | |
|  * Warning: This code is nasty. Color cursors were meant to be read
 | |
|  * from resources; constructing the structures programmatically is messy.
 | |
|  */
 | |
| /*
 | |
|     QuickDraw cursor representation:
 | |
|     Our color cursor is a 2 bit per pixel pixmap.
 | |
|     Each pixel's bits are (source<<1 | mask) from the original X cursor pixel.
 | |
|     The cursor's color table maps the colors like this:
 | |
|     (2-bit value | X result    | colortable | Mac result)
 | |
|              00  | transparent | white      | transparent (white outside mask)
 | |
|              01  | back color  | back color | back color
 | |
|              10  | undefined   | black      | invert background (just for fun)
 | |
|              11  | fore color  | fore color | fore color
 | |
| */
 | |
| static CCrsrHandle
 | |
| MakeQDCursor(
 | |
|     CursorPtr pCursor )
 | |
| {
 | |
|     CCrsrHandle result;
 | |
|     CCrsrPtr curs;
 | |
|     int i, w, h;
 | |
|     unsigned short rowMask;
 | |
|     PixMap *pix;
 | |
|     ColorTable *ctab;
 | |
|     unsigned short *image;
 | |
| 
 | |
|     result = (CCrsrHandle) NewHandleClear(sizeof(CCrsr));
 | |
|     if (!result) return NULL;
 | |
|     HLock((Handle)result);
 | |
|     curs = *result;
 | |
| 
 | |
|     // Initialize CCrsr
 | |
|     curs->crsrType = 0x8001;     // 0x8000 = b&w, 0x8001 = color
 | |
|     curs->crsrMap = (PixMapHandle) NewHandleClear(sizeof(PixMap));
 | |
|     if (!curs->crsrMap) goto pixAllocFailed;
 | |
|     HLock((Handle)curs->crsrMap);
 | |
|     pix = *curs->crsrMap;
 | |
|     curs->crsrData = NULL;       // raw cursor image data (set below)
 | |
|     curs->crsrXData = NULL;      // QD's processed data
 | |
|     curs->crsrXValid = 0;        // zero means QD must re-process cursor data
 | |
|     curs->crsrXHandle = NULL;    // reserved
 | |
|     memset(curs->crsr1Data, 0, CURSORWIDTH*CURSORHEIGHT/8); // b&w data
 | |
|     memset(curs->crsrMask,  0, CURSORWIDTH*CURSORHEIGHT/8); // b&w & color mask
 | |
|     curs->crsrHotSpot.h = min(CURSORWIDTH,  pCursor->bits->xhot); // hot spot
 | |
|     curs->crsrHotSpot.v = min(CURSORHEIGHT, pCursor->bits->yhot); // hot spot
 | |
|     curs->crsrXTable = 0;        // reserved
 | |
|     curs->crsrID = GetCTSeed();  // unique ID from Color Manager
 | |
| 
 | |
|     // Set the b&w data and mask
 | |
|     w = min(pCursor->bits->width,  CURSORWIDTH);
 | |
|     h = min(pCursor->bits->height, CURSORHEIGHT);
 | |
|     rowMask = ~((1 << (CURSORWIDTH - w)) - 1);
 | |
|     for (i = 0; i < h; i++) {
 | |
|         curs->crsr1Data[i] = rowMask &
 | |
|         ((pCursor->bits->source[i*4]<<8) | pCursor->bits->source[i*4+1]);
 | |
|         curs->crsrMask[i] = rowMask &
 | |
|         ((pCursor->bits->mask[i*4]<<8)   | pCursor->bits->mask[i*4+1]);
 | |
|     }
 | |
| 
 | |
|     // Set the color data and mask
 | |
|     // crsrMap: defines bit depth and size and colortable only
 | |
|     pix->rowBytes = (CURSORWIDTH * 2 / 8) | 0x8000; // last bit on means PixMap
 | |
|     SetRect(&pix->bounds, 0, 0, CURSORWIDTH, CURSORHEIGHT); // see TN 1020
 | |
|     pix->pixelSize = 2;
 | |
|     pix->cmpCount = 1;
 | |
|     pix->cmpSize = 2;
 | |
|     // pix->pmTable set below
 | |
| 
 | |
|     // crsrData is the pixel data. crsrMap's baseAddr is not used.
 | |
|     curs->crsrData = NewHandleClear(CURSORWIDTH*CURSORHEIGHT * 2 / 8);
 | |
|     if (!curs->crsrData) goto imageAllocFailed;
 | |
|     HLock((Handle)curs->crsrData);
 | |
|     image = (unsigned short *) *curs->crsrData;
 | |
|     // Pixel data is just 1-bit data and mask interleaved (see above)
 | |
|     for (i = 0; i < h; i++) {
 | |
|         unsigned char s, m;
 | |
|         s = pCursor->bits->source[i*4] & (rowMask >> 8);
 | |
|         m = pCursor->bits->mask[i*4] & (rowMask >> 8);
 | |
|         image[2*i] = interleave(s, m);
 | |
|         s = pCursor->bits->source[i*4+1] & (rowMask & 0x00ff);
 | |
|         m = pCursor->bits->mask[i*4+1] & (rowMask & 0x00ff);
 | |
|         image[2*i+1] = interleave(s, m);
 | |
|     }
 | |
| 
 | |
|     // Build the color table (entries described above)
 | |
|     // NewPixMap allocates a color table handle.
 | |
|     pix->pmTable = (CTabHandle) NewHandleClear(sizeof(ColorTable) + 3
 | |
|                     * sizeof(ColorSpec));
 | |
|     if (!pix->pmTable) goto ctabAllocFailed;
 | |
|     HLock((Handle)pix->pmTable);
 | |
|     ctab = *pix->pmTable;
 | |
|     ctab->ctSeed = GetCTSeed();
 | |
|     ctab->ctFlags = 0;
 | |
|     ctab->ctSize = 3; // color count - 1
 | |
|     CTAB_ENTER(ctab, 0, 0xffff, 0xffff, 0xffff);
 | |
|     CTAB_ENTER(ctab, 1, pCursor->backRed, pCursor->backGreen,
 | |
|                pCursor->backBlue);
 | |
|     CTAB_ENTER(ctab, 2, 0x0000, 0x0000, 0x0000);
 | |
|     CTAB_ENTER(ctab, 3, pCursor->foreRed, pCursor->foreGreen,
 | |
|                pCursor->foreBlue);
 | |
| 
 | |
|     HUnlock((Handle)pix->pmTable); // ctab
 | |
|     HUnlock((Handle)curs->crsrData); // image data
 | |
|     HUnlock((Handle)curs->crsrMap); // pix
 | |
|     HUnlock((Handle)result); // cursor
 | |
| 
 | |
|     return result;
 | |
| 
 | |
|     // "What we have here is a failure to allocate"
 | |
| ctabAllocFailed:
 | |
|     HUnlock((Handle)curs->crsrData);
 | |
|     DisposeHandle((Handle)curs->crsrData);
 | |
| imageAllocFailed:
 | |
|     HUnlock((Handle)curs->crsrMap);
 | |
|     DisposeHandle((Handle)curs->crsrMap);
 | |
| pixAllocFailed:
 | |
|     HUnlock((Handle)result);
 | |
|     DisposeHandle((Handle)result);
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * FreeQDCursor
 | |
|  * Destroy a QuickDraw color cursor created with MakeQDCursor().
 | |
|  * The cursor must not currently be on screen.
 | |
|  */
 | |
| static void FreeQDCursor(CCrsrHandle cursHandle)
 | |
| {
 | |
|     CCrsrPtr curs;
 | |
|     PixMap *pix;
 | |
| 
 | |
|     HLock((Handle)cursHandle);
 | |
|     curs = *cursHandle;
 | |
|     HLock((Handle)curs->crsrMap);
 | |
|     pix = *curs->crsrMap;
 | |
|     DisposeHandle((Handle)pix->pmTable);
 | |
|     HUnlock((Handle)curs->crsrMap);
 | |
|     DisposeHandle((Handle)curs->crsrMap);
 | |
|     DisposeHandle((Handle)curs->crsrData);
 | |
|     HUnlock((Handle)cursHandle);
 | |
|     DisposeHandle((Handle)cursHandle);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ===========================================================================
 | |
| 
 | |
|  Pointer sprite functions
 | |
| 
 | |
| ===========================================================================
 | |
| */
 | |
| 
 | |
| /*
 | |
|  * QuartzRealizeCursor
 | |
|  * Convert the X cursor representation to QuickDraw format if possible.
 | |
|  */
 | |
| Bool
 | |
| QuartzRealizeCursor(
 | |
|     ScreenPtr pScreen,
 | |
|     CursorPtr pCursor )
 | |
| {
 | |
|     CCrsrHandle qdCursor;
 | |
|     QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
 | |
| 
 | |
|     if(!pCursor || !pCursor->bits)
 | |
|         return FALSE;
 | |
| 
 | |
|     // if the cursor is too big we use a software cursor
 | |
|     if ((pCursor->bits->height > CURSORHEIGHT) ||
 | |
|         (pCursor->bits->width > CURSORWIDTH) || !ScreenPriv->useQDCursor)
 | |
|     {
 | |
|         if (quartzRootless) {
 | |
|             // rootless can't use a software cursor
 | |
|             return TRUE;
 | |
|         } else {
 | |
|             return (*ScreenPriv->spriteFuncs->RealizeCursor)
 | |
|                         (pScreen, pCursor);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // make new cursor image
 | |
|     qdCursor = MakeQDCursor(pCursor);
 | |
|     if (!qdCursor) return FALSE;
 | |
| 
 | |
|     // save the result
 | |
|     pCursor->devPriv[pScreen->myNum] = (pointer) qdCursor;
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * QuartzUnrealizeCursor
 | |
|  * Free the storage space associated with a realized cursor.
 | |
|  */
 | |
| Bool
 | |
| QuartzUnrealizeCursor(
 | |
|     ScreenPtr pScreen,
 | |
|     CursorPtr pCursor )
 | |
| {
 | |
|     QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
 | |
| 
 | |
|     if ((pCursor->bits->height > CURSORHEIGHT) ||
 | |
|         (pCursor->bits->width > CURSORWIDTH) || !ScreenPriv->useQDCursor)
 | |
|     {
 | |
|         if (quartzRootless) {
 | |
|             return TRUE;
 | |
|         } else {
 | |
|             return (*ScreenPriv->spriteFuncs->UnrealizeCursor)
 | |
|                         (pScreen, pCursor);
 | |
|         }
 | |
|     } else {
 | |
|         CCrsrHandle oldCursor = (CCrsrHandle) pCursor->devPriv[pScreen->myNum];
 | |
| 
 | |
|         if (currentCursor != oldCursor) {
 | |
|             // This should only fail when quitting, in which case we just leak.
 | |
|             FreeQDCursor(oldCursor);
 | |
|         }
 | |
|         pCursor->devPriv[pScreen->myNum] = NULL;
 | |
|         return TRUE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * QuartzSetCursor
 | |
|  * Set the cursor sprite and position.
 | |
|  * Use QuickDraw cursor if possible.
 | |
|  */
 | |
| static void
 | |
| QuartzSetCursor(
 | |
|     ScreenPtr       pScreen,
 | |
|     CursorPtr       pCursor,
 | |
|     int             x,
 | |
|     int             y)
 | |
| {
 | |
|     QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
 | |
| 
 | |
|     quartzLatentCursor = pCursor;
 | |
| 
 | |
|     // Don't touch Mac OS cursor if X is hidden!
 | |
|     if (!quartzServerVisible)
 | |
|         return;
 | |
| 
 | |
|     if (!pCursor) {
 | |
|         // Remove the cursor completely.
 | |
|         HIDE_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
 | |
|         if (! ScreenPriv->qdCursorMode)
 | |
|             (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y);
 | |
|     }
 | |
|     else if ((pCursor->bits->height <= CURSORHEIGHT) &&
 | |
|              (pCursor->bits->width <= CURSORWIDTH) && ScreenPriv->useQDCursor)
 | |
|     {
 | |
|         // Cursor is small enough to use QuickDraw directly.
 | |
|         if (! ScreenPriv->qdCursorMode)    // remove the X cursor
 | |
|             (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y);
 | |
|         ScreenPriv->qdCursorMode = TRUE;
 | |
| 
 | |
|         CHANGE_QD_CURSOR(pCursor->devPriv[pScreen->myNum]);
 | |
|         SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
 | |
|     }
 | |
|     else if (quartzRootless) {
 | |
|         // Rootless can't use a software cursor, so we just use Mac OS arrow.
 | |
|         CHANGE_QD_CURSOR(NULL);
 | |
|         SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
 | |
|     }
 | |
|     else {
 | |
|         // Cursor is too big for QuickDraw. Use X software cursor.
 | |
|         HIDE_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
 | |
|         ScreenPriv->qdCursorMode = FALSE;
 | |
|         (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, pCursor, x, y);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * QuartzReallySetCursor
 | |
|  * Set the QuickDraw cursor. Called from the main thread since changing the
 | |
|  * cursor with QuickDraw is not thread safe on dual processor machines.
 | |
|  */
 | |
| void
 | |
| QuartzReallySetCursor()
 | |
| {
 | |
|     pthread_mutex_lock(&cursorMutex);
 | |
| 
 | |
|     if (currentCursor) {
 | |
|         SetCCursor(currentCursor);
 | |
|     } else {
 | |
|         SetCursor(&gQDArrow);
 | |
|     }
 | |
| 
 | |
|     pthread_cond_signal(&cursorCondition);
 | |
|     pthread_mutex_unlock(&cursorMutex);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * QuartzMoveCursor
 | |
|  * Move the cursor. This is a noop for QuickDraw.
 | |
|  */
 | |
| static void
 | |
| QuartzMoveCursor(
 | |
|     ScreenPtr   pScreen,
 | |
|     int         x,
 | |
|     int         y)
 | |
| {
 | |
|     QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
 | |
| 
 | |
|     // only the X cursor needs to be explicitly moved
 | |
|     if (!ScreenPriv->qdCursorMode)
 | |
|         (*ScreenPriv->spriteFuncs->MoveCursor)(pScreen, x, y);
 | |
| }
 | |
| 
 | |
| 
 | |
| static miPointerSpriteFuncRec quartzSpriteFuncsRec = {
 | |
|     QuartzRealizeCursor,
 | |
|     QuartzUnrealizeCursor,
 | |
|     QuartzSetCursor,
 | |
|     QuartzMoveCursor
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
| ===========================================================================
 | |
| 
 | |
|  Pointer screen functions
 | |
| 
 | |
| ===========================================================================
 | |
| */
 | |
| 
 | |
| /*
 | |
|  * QuartzCursorOffScreen
 | |
|  */
 | |
| static Bool QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
 | |
| {
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * QuartzCrossScreen
 | |
|  */
 | |
| static void QuartzCrossScreen(ScreenPtr pScreen, Bool entering)
 | |
| {
 | |
|     return;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * QuartzWarpCursor
 | |
|  *  Change the cursor position without generating an event or motion history.
 | |
|  *  The input coordinates (x,y) are in pScreen-local X11 coordinates.
 | |
|  *
 | |
|  */
 | |
| static void
 | |
| QuartzWarpCursor(
 | |
|     ScreenPtr               pScreen,
 | |
|     int                     x,
 | |
|     int                     y)
 | |
| {
 | |
|     static int              neverMoved = TRUE;
 | |
| 
 | |
|     if (neverMoved) {
 | |
|         // Don't move the cursor the first time. This is the jump-to-center
 | |
|         // initialization, and it's annoying because we may still be in MacOS.
 | |
|         neverMoved = FALSE;
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (quartzServerVisible) {
 | |
|         CGDisplayErr        cgErr;
 | |
|         CGPoint             cgPoint;
 | |
|         // Only need to do this for one display. Any display will do.
 | |
|         CGDirectDisplayID   cgID = QUARTZ_PRIV(pScreen)->displayIDs[0];
 | |
|         CGRect              cgRect = CGDisplayBounds(cgID);
 | |
| 
 | |
|         // Convert (x,y) to CoreGraphics screen-local CG coordinates.
 | |
|         // This is necessary because the X11 screen and CG screen may not
 | |
|         // coincide. (e.g. X11 screen may be moved to dodge the menu bar)
 | |
| 
 | |
|         // Make point in X11 global coordinates
 | |
|         cgPoint = CGPointMake(x + dixScreenOrigins[pScreen->myNum].x,
 | |
|                               y + dixScreenOrigins[pScreen->myNum].y);
 | |
|         // Shift to CoreGraphics global screen coordinates
 | |
|         cgPoint.x += darwinMainScreenX;
 | |
|         cgPoint.y += darwinMainScreenY;
 | |
|         // Shift to CoreGraphics screen-local coordinates
 | |
|         cgPoint.x -= cgRect.origin.x;
 | |
|         cgPoint.y -= cgRect.origin.y;
 | |
| 
 | |
|         cgErr = CGDisplayMoveCursorToPoint(cgID, cgPoint);
 | |
|         if (cgErr != CGDisplayNoErr) {
 | |
|             ErrorF("Could not set cursor position with error code 0x%x.\n",
 | |
|                     cgErr);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     miPointerWarpCursor(pScreen, x, y);
 | |
|     miPointerUpdate();
 | |
| }
 | |
| 
 | |
| 
 | |
| static miPointerScreenFuncRec quartzScreenFuncsRec = {
 | |
|     QuartzCursorOffScreen,
 | |
|     QuartzCrossScreen,
 | |
|     QuartzWarpCursor,
 | |
|     DarwinEQPointerPost,
 | |
|     DarwinEQSwitchScreen
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
| ===========================================================================
 | |
| 
 | |
|  Other screen functions
 | |
| 
 | |
| ===========================================================================
 | |
| */
 | |
| 
 | |
| /*
 | |
|  * QuartzCursorQueryBestSize
 | |
|  * Handle queries for best cursor size
 | |
|  */
 | |
| static void
 | |
| QuartzCursorQueryBestSize(
 | |
|    int              class,
 | |
|    unsigned short   *width,
 | |
|    unsigned short   *height,
 | |
|    ScreenPtr        pScreen)
 | |
| {
 | |
|     QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
 | |
| 
 | |
|     if (class == CursorShape) {
 | |
|         *width = CURSORWIDTH;
 | |
|         *height = CURSORHEIGHT;
 | |
|     } else {
 | |
|         (*ScreenPriv->QueryBestSize)(class, width, height, pScreen);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * QuartzInitCursor
 | |
|  * Initialize cursor support
 | |
|  */
 | |
| Bool
 | |
| QuartzInitCursor(
 | |
|     ScreenPtr   pScreen )
 | |
| {
 | |
|     QuartzCursorScreenPtr   ScreenPriv;
 | |
|     miPointerScreenPtr      PointPriv;
 | |
|     DarwinFramebufferPtr    dfb = SCREEN_PRIV(pScreen);
 | |
| 
 | |
|     // initialize software cursor handling (always needed as backup)
 | |
|     if (!miDCInitialize(pScreen, &quartzScreenFuncsRec)) {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     // allocate private storage for this screen's QuickDraw cursor info
 | |
|     if (darwinCursorGeneration != serverGeneration) {
 | |
|         if ((darwinCursorScreenIndex = AllocateScreenPrivateIndex()) < 0)
 | |
|             return FALSE;
 | |
|         darwinCursorGeneration = serverGeneration;
 | |
|     }
 | |
| 
 | |
|     ScreenPriv = xcalloc( 1, sizeof(QuartzCursorScreenRec) );
 | |
|     if (!ScreenPriv) return FALSE;
 | |
| 
 | |
|     CURSOR_PRIV(pScreen) = ScreenPriv;
 | |
| 
 | |
|     // override some screen procedures
 | |
|     ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
 | |
|     pScreen->QueryBestSize = QuartzCursorQueryBestSize;
 | |
| 
 | |
|     // initialize QuickDraw cursor handling
 | |
|     GetQDGlobalsArrow(&gQDArrow);
 | |
|     PointPriv = (miPointerScreenPtr)
 | |
|                     pScreen->devPrivates[miPointerScreenIndex].ptr;
 | |
| 
 | |
|     ScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
 | |
|     PointPriv->spriteFuncs = &quartzSpriteFuncsRec;
 | |
| 
 | |
|     if (!quartzRootless)
 | |
|         ScreenPriv->useQDCursor = QuartzFSUseQDCursor(dfb->colorBitsPerPixel);
 | |
|     else
 | |
|         ScreenPriv->useQDCursor = TRUE;
 | |
|     ScreenPriv->qdCursorMode = TRUE;
 | |
|     ScreenPriv->qdCursorVisible = TRUE;
 | |
| 
 | |
|     // initialize cursor mutex lock
 | |
|     pthread_mutex_init(&cursorMutex, NULL);
 | |
| 
 | |
|     // initialize condition for waiting
 | |
|     pthread_cond_init(&cursorCondition, NULL);
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| // X server is hiding. Restore the Aqua cursor.
 | |
| void QuartzSuspendXCursor(
 | |
|     ScreenPtr pScreen )
 | |
| {
 | |
|     QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
 | |
| 
 | |
|     CHANGE_QD_CURSOR(NULL);
 | |
|     SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
 | |
| }
 | |
| 
 | |
| 
 | |
| // X server is showing. Restore the X cursor.
 | |
| void QuartzResumeXCursor(
 | |
|     ScreenPtr pScreen,
 | |
|     int x,
 | |
|     int y )
 | |
| {
 | |
|     QuartzSetCursor(pScreen, quartzLatentCursor, x, y);
 | |
| }
 |