#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#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"
#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;
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) { \
\
pthread_mutex_lock(&cursorMutex); \
currentCursor = (CCrsrHandle) (cursorH); \
QuartzMessageMainThread(kQuartzCursorUpdate, NULL, 0); \
\
\
pthread_cond_wait(&cursorCondition, &cursorMutex); \
pthread_mutex_unlock(&cursorMutex); \
} ((void)0)
#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
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) ;
}
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;
curs->crsrType = 0x8001; curs->crsrMap = (PixMapHandle) NewHandleClear(sizeof(PixMap));
if (!curs->crsrMap) goto pixAllocFailed;
HLock((Handle)curs->crsrMap);
pix = *curs->crsrMap;
curs->crsrData = NULL; curs->crsrXData = NULL; curs->crsrXValid = 0; curs->crsrXHandle = NULL; memset(curs->crsr1Data, 0, CURSORWIDTH*CURSORHEIGHT/8); memset(curs->crsrMask, 0, CURSORWIDTH*CURSORHEIGHT/8); curs->crsrHotSpot.h = min(CURSORWIDTH, pCursor->bits->xhot); curs->crsrHotSpot.v = min(CURSORHEIGHT, pCursor->bits->yhot); curs->crsrXTable = 0; curs->crsrID = GetCTSeed();
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]);
}
pix->rowBytes = (CURSORWIDTH * 2 / 8) | 0x8000; SetRect(&pix->bounds, 0, 0, CURSORWIDTH, CURSORHEIGHT); pix->pixelSize = 2;
pix->cmpCount = 1;
pix->cmpSize = 2;
curs->crsrData = NewHandleClear(CURSORWIDTH*CURSORHEIGHT * 2 / 8);
if (!curs->crsrData) goto imageAllocFailed;
HLock((Handle)curs->crsrData);
image = (unsigned short *) *curs->crsrData;
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);
}
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; 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); HUnlock((Handle)curs->crsrData); HUnlock((Handle)curs->crsrMap); HUnlock((Handle)result);
return result;
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;
}
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);
}
Bool
QuartzRealizeCursor(
ScreenPtr pScreen,
CursorPtr pCursor )
{
CCrsrHandle qdCursor;
QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
if(!pCursor || !pCursor->bits)
return FALSE;
if ((pCursor->bits->height > CURSORHEIGHT) ||
(pCursor->bits->width > CURSORWIDTH) || !ScreenPriv->useQDCursor)
{
if (quartzRootless) {
return TRUE;
} else {
return (*ScreenPriv->spriteFuncs->RealizeCursor)
(pScreen, pCursor);
}
}
qdCursor = MakeQDCursor(pCursor);
if (!qdCursor) return FALSE;
pCursor->devPriv[pScreen->myNum] = (pointer) qdCursor;
return TRUE;
}
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) {
FreeQDCursor(oldCursor);
}
pCursor->devPriv[pScreen->myNum] = NULL;
return TRUE;
}
}
static void
QuartzSetCursor(
ScreenPtr pScreen,
CursorPtr pCursor,
int x,
int y)
{
QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
quartzLatentCursor = pCursor;
if (!quartzServerVisible)
return;
if (!pCursor) {
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)
{
if (! ScreenPriv->qdCursorMode) (*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) {
CHANGE_QD_CURSOR(NULL);
SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
}
else {
HIDE_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
ScreenPriv->qdCursorMode = FALSE;
(*ScreenPriv->spriteFuncs->SetCursor)(pScreen, pCursor, x, y);
}
}
void
QuartzReallySetCursor()
{
pthread_mutex_lock(&cursorMutex);
if (currentCursor) {
SetCCursor(currentCursor);
} else {
SetCursor(&gQDArrow);
}
pthread_cond_signal(&cursorCondition);
pthread_mutex_unlock(&cursorMutex);
}
static void
QuartzMoveCursor(
ScreenPtr pScreen,
int x,
int y)
{
QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
if (!ScreenPriv->qdCursorMode)
(*ScreenPriv->spriteFuncs->MoveCursor)(pScreen, x, y);
}
static miPointerSpriteFuncRec quartzSpriteFuncsRec = {
QuartzRealizeCursor,
QuartzUnrealizeCursor,
QuartzSetCursor,
QuartzMoveCursor
};
static Bool QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
{
return FALSE;
}
static void QuartzCrossScreen(ScreenPtr pScreen, Bool entering)
{
return;
}
static void
QuartzWarpCursor(
ScreenPtr pScreen,
int x,
int y)
{
static int neverMoved = TRUE;
if (neverMoved) {
neverMoved = FALSE;
return;
}
if (quartzServerVisible) {
CGDisplayErr cgErr;
CGPoint cgPoint;
CGDirectDisplayID cgID = QUARTZ_PRIV(pScreen)->displayIDs[0];
CGRect cgRect = CGDisplayBounds(cgID);
cgPoint = CGPointMake(x + dixScreenOrigins[pScreen->myNum].x,
y + dixScreenOrigins[pScreen->myNum].y);
cgPoint.x += darwinMainScreenX;
cgPoint.y += darwinMainScreenY;
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
};
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);
}
}
Bool
QuartzInitCursor(
ScreenPtr pScreen )
{
QuartzCursorScreenPtr ScreenPriv;
miPointerScreenPtr PointPriv;
DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
if (!miDCInitialize(pScreen, &quartzScreenFuncsRec)) {
return FALSE;
}
if (darwinCursorGeneration != serverGeneration) {
if ((darwinCursorScreenIndex = AllocateScreenPrivateIndex()) < 0)
return FALSE;
darwinCursorGeneration = serverGeneration;
}
ScreenPriv = xcalloc( 1, sizeof(QuartzCursorScreenRec) );
if (!ScreenPriv) return FALSE;
CURSOR_PRIV(pScreen) = ScreenPriv;
ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
pScreen->QueryBestSize = QuartzCursorQueryBestSize;
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;
pthread_mutex_init(&cursorMutex, NULL);
pthread_cond_init(&cursorCondition, NULL);
return TRUE;
}
void QuartzSuspendXCursor(
ScreenPtr pScreen )
{
QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
CHANGE_QD_CURSOR(NULL);
SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible);
}
void QuartzResumeXCursor(
ScreenPtr pScreen,
int x,
int y )
{
QuartzSetCursor(pScreen, quartzLatentCursor, x, y);
}