#include "scrnintstr.h"
#include "cursorstr.h"
#include "mipointrst.h"
#include "micmap.h"
#define NO_CFPLUGIN
#include <IOKit/graphics/IOGraphicsLib.h>
#include <IOKit/hidsystem/IOHIDLib.h>
#include "darwin.h"
#include "xfIOKit.h"
#define DUMP_DARWIN_CURSOR FALSE
#define CURSOR_PRIV(pScreen) \
((XFIOKitCursorScreenPtr)pScreen->devPrivates[darwinCursorScreenIndex].ptr)
#define RGBto34WithGamma(red, green, blue) \
( 0x000F \
| (((red) & 0xF) << 12) \
| (((green) & 0xF) << 8) \
| (((blue) & 0xF) << 4) )
#define RGBto38WithGamma(red, green, blue) \
( 0xFF << 24 \
| (((red) & 0xFF) << 16) \
| (((green) & 0xFF) << 8) \
| (((blue) & 0xFF)) )
#define HighBitOf32 0x80000000
typedef struct {
Bool canHWCursor;
short cursorMode;
RecolorCursorProcPtr RecolorCursor;
InstallColormapProcPtr InstallColormap;
QueryBestSizeProcPtr QueryBestSize;
miPointerSpriteFuncPtr spriteFuncs;
ColormapPtr pInstalledMap;
} XFIOKitCursorScreenRec, *XFIOKitCursorScreenPtr;
static int darwinCursorScreenIndex = -1;
static unsigned long darwinCursorGeneration = 0;
typedef struct {
unsigned char image[CURSORWIDTH*CURSORHEIGHT];
unsigned char mask[CURSORWIDTH*CURSORHEIGHT];
} cursorPrivRec, *cursorPrivPtr;
static Bool
XFIOKitRealizeCursor8(
ScreenPtr pScreen,
CursorPtr pCursor)
{
cursorPrivPtr newCursor;
unsigned char *newSourceP, *newMaskP;
CARD32 *oldSourceP, *oldMaskP;
xColorItem fgColor, bgColor;
int index, x, y, rowPad;
int cursorWidth, cursorHeight;
ColormapPtr pmap;
cursorWidth = pCursor->bits->width;
cursorHeight = pCursor->bits->height;
if (cursorHeight > CURSORHEIGHT || cursorWidth > CURSORWIDTH)
return FALSE;
index = pScreen->myNum;
pmap = miInstalledMaps[index];
if (!pmap) return FALSE;
fgColor.red = pCursor->foreRed;
fgColor.green = pCursor->foreGreen;
fgColor.blue = pCursor->foreBlue;
FakeAllocColor(pmap, &fgColor);
bgColor.red = pCursor->backRed;
bgColor.green = pCursor->backGreen;
bgColor.blue = pCursor->backBlue;
FakeAllocColor(pmap, &bgColor);
FakeFreeColor(pmap, fgColor.pixel);
FakeFreeColor(pmap, bgColor.pixel);
newCursor = xalloc( sizeof(cursorPrivRec) );
if (!newCursor)
return FALSE;
memset( newCursor->image, pScreen->blackPixel, CURSORWIDTH*CURSORHEIGHT );
memset( newCursor->mask, 0, CURSORWIDTH*CURSORHEIGHT );
oldSourceP = (CARD32 *) pCursor->bits->source;
oldMaskP = (CARD32 *) pCursor->bits->mask;
newSourceP = newCursor->image;
newMaskP = newCursor->mask;
rowPad = CURSORWIDTH - cursorWidth;
for (y = 0; y < cursorHeight; y++) {
for (x = 0; x < cursorWidth; x++) {
if (*oldSourceP & (HighBitOf32 >> x))
*newSourceP = fgColor.pixel;
else
*newSourceP = bgColor.pixel;
if (*oldMaskP & (HighBitOf32 >> x))
*newMaskP = 255;
else
*newSourceP = pScreen->blackPixel;
newSourceP++; newMaskP++;
}
oldSourceP++; oldMaskP++;
newSourceP += rowPad; newMaskP += rowPad;
}
pCursor->devPriv[pScreen->myNum] = (pointer) newCursor;
return TRUE;
}
static Bool
XFIOKitRealizeCursor15(
ScreenPtr pScreen,
CursorPtr pCursor)
{
unsigned short *newCursor;
unsigned short fgPixel, bgPixel;
unsigned short *newSourceP;
CARD32 *oldSourceP, *oldMaskP;
int x, y, rowPad;
int cursorWidth, cursorHeight;
cursorWidth = pCursor->bits->width;
cursorHeight = pCursor->bits->height;
if (cursorHeight > CURSORHEIGHT || cursorWidth > CURSORWIDTH)
return FALSE;
newCursor = xalloc( CURSORWIDTH*CURSORHEIGHT*sizeof(short) );
if (!newCursor)
return FALSE;
memset( newCursor, 0, CURSORWIDTH*CURSORHEIGHT*sizeof(short) );
fgPixel = RGBto34WithGamma( pCursor->foreRed, pCursor->foreGreen,
pCursor->foreBlue );
bgPixel = RGBto34WithGamma( pCursor->backRed, pCursor->backGreen,
pCursor->backBlue );
oldSourceP = (CARD32 *) pCursor->bits->source;
oldMaskP = (CARD32 *) pCursor->bits->mask;
newSourceP = newCursor;
rowPad = CURSORWIDTH - cursorWidth;
for (y = 0; y < cursorHeight; y++) {
for (x = 0; x < cursorWidth; x++) {
if (*oldMaskP & (HighBitOf32 >> x)) {
if (*oldSourceP & (HighBitOf32 >> x))
*newSourceP = fgPixel;
else
*newSourceP = bgPixel;
} else {
*newSourceP = 0;
}
newSourceP++;
}
oldSourceP++; oldMaskP++;
newSourceP += rowPad;
}
#if DUMP_DARWIN_CURSOR
ErrorF("Cursor: 0x%x\n", pCursor);
ErrorF("Width = %i, Height = %i, RowPad = %i\n", cursorWidth,
cursorHeight, rowPad);
for (y = 0; y < cursorHeight; y++) {
newSourceP = newCursor + y*CURSORWIDTH;
for (x = 0; x < cursorWidth; x++) {
if (*newSourceP == fgPixel)
ErrorF("x");
else if (*newSourceP == bgPixel)
ErrorF("o");
else
ErrorF(" ");
newSourceP++;
}
ErrorF("\n");
}
#endif
pCursor->devPriv[pScreen->myNum] = (pointer) newCursor;
return TRUE;
}
static Bool
XFIOKitRealizeCursor24(
ScreenPtr pScreen,
CursorPtr pCursor)
{
unsigned int *newCursor;
unsigned int fgPixel, bgPixel;
unsigned int *newSourceP;
CARD32 *oldSourceP, *oldMaskP;
int x, y, rowPad;
int cursorWidth, cursorHeight;
cursorWidth = pCursor->bits->width;
cursorHeight = pCursor->bits->height;
if (cursorHeight > CURSORHEIGHT || cursorWidth > CURSORWIDTH)
return FALSE;
newCursor = xalloc( CURSORWIDTH*CURSORHEIGHT*sizeof(int) );
if (!newCursor)
return FALSE;
memset( newCursor, 0, CURSORWIDTH*CURSORHEIGHT*sizeof(int) );
fgPixel = RGBto38WithGamma( pCursor->foreRed, pCursor->foreGreen,
pCursor->foreBlue );
bgPixel = RGBto38WithGamma( pCursor->backRed, pCursor->backGreen,
pCursor->backBlue );
oldSourceP = (CARD32 *) pCursor->bits->source;
oldMaskP = (CARD32 *) pCursor->bits->mask;
newSourceP = newCursor;
rowPad = CURSORWIDTH - cursorWidth;
for (y = 0; y < cursorHeight; y++) {
for (x = 0; x < cursorWidth; x++) {
if (*oldMaskP & (HighBitOf32 >> x)) {
if (*oldSourceP & (HighBitOf32 >> x))
*newSourceP = fgPixel;
else
*newSourceP = bgPixel;
} else {
*newSourceP = 0;
}
newSourceP++;
}
oldSourceP++; oldMaskP++;
newSourceP += rowPad;
}
#if DUMP_DARWIN_CURSOR
ErrorF("Cursor: 0x%x\n", pCursor);
ErrorF("Width = %i, Height = %i, RowPad = %i\n", cursorWidth,
cursorHeight, rowPad);
for (y = 0; y < cursorHeight; y++) {
newSourceP = newCursor + y*CURSORWIDTH;
for (x = 0; x < cursorWidth; x++) {
if (*newSourceP == fgPixel)
ErrorF("x");
else if (*newSourceP == bgPixel)
ErrorF("o");
else
ErrorF(" ");
newSourceP++;
}
ErrorF("\n");
}
#endif
pCursor->devPriv[pScreen->myNum] = (pointer) newCursor;
return TRUE;
}
static Bool
XFIOKitRealizeCursor(
ScreenPtr pScreen,
CursorPtr pCursor)
{
Bool result;
XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
if ((pCursor->bits->height > CURSORHEIGHT) ||
(pCursor->bits->width > CURSORWIDTH) ||
!ScreenPriv->canHWCursor) {
result = (*ScreenPriv->spriteFuncs->RealizeCursor)(pScreen, pCursor);
} else if (dfb->bitsPerPixel == 8) {
result = XFIOKitRealizeCursor8(pScreen, pCursor);
} else if (dfb->bitsPerPixel == 16) {
result = XFIOKitRealizeCursor15(pScreen, pCursor);
} else {
result = XFIOKitRealizeCursor24(pScreen, pCursor);
}
return result;
}
static Bool
XFIOKitUnrealizeCursor(
ScreenPtr pScreen,
CursorPtr pCursor)
{
Bool result;
XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
if ((pCursor->bits->height > CURSORHEIGHT) ||
(pCursor->bits->width > CURSORWIDTH) ||
!ScreenPriv->canHWCursor) {
result = (*ScreenPriv->spriteFuncs->UnrealizeCursor)(pScreen, pCursor);
} else {
xfree( pCursor->devPriv[pScreen->myNum] );
result = TRUE;
}
return result;
}
static void
XFIOKitSetCursor(
ScreenPtr pScreen,
CursorPtr pCursor,
int x,
int y)
{
kern_return_t kr;
DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen);
StdFBShmem_t *cshmem = iokitScreen->cursorShmem;
XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
if (!pCursor) {
if (ScreenPriv->cursorMode == 0)
(*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y);
else {
if (!cshmem->cursorShow) {
cshmem->cursorShow++;
if (cshmem->hardwareCursorActive) {
kr = IOFBSetCursorVisible(iokitScreen->fbService, FALSE);
kern_assert( kr );
}
}
}
return;
}
if ((pCursor->bits->height <= CURSORHEIGHT) &&
(pCursor->bits->width <= CURSORWIDTH) &&
ScreenPriv->canHWCursor) {
if (ScreenPriv->cursorMode == 0) (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y);
ScreenPriv->cursorMode = 1;
if (dfb->bitsPerPixel == 8) {
cursorPrivPtr newCursor =
(cursorPrivPtr) pCursor->devPriv[pScreen->myNum];
memcpy(cshmem->cursor.bw8.image[0], newCursor->image,
CURSORWIDTH*CURSORHEIGHT);
memcpy(cshmem->cursor.bw8.mask[0], newCursor->mask,
CURSORWIDTH*CURSORHEIGHT);
} else if (dfb->bitsPerPixel == 16) {
unsigned short *newCursor =
(unsigned short *) pCursor->devPriv[pScreen->myNum];
memcpy(cshmem->cursor.rgb.image[0], newCursor,
2*CURSORWIDTH*CURSORHEIGHT);
} else {
unsigned int *newCursor =
(unsigned int *) pCursor->devPriv[pScreen->myNum];
memcpy(cshmem->cursor.rgb24.image[0], newCursor,
4*CURSORWIDTH*CURSORHEIGHT);
}
cshmem->cursorSize[0].width = CURSORWIDTH;
cshmem->cursorSize[0].height = CURSORHEIGHT;
cshmem->hotSpot[0].x = pCursor->bits->xhot;
cshmem->hotSpot[0].y = pCursor->bits->yhot;
if (ScreenPriv->canHWCursor) {
kr = IOFBSetNewCursor(iokitScreen->fbService, 0, 0, 0);
kern_assert( kr );
#if 0
if (kr != KERN_SUCCESS) {
ErrorF("Could not set new cursor with kernel return 0x%x.\n", kr);
ScreenPriv->canHWCursor = FALSE;
}
#endif
}
if (cshmem->cursorShow)
cshmem->cursorShow--;
if (!cshmem->cursorShow && ScreenPriv->canHWCursor) {
kr = IOFBSetCursorVisible(iokitScreen->fbService, TRUE);
kern_assert( kr );
#if 0
if (kr != KERN_SUCCESS) {
ErrorF("Couldn't set hardware cursor visible with kernel return 0x%x.\n", kr);
ScreenPriv->canHWCursor = FALSE;
} else
#endif
ScreenPriv->cursorMode = 2; }
return;
}
if (ScreenPriv->cursorMode) {
XFIOKitSetCursor(pScreen, 0, x, y);
}
ScreenPriv->cursorMode = 0;
(*ScreenPriv->spriteFuncs->SetCursor)(pScreen, pCursor, x, y);
}
static void
XFIOKitMoveCursor(
ScreenPtr pScreen,
int x,
int y)
{
XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
if (!ScreenPriv->cursorMode)
(*ScreenPriv->spriteFuncs->MoveCursor)(pScreen, x, y);
}
static miPointerSpriteFuncRec darwinSpriteFuncsRec = {
XFIOKitRealizeCursor,
XFIOKitUnrealizeCursor,
XFIOKitSetCursor,
XFIOKitMoveCursor
};
static Bool XFIOKitCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
{ return FALSE;
}
static void XFIOKitCrossScreen(ScreenPtr pScreen, Bool entering)
{ return;
}
static void
XFIOKitWarpCursor(
ScreenPtr pScreen,
int x,
int y)
{
kern_return_t kr;
kr = IOHIDSetMouseLocation( xfIOKitInputConnect, x, y );
if (kr != KERN_SUCCESS) {
ErrorF("Could not set cursor position with kernel return 0x%x.\n", kr);
}
miPointerWarpCursor(pScreen, x, y);
}
static miPointerScreenFuncRec darwinScreenFuncsRec = {
XFIOKitCursorOffScreen,
XFIOKitCrossScreen,
XFIOKitWarpCursor,
DarwinEQPointerPost,
DarwinEQSwitchScreen
};
static void
XFIOKitCursorQueryBestSize(
int class,
unsigned short *width,
unsigned short *height,
ScreenPtr pScreen)
{
XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
if (class == CursorShape) {
*width = CURSORWIDTH;
*height = CURSORHEIGHT;
} else
(*ScreenPriv->QueryBestSize)(class, width, height, pScreen);
}
Bool
XFIOKitInitCursor(
ScreenPtr pScreen)
{
XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen);
XFIOKitCursorScreenPtr ScreenPriv;
miPointerScreenPtr PointPriv;
kern_return_t kr;
if (!iokitScreen->cursorShmem->cursorShow++) {
if (iokitScreen->cursorShmem->hardwareCursorActive) {
kr = IOFBSetCursorVisible(iokitScreen->fbService, FALSE);
kern_assert( kr );
}
}
if (!miDCInitialize(pScreen, &darwinScreenFuncsRec)) {
return FALSE;
}
if (darwinCursorGeneration != serverGeneration) {
if ((darwinCursorScreenIndex = AllocateScreenPrivateIndex()) < 0)
return FALSE;
darwinCursorGeneration = serverGeneration;
}
ScreenPriv = xcalloc( 1, sizeof(XFIOKitCursorScreenRec) );
if (!ScreenPriv) return FALSE;
pScreen->devPrivates[darwinCursorScreenIndex].ptr = (pointer) ScreenPriv;
if (!iokitScreen->cursorShmem->hardwareCursorCapable) {
ScreenPriv->canHWCursor = FALSE;
ErrorF("Hardware cursor not supported.\n");
} else {
ScreenPriv->canHWCursor = TRUE;
kr = IOFBSetNewCursor(iokitScreen->fbService, 0, 0, 0);
if (kr != KERN_SUCCESS) {
ErrorF("Could not set hardware cursor with kernel return 0x%x.\n", kr);
ScreenPriv->canHWCursor = FALSE;
}
kr = IOFBSetCursorVisible(iokitScreen->fbService, TRUE);
if (kr != KERN_SUCCESS) {
ErrorF("Couldn't set hardware cursor visible with kernel return 0x%x.\n", kr);
ScreenPriv->canHWCursor = FALSE;
}
IOFBSetCursorVisible(iokitScreen->fbService, FALSE);
}
ScreenPriv->cursorMode = 0;
ScreenPriv->pInstalledMap = NULL;
ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
pScreen->QueryBestSize = XFIOKitCursorQueryBestSize;
PointPriv = (miPointerScreenPtr)
pScreen->devPrivates[miPointerScreenIndex].ptr;
ScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
PointPriv->spriteFuncs = &darwinSpriteFuncsRec;
return TRUE;
}