14642e01fSmrg/**************************************************************
24642e01fSmrg *
34642e01fSmrg * Xplugin cursor support
44642e01fSmrg *
54642e01fSmrg * Copyright (c) 2001 Torrey T. Lyons and Greg Parker.
64642e01fSmrg * Copyright (c) 2002 Apple Computer, Inc.
74642e01fSmrg *                 All Rights Reserved.
84642e01fSmrg *
94642e01fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
104642e01fSmrg * copy of this software and associated documentation files (the "Software"),
114642e01fSmrg * to deal in the Software without restriction, including without limitation
124642e01fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
134642e01fSmrg * and/or sell copies of the Software, and to permit persons to whom the
144642e01fSmrg * Software is furnished to do so, subject to the following conditions:
154642e01fSmrg *
164642e01fSmrg * The above copyright notice and this permission notice shall be included in
174642e01fSmrg * all copies or substantial portions of the Software.
184642e01fSmrg *
194642e01fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
204642e01fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
214642e01fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
224642e01fSmrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
234642e01fSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
244642e01fSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
254642e01fSmrg * DEALINGS IN THE SOFTWARE.
264642e01fSmrg *
274642e01fSmrg * Except as contained in this notice, the name(s) of the above copyright
284642e01fSmrg * holders shall not be used in advertising or otherwise to promote the sale,
294642e01fSmrg * use or other dealings in this Software without prior written authorization.
304642e01fSmrg */
314642e01fSmrg
324642e01fSmrg#include "sanitizedCarbon.h"
334642e01fSmrg
344642e01fSmrg#ifdef HAVE_DIX_CONFIG_H
354642e01fSmrg#include <dix-config.h>
364642e01fSmrg#endif
374642e01fSmrg
386747b715Smrg#include "quartz.h"
394642e01fSmrg#include "xpr.h"
404642e01fSmrg#include "darwinEvents.h"
414642e01fSmrg#include <Xplugin.h>
424642e01fSmrg
434642e01fSmrg#include "mi.h"
444642e01fSmrg#include "scrnintstr.h"
454642e01fSmrg#include "cursorstr.h"
464642e01fSmrg#include "mipointrst.h"
474642e01fSmrg#include "windowstr.h"
484642e01fSmrg#include "globals.h"
494642e01fSmrg#include "servermd.h"
504642e01fSmrg#include "dixevents.h"
514642e01fSmrg#include "x-hash.h"
524642e01fSmrg
534642e01fSmrgtypedef struct {
5435c4bbdfSmrg    int cursorVisible;
5535c4bbdfSmrg    QueryBestSizeProcPtr QueryBestSize;
5635c4bbdfSmrg    miPointerSpriteFuncPtr spriteFuncs;
574642e01fSmrg} QuartzCursorScreenRec, *QuartzCursorScreenPtr;
584642e01fSmrg
596747b715Smrgstatic DevPrivateKeyRec darwinCursorScreenKeyRec;
606747b715Smrg#define darwinCursorScreenKey (&darwinCursorScreenKeyRec)
614642e01fSmrg
624642e01fSmrg#define CURSOR_PRIV(pScreen) ((QuartzCursorScreenPtr) \
6335c4bbdfSmrg                              dixLookupPrivate(&pScreen->devPrivates, \
6435c4bbdfSmrg                                               darwinCursorScreenKey))
654642e01fSmrg
664642e01fSmrgstatic Bool
674642e01fSmrgload_cursor(CursorPtr src, int screen)
684642e01fSmrg{
694642e01fSmrg    uint32_t *data;
706747b715Smrg    Bool free_data = FALSE;
714642e01fSmrg    uint32_t rowbytes;
724642e01fSmrg    int width, height;
734642e01fSmrg    int hot_x, hot_y;
744642e01fSmrg
754642e01fSmrg    uint32_t fg_color, bg_color;
764642e01fSmrg    uint8_t *srow, *sptr;
774642e01fSmrg    uint8_t *mrow, *mptr;
784642e01fSmrg    uint32_t *drow, *dptr;
794642e01fSmrg    unsigned xcount, ycount;
804642e01fSmrg
814642e01fSmrg    xp_error err;
824642e01fSmrg
834642e01fSmrg    width = src->bits->width;
844642e01fSmrg    height = src->bits->height;
854642e01fSmrg    hot_x = src->bits->xhot;
864642e01fSmrg    hot_y = src->bits->yhot;
874642e01fSmrg
8835c4bbdfSmrg    if (src->bits->argb != NULL) {
894642e01fSmrg#if BITMAP_BIT_ORDER == MSBFirst
9035c4bbdfSmrg        rowbytes = src->bits->width * sizeof(CARD32);
9135c4bbdfSmrg        data = (uint32_t *)src->bits->argb;
924642e01fSmrg#else
9335c4bbdfSmrg        const uint32_t *be_data = (uint32_t *)src->bits->argb;
944642e01fSmrg        unsigned i;
9535c4bbdfSmrg        rowbytes = src->bits->width * sizeof(CARD32);
966747b715Smrg        data = malloc(rowbytes * src->bits->height);
976747b715Smrg        free_data = TRUE;
9835c4bbdfSmrg        if (!data) {
996747b715Smrg            FatalError("Failed to allocate memory in %s\n", __func__);
1006747b715Smrg        }
10135c4bbdfSmrg        for (i = 0; i < (src->bits->width * src->bits->height); i++)
10235c4bbdfSmrg            data[i] = ntohl(be_data[i]);
1034642e01fSmrg#endif
1044642e01fSmrg    }
1054642e01fSmrg    else
1064642e01fSmrg    {
1074642e01fSmrg        fg_color = 0xFF00 | (src->foreRed >> 8);
1084642e01fSmrg        fg_color <<= 16;
1094642e01fSmrg        fg_color |= src->foreGreen & 0xFF00;
1104642e01fSmrg        fg_color |= src->foreBlue >> 8;
1114642e01fSmrg
1124642e01fSmrg        bg_color = 0xFF00 | (src->backRed >> 8);
1134642e01fSmrg        bg_color <<= 16;
1144642e01fSmrg        bg_color |= src->backGreen & 0xFF00;
1154642e01fSmrg        bg_color |= src->backBlue >> 8;
1164642e01fSmrg
1174642e01fSmrg        fg_color = htonl(fg_color);
1184642e01fSmrg        bg_color = htonl(bg_color);
1194642e01fSmrg
1204642e01fSmrg        /* round up to 8 pixel boundary so we can convert whole bytes */
1214642e01fSmrg        rowbytes = ((src->bits->width * 4) + 31) & ~31;
1226747b715Smrg        data = malloc(rowbytes * src->bits->height);
1236747b715Smrg        free_data = TRUE;
12435c4bbdfSmrg        if (!data) {
1256747b715Smrg            FatalError("Failed to allocate memory in %s\n", __func__);
1266747b715Smrg        }
12735c4bbdfSmrg
12835c4bbdfSmrg        if (!src->bits->emptyMask) {
1294642e01fSmrg            ycount = src->bits->height;
13035c4bbdfSmrg            srow = src->bits->source;
13135c4bbdfSmrg            mrow = src->bits->mask;
1324642e01fSmrg            drow = data;
1334642e01fSmrg
1344642e01fSmrg            while (ycount-- > 0)
1354642e01fSmrg            {
1366747b715Smrg                xcount = bits_to_bytes(src->bits->width);
13735c4bbdfSmrg                sptr = srow;
13835c4bbdfSmrg                mptr = mrow;
1394642e01fSmrg                dptr = drow;
1404642e01fSmrg
1414642e01fSmrg                while (xcount-- > 0)
1424642e01fSmrg                {
1434642e01fSmrg                    uint8_t s, m;
1444642e01fSmrg                    int i;
1454642e01fSmrg
14635c4bbdfSmrg                    s = *sptr++;
14735c4bbdfSmrg                    m = *mptr++;
14835c4bbdfSmrg                    for (i = 0; i < 8; i++) {
1494642e01fSmrg#if BITMAP_BIT_ORDER == MSBFirst
1504642e01fSmrg                        if (m & 128)
1514642e01fSmrg                            *dptr++ = (s & 128) ? fg_color : bg_color;
1524642e01fSmrg                        else
1534642e01fSmrg                            *dptr++ = 0;
15435c4bbdfSmrg                        s <<= 1;
15535c4bbdfSmrg                        m <<= 1;
1564642e01fSmrg#else
1574642e01fSmrg                        if (m & 1)
1584642e01fSmrg                            *dptr++ = (s & 1) ? fg_color : bg_color;
1594642e01fSmrg                        else
1604642e01fSmrg                            *dptr++ = 0;
16135c4bbdfSmrg                        s >>= 1;
16235c4bbdfSmrg                        m >>= 1;
1634642e01fSmrg#endif
1644642e01fSmrg                    }
1654642e01fSmrg                }
1664642e01fSmrg
1674642e01fSmrg                srow += BitmapBytePad(src->bits->width);
1684642e01fSmrg                mrow += BitmapBytePad(src->bits->width);
16935c4bbdfSmrg                drow = (uint32_t *)((char *)drow + rowbytes);
1704642e01fSmrg            }
1714642e01fSmrg        }
17235c4bbdfSmrg        else {
1734642e01fSmrg            memset(data, 0, src->bits->height * rowbytes);
1744642e01fSmrg        }
1754642e01fSmrg    }
1764642e01fSmrg
1774642e01fSmrg    err = xp_set_cursor(width, height, hot_x, hot_y, data, rowbytes);
17835c4bbdfSmrg    if (free_data)
1796747b715Smrg        free(data);
1804642e01fSmrg    return err == Success;
1814642e01fSmrg}
1824642e01fSmrg
1834642e01fSmrg/*
18435c4bbdfSmrg   ===========================================================================
1854642e01fSmrg
18635c4bbdfSmrg   Pointer sprite functions
1874642e01fSmrg
18835c4bbdfSmrg   ===========================================================================
18935c4bbdfSmrg */
1904642e01fSmrg
1914642e01fSmrg/*
1924642e01fSmrg * QuartzRealizeCursor
1934642e01fSmrg *  Convert the X cursor representation to native format if possible.
1944642e01fSmrg */
1954642e01fSmrgstatic Bool
1964642e01fSmrgQuartzRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
1974642e01fSmrg{
19835c4bbdfSmrg    if (pCursor == NULL || pCursor->bits == NULL)
1994642e01fSmrg        return FALSE;
2004642e01fSmrg
2014642e01fSmrg    /* FIXME: cache ARGB8888 representation? */
2024642e01fSmrg
2034642e01fSmrg    return TRUE;
2044642e01fSmrg}
2054642e01fSmrg
2064642e01fSmrg/*
2074642e01fSmrg * QuartzUnrealizeCursor
2084642e01fSmrg *  Free the storage space associated with a realized cursor.
2094642e01fSmrg */
2104642e01fSmrgstatic Bool
2114642e01fSmrgQuartzUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
2124642e01fSmrg{
2134642e01fSmrg    return TRUE;
2144642e01fSmrg}
2154642e01fSmrg
2164642e01fSmrg/*
2174642e01fSmrg * QuartzSetCursor
2184642e01fSmrg *  Set the cursor sprite and position.
2194642e01fSmrg */
2204642e01fSmrgstatic void
22135c4bbdfSmrgQuartzSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor,
22235c4bbdfSmrg                int x,
22335c4bbdfSmrg                int y)
2244642e01fSmrg{
2254642e01fSmrg    QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
2264642e01fSmrg
2276747b715Smrg    if (!XQuartzServerVisible)
2284642e01fSmrg        return;
2294642e01fSmrg
23035c4bbdfSmrg    if (pCursor == NULL) {
23135c4bbdfSmrg        if (ScreenPriv->cursorVisible) {
2324642e01fSmrg            xp_hide_cursor();
2334642e01fSmrg            ScreenPriv->cursorVisible = FALSE;
2344642e01fSmrg        }
2354642e01fSmrg    }
23635c4bbdfSmrg    else {
2374642e01fSmrg        load_cursor(pCursor, pScreen->myNum);
2384642e01fSmrg
23935c4bbdfSmrg        if (!ScreenPriv->cursorVisible) {
2404642e01fSmrg            xp_show_cursor();
2414642e01fSmrg            ScreenPriv->cursorVisible = TRUE;
2424642e01fSmrg        }
2434642e01fSmrg    }
2444642e01fSmrg}
2454642e01fSmrg
2464642e01fSmrg/*
2474642e01fSmrg * QuartzMoveCursor
2484642e01fSmrg *  Move the cursor. This is a noop for us.
2494642e01fSmrg */
2504642e01fSmrgstatic void
2514642e01fSmrgQuartzMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
25235c4bbdfSmrg{}
2534642e01fSmrg
2544642e01fSmrg/*
25535c4bbdfSmrg   ===========================================================================
2564642e01fSmrg
25735c4bbdfSmrg   Pointer screen functions
2584642e01fSmrg
25935c4bbdfSmrg   ===========================================================================
26035c4bbdfSmrg */
2614642e01fSmrg
2624642e01fSmrg/*
2634642e01fSmrg * QuartzCursorOffScreen
2644642e01fSmrg */
2654642e01fSmrgstatic Bool
2664642e01fSmrgQuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
2674642e01fSmrg{
2684642e01fSmrg    return FALSE;
2694642e01fSmrg}
2704642e01fSmrg
2714642e01fSmrg/*
2724642e01fSmrg * QuartzCrossScreen
2734642e01fSmrg */
2744642e01fSmrgstatic void
2754642e01fSmrgQuartzCrossScreen(ScreenPtr pScreen, Bool entering)
2764642e01fSmrg{
2774642e01fSmrg    return;
2784642e01fSmrg}
2794642e01fSmrg
2804642e01fSmrg/*
2814642e01fSmrg * QuartzWarpCursor
2824642e01fSmrg *  Change the cursor position without generating an event or motion history.
2834642e01fSmrg *  The input coordinates (x,y) are in pScreen-local X11 coordinates.
2844642e01fSmrg *
2854642e01fSmrg */
2864642e01fSmrgstatic void
2874642e01fSmrgQuartzWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
2884642e01fSmrg{
28935c4bbdfSmrg    if (XQuartzServerVisible) {
2904642e01fSmrg        int sx, sy;
2914642e01fSmrg
2926747b715Smrg        sx = pScreen->x + darwinMainScreenX;
2936747b715Smrg        sy = pScreen->y + darwinMainScreenY;
2944642e01fSmrg
2954642e01fSmrg        CGWarpMouseCursorPosition(CGPointMake(sx + x, sy + y));
2964642e01fSmrg    }
2974642e01fSmrg
2984642e01fSmrg    miPointerWarpCursor(pDev, pScreen, x, y);
2994642e01fSmrg    miPointerUpdateSprite(pDev);
3004642e01fSmrg}
3014642e01fSmrg
3024642e01fSmrgstatic miPointerScreenFuncRec quartzScreenFuncsRec = {
3034642e01fSmrg    QuartzCursorOffScreen,
3044642e01fSmrg    QuartzCrossScreen,
3054642e01fSmrg    QuartzWarpCursor,
3064642e01fSmrg};
3074642e01fSmrg
3084642e01fSmrg/*
30935c4bbdfSmrg   ===========================================================================
3104642e01fSmrg
31135c4bbdfSmrg   Other screen functions
3124642e01fSmrg
31335c4bbdfSmrg   ===========================================================================
31435c4bbdfSmrg */
3154642e01fSmrg
3164642e01fSmrg/*
3174642e01fSmrg * QuartzCursorQueryBestSize
3184642e01fSmrg *  Handle queries for best cursor size
3194642e01fSmrg */
3204642e01fSmrgstatic void
3214642e01fSmrgQuartzCursorQueryBestSize(int class, unsigned short *width,
3224642e01fSmrg                          unsigned short *height, ScreenPtr pScreen)
3234642e01fSmrg{
3244642e01fSmrg    QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
3254642e01fSmrg
32635c4bbdfSmrg    if (class == CursorShape) {
3274642e01fSmrg        /* FIXME: query window server? */
3284642e01fSmrg        *width = 32;
3294642e01fSmrg        *height = 32;
3304642e01fSmrg    }
33135c4bbdfSmrg    else {
3324642e01fSmrg        (*ScreenPriv->QueryBestSize)(class, width, height, pScreen);
3334642e01fSmrg    }
3344642e01fSmrg}
3354642e01fSmrg
3364642e01fSmrg/*
3374642e01fSmrg * QuartzInitCursor
3384642e01fSmrg *  Initialize cursor support
3394642e01fSmrg */
3404642e01fSmrgBool
3414642e01fSmrgQuartzInitCursor(ScreenPtr pScreen)
3424642e01fSmrg{
3434642e01fSmrg    QuartzCursorScreenPtr ScreenPriv;
3444642e01fSmrg    miPointerScreenPtr PointPriv;
3454642e01fSmrg
3464642e01fSmrg    /* initialize software cursor handling (always needed as backup) */
3474642e01fSmrg    if (!miDCInitialize(pScreen, &quartzScreenFuncsRec))
3484642e01fSmrg        return FALSE;
3494642e01fSmrg
3506747b715Smrg    if (!dixRegisterPrivateKey(&darwinCursorScreenKeyRec, PRIVATE_SCREEN, 0))
35135c4bbdfSmrg        return FALSE;
3526747b715Smrg
3536747b715Smrg    ScreenPriv = calloc(1, sizeof(QuartzCursorScreenRec));
3544642e01fSmrg    if (ScreenPriv == NULL)
3554642e01fSmrg        return FALSE;
3564642e01fSmrg
3574642e01fSmrg    /* CURSOR_PRIV(pScreen) = ScreenPriv; */
3584642e01fSmrg    dixSetPrivate(&pScreen->devPrivates, darwinCursorScreenKey, ScreenPriv);
3594642e01fSmrg
3604642e01fSmrg    /* override some screen procedures */
3614642e01fSmrg    ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
3624642e01fSmrg    pScreen->QueryBestSize = QuartzCursorQueryBestSize;
3634642e01fSmrg
3644642e01fSmrg    PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
3654642e01fSmrg
3664642e01fSmrg    ScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
3674642e01fSmrg
3684642e01fSmrg    PointPriv->spriteFuncs->RealizeCursor = QuartzRealizeCursor;
3694642e01fSmrg    PointPriv->spriteFuncs->UnrealizeCursor = QuartzUnrealizeCursor;
3704642e01fSmrg    PointPriv->spriteFuncs->SetCursor = QuartzSetCursor;
3714642e01fSmrg    PointPriv->spriteFuncs->MoveCursor = QuartzMoveCursor;
37235c4bbdfSmrg
3734642e01fSmrg    ScreenPriv->cursorVisible = TRUE;
3744642e01fSmrg    return TRUE;
3754642e01fSmrg}
3764642e01fSmrg
3774642e01fSmrg/*
3784642e01fSmrg * QuartzSuspendXCursor
3794642e01fSmrg *  X server is hiding. Restore the Aqua cursor.
3804642e01fSmrg */
3814642e01fSmrgvoid
3824642e01fSmrgQuartzSuspendXCursor(ScreenPtr pScreen)
383a035e2b2Smrg{
384a035e2b2Smrg    xp_show_cursor();
385a035e2b2Smrg}
3864642e01fSmrg
3874642e01fSmrg/*
3884642e01fSmrg * QuartzResumeXCursor
3894642e01fSmrg *  X server is showing. Restore the X cursor.
3904642e01fSmrg */
3914642e01fSmrgvoid
3926747b715SmrgQuartzResumeXCursor(ScreenPtr pScreen)
3934642e01fSmrg{
3944642e01fSmrg    WindowPtr pWin;
3954642e01fSmrg    CursorPtr pCursor;
3964642e01fSmrg
3974642e01fSmrg    /* TODO: Tablet? */
39835c4bbdfSmrg
3994642e01fSmrg    pWin = GetSpriteWindow(darwinPointer);
4004642e01fSmrg    if (pWin->drawable.pScreen != pScreen)
4014642e01fSmrg        return;
4024642e01fSmrg
4034642e01fSmrg    pCursor = GetSpriteCursor(darwinPointer);
4044642e01fSmrg    if (pCursor == NULL)
4054642e01fSmrg        return;
4064642e01fSmrg
4076747b715Smrg    QuartzSetCursor(darwinPointer, pScreen, pCursor, /* x */ 0, /* y */ 0);
4084642e01fSmrg}
409