1706f2543Smrg/**************************************************************
2706f2543Smrg *
3706f2543Smrg * Xplugin cursor support
4706f2543Smrg *
5706f2543Smrg * Copyright (c) 2001 Torrey T. Lyons and Greg Parker.
6706f2543Smrg * Copyright (c) 2002 Apple Computer, Inc.
7706f2543Smrg *                 All Rights Reserved.
8706f2543Smrg *
9706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
10706f2543Smrg * copy of this software and associated documentation files (the "Software"),
11706f2543Smrg * to deal in the Software without restriction, including without limitation
12706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
14706f2543Smrg * Software is furnished to do so, subject to the following conditions:
15706f2543Smrg *
16706f2543Smrg * The above copyright notice and this permission notice shall be included in
17706f2543Smrg * all copies or substantial portions of the Software.
18706f2543Smrg *
19706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22706f2543Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25706f2543Smrg * DEALINGS IN THE SOFTWARE.
26706f2543Smrg *
27706f2543Smrg * Except as contained in this notice, the name(s) of the above copyright
28706f2543Smrg * holders shall not be used in advertising or otherwise to promote the sale,
29706f2543Smrg * use or other dealings in this Software without prior written authorization.
30706f2543Smrg */
31706f2543Smrg
32706f2543Smrg#include "sanitizedCarbon.h"
33706f2543Smrg
34706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
35706f2543Smrg#include <dix-config.h>
36706f2543Smrg#endif
37706f2543Smrg
38706f2543Smrg#include "quartz.h"
39706f2543Smrg#include "xpr.h"
40706f2543Smrg#include "darwin.h"
41706f2543Smrg#include "darwinEvents.h"
42706f2543Smrg#include <Xplugin.h>
43706f2543Smrg
44706f2543Smrg#include "mi.h"
45706f2543Smrg#include "scrnintstr.h"
46706f2543Smrg#include "cursorstr.h"
47706f2543Smrg#include "mipointrst.h"
48706f2543Smrg#include "windowstr.h"
49706f2543Smrg#include "globals.h"
50706f2543Smrg#include "servermd.h"
51706f2543Smrg#include "dixevents.h"
52706f2543Smrg#include "x-hash.h"
53706f2543Smrg
54706f2543Smrgtypedef struct {
55706f2543Smrg    int                     cursorVisible;
56706f2543Smrg    QueryBestSizeProcPtr    QueryBestSize;
57706f2543Smrg    miPointerSpriteFuncPtr  spriteFuncs;
58706f2543Smrg} QuartzCursorScreenRec, *QuartzCursorScreenPtr;
59706f2543Smrg
60706f2543Smrgstatic DevPrivateKeyRec darwinCursorScreenKeyRec;
61706f2543Smrg#define darwinCursorScreenKey (&darwinCursorScreenKeyRec)
62706f2543Smrg
63706f2543Smrg#define CURSOR_PRIV(pScreen) ((QuartzCursorScreenPtr) \
64706f2543Smrg    dixLookupPrivate(&pScreen->devPrivates, darwinCursorScreenKey))
65706f2543Smrg
66706f2543Smrgstatic Bool
67706f2543Smrgload_cursor(CursorPtr src, int screen)
68706f2543Smrg{
69706f2543Smrg    uint32_t *data;
70706f2543Smrg    Bool free_data = FALSE;
71706f2543Smrg    uint32_t rowbytes;
72706f2543Smrg    int width, height;
73706f2543Smrg    int hot_x, hot_y;
74706f2543Smrg
75706f2543Smrg    uint32_t fg_color, bg_color;
76706f2543Smrg    uint8_t *srow, *sptr;
77706f2543Smrg    uint8_t *mrow, *mptr;
78706f2543Smrg    uint32_t *drow, *dptr;
79706f2543Smrg    unsigned xcount, ycount;
80706f2543Smrg
81706f2543Smrg    xp_error err;
82706f2543Smrg
83706f2543Smrg    width = src->bits->width;
84706f2543Smrg    height = src->bits->height;
85706f2543Smrg    hot_x = src->bits->xhot;
86706f2543Smrg    hot_y = src->bits->yhot;
87706f2543Smrg
88706f2543Smrg#ifdef ARGB_CURSOR
89706f2543Smrg    if (src->bits->argb != NULL)
90706f2543Smrg    {
91706f2543Smrg#if BITMAP_BIT_ORDER == MSBFirst
92706f2543Smrg        rowbytes = src->bits->width * sizeof (CARD32);
93706f2543Smrg        data = (uint32_t *) src->bits->argb;
94706f2543Smrg#else
95706f2543Smrg        const uint32_t *be_data=(uint32_t *) src->bits->argb;
96706f2543Smrg        unsigned i;
97706f2543Smrg        rowbytes = src->bits->width * sizeof (CARD32);
98706f2543Smrg        data = malloc(rowbytes * src->bits->height);
99706f2543Smrg        free_data = TRUE;
100706f2543Smrg        if(!data) {
101706f2543Smrg            FatalError("Failed to allocate memory in %s\n", __func__);
102706f2543Smrg        }
103706f2543Smrg        for(i=0;i<(src->bits->width*src->bits->height);i++)
104706f2543Smrg            data[i]=ntohl(be_data[i]);
105706f2543Smrg#endif
106706f2543Smrg    }
107706f2543Smrg    else
108706f2543Smrg#endif
109706f2543Smrg    {
110706f2543Smrg        fg_color = 0xFF00 | (src->foreRed >> 8);
111706f2543Smrg        fg_color <<= 16;
112706f2543Smrg        fg_color |= src->foreGreen & 0xFF00;
113706f2543Smrg        fg_color |= src->foreBlue >> 8;
114706f2543Smrg
115706f2543Smrg        bg_color = 0xFF00 | (src->backRed >> 8);
116706f2543Smrg        bg_color <<= 16;
117706f2543Smrg        bg_color |= src->backGreen & 0xFF00;
118706f2543Smrg        bg_color |= src->backBlue >> 8;
119706f2543Smrg
120706f2543Smrg        fg_color = htonl(fg_color);
121706f2543Smrg        bg_color = htonl(bg_color);
122706f2543Smrg
123706f2543Smrg        /* round up to 8 pixel boundary so we can convert whole bytes */
124706f2543Smrg        rowbytes = ((src->bits->width * 4) + 31) & ~31;
125706f2543Smrg        data = malloc(rowbytes * src->bits->height);
126706f2543Smrg        free_data = TRUE;
127706f2543Smrg        if(!data) {
128706f2543Smrg            FatalError("Failed to allocate memory in %s\n", __func__);
129706f2543Smrg        }
130706f2543Smrg
131706f2543Smrg        if (!src->bits->emptyMask)
132706f2543Smrg        {
133706f2543Smrg            ycount = src->bits->height;
134706f2543Smrg            srow = src->bits->source; mrow = src->bits->mask;
135706f2543Smrg            drow = data;
136706f2543Smrg
137706f2543Smrg            while (ycount-- > 0)
138706f2543Smrg            {
139706f2543Smrg                xcount = bits_to_bytes(src->bits->width);
140706f2543Smrg                sptr = srow; mptr = mrow;
141706f2543Smrg                dptr = drow;
142706f2543Smrg
143706f2543Smrg                while (xcount-- > 0)
144706f2543Smrg                {
145706f2543Smrg                    uint8_t s, m;
146706f2543Smrg                    int i;
147706f2543Smrg
148706f2543Smrg                    s = *sptr++; m = *mptr++;
149706f2543Smrg                    for (i = 0; i < 8; i++)
150706f2543Smrg                    {
151706f2543Smrg#if BITMAP_BIT_ORDER == MSBFirst
152706f2543Smrg                        if (m & 128)
153706f2543Smrg                            *dptr++ = (s & 128) ? fg_color : bg_color;
154706f2543Smrg                        else
155706f2543Smrg                            *dptr++ = 0;
156706f2543Smrg                        s <<= 1; m <<= 1;
157706f2543Smrg#else
158706f2543Smrg                        if (m & 1)
159706f2543Smrg                            *dptr++ = (s & 1) ? fg_color : bg_color;
160706f2543Smrg                        else
161706f2543Smrg                            *dptr++ = 0;
162706f2543Smrg                        s >>= 1; m >>= 1;
163706f2543Smrg#endif
164706f2543Smrg                    }
165706f2543Smrg                }
166706f2543Smrg
167706f2543Smrg                srow += BitmapBytePad(src->bits->width);
168706f2543Smrg                mrow += BitmapBytePad(src->bits->width);
169706f2543Smrg                drow = (uint32_t *) ((char *) drow + rowbytes);
170706f2543Smrg            }
171706f2543Smrg        }
172706f2543Smrg        else
173706f2543Smrg        {
174706f2543Smrg            memset(data, 0, src->bits->height * rowbytes);
175706f2543Smrg        }
176706f2543Smrg    }
177706f2543Smrg
178706f2543Smrg    err = xp_set_cursor(width, height, hot_x, hot_y, data, rowbytes);
179706f2543Smrg    if(free_data)
180706f2543Smrg        free(data);
181706f2543Smrg    return err == Success;
182706f2543Smrg}
183706f2543Smrg
184706f2543Smrg
185706f2543Smrg/*
186706f2543Smrg===========================================================================
187706f2543Smrg
188706f2543Smrg Pointer sprite functions
189706f2543Smrg
190706f2543Smrg===========================================================================
191706f2543Smrg*/
192706f2543Smrg
193706f2543Smrg/*
194706f2543Smrg * QuartzRealizeCursor
195706f2543Smrg *  Convert the X cursor representation to native format if possible.
196706f2543Smrg */
197706f2543Smrgstatic Bool
198706f2543SmrgQuartzRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
199706f2543Smrg{
200706f2543Smrg    if(pCursor == NULL || pCursor->bits == NULL)
201706f2543Smrg        return FALSE;
202706f2543Smrg
203706f2543Smrg    /* FIXME: cache ARGB8888 representation? */
204706f2543Smrg
205706f2543Smrg    return TRUE;
206706f2543Smrg}
207706f2543Smrg
208706f2543Smrg
209706f2543Smrg/*
210706f2543Smrg * QuartzUnrealizeCursor
211706f2543Smrg *  Free the storage space associated with a realized cursor.
212706f2543Smrg */
213706f2543Smrgstatic Bool
214706f2543SmrgQuartzUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
215706f2543Smrg{
216706f2543Smrg    return TRUE;
217706f2543Smrg}
218706f2543Smrg
219706f2543Smrg
220706f2543Smrg/*
221706f2543Smrg * QuartzSetCursor
222706f2543Smrg *  Set the cursor sprite and position.
223706f2543Smrg */
224706f2543Smrgstatic void
225706f2543SmrgQuartzSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
226706f2543Smrg{
227706f2543Smrg    QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
228706f2543Smrg
229706f2543Smrg    if (!XQuartzServerVisible)
230706f2543Smrg        return;
231706f2543Smrg
232706f2543Smrg    if (pCursor == NULL)
233706f2543Smrg    {
234706f2543Smrg        if (ScreenPriv->cursorVisible)
235706f2543Smrg        {
236706f2543Smrg            xp_hide_cursor();
237706f2543Smrg            ScreenPriv->cursorVisible = FALSE;
238706f2543Smrg        }
239706f2543Smrg    }
240706f2543Smrg    else
241706f2543Smrg    {
242706f2543Smrg        load_cursor(pCursor, pScreen->myNum);
243706f2543Smrg
244706f2543Smrg        if (!ScreenPriv->cursorVisible)
245706f2543Smrg        {
246706f2543Smrg            xp_show_cursor();
247706f2543Smrg            ScreenPriv->cursorVisible = TRUE;
248706f2543Smrg        }
249706f2543Smrg    }
250706f2543Smrg}
251706f2543Smrg
252706f2543Smrg/*
253706f2543Smrg * QuartzMoveCursor
254706f2543Smrg *  Move the cursor. This is a noop for us.
255706f2543Smrg */
256706f2543Smrgstatic void
257706f2543SmrgQuartzMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
258706f2543Smrg{
259706f2543Smrg}
260706f2543Smrg
261706f2543Smrg/*
262706f2543Smrg===========================================================================
263706f2543Smrg
264706f2543Smrg Pointer screen functions
265706f2543Smrg
266706f2543Smrg===========================================================================
267706f2543Smrg*/
268706f2543Smrg
269706f2543Smrg/*
270706f2543Smrg * QuartzCursorOffScreen
271706f2543Smrg */
272706f2543Smrgstatic Bool
273706f2543SmrgQuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
274706f2543Smrg{
275706f2543Smrg    return FALSE;
276706f2543Smrg}
277706f2543Smrg
278706f2543Smrg
279706f2543Smrg/*
280706f2543Smrg * QuartzCrossScreen
281706f2543Smrg */
282706f2543Smrgstatic void
283706f2543SmrgQuartzCrossScreen(ScreenPtr pScreen, Bool entering)
284706f2543Smrg{
285706f2543Smrg    return;
286706f2543Smrg}
287706f2543Smrg
288706f2543Smrg
289706f2543Smrg/*
290706f2543Smrg * QuartzWarpCursor
291706f2543Smrg *  Change the cursor position without generating an event or motion history.
292706f2543Smrg *  The input coordinates (x,y) are in pScreen-local X11 coordinates.
293706f2543Smrg *
294706f2543Smrg */
295706f2543Smrgstatic void
296706f2543SmrgQuartzWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
297706f2543Smrg{
298706f2543Smrg    if (XQuartzServerVisible)
299706f2543Smrg    {
300706f2543Smrg        int sx, sy;
301706f2543Smrg
302706f2543Smrg        sx = pScreen->x + darwinMainScreenX;
303706f2543Smrg        sy = pScreen->y + darwinMainScreenY;
304706f2543Smrg
305706f2543Smrg        CGWarpMouseCursorPosition(CGPointMake(sx + x, sy + y));
306706f2543Smrg    }
307706f2543Smrg
308706f2543Smrg    miPointerWarpCursor(pDev, pScreen, x, y);
309706f2543Smrg    miPointerUpdateSprite(pDev);
310706f2543Smrg}
311706f2543Smrg
312706f2543Smrg
313706f2543Smrgstatic miPointerScreenFuncRec quartzScreenFuncsRec = {
314706f2543Smrg    QuartzCursorOffScreen,
315706f2543Smrg    QuartzCrossScreen,
316706f2543Smrg    QuartzWarpCursor,
317706f2543Smrg    NULL,
318706f2543Smrg    NULL
319706f2543Smrg};
320706f2543Smrg
321706f2543Smrg
322706f2543Smrg/*
323706f2543Smrg===========================================================================
324706f2543Smrg
325706f2543Smrg Other screen functions
326706f2543Smrg
327706f2543Smrg===========================================================================
328706f2543Smrg*/
329706f2543Smrg
330706f2543Smrg/*
331706f2543Smrg * QuartzCursorQueryBestSize
332706f2543Smrg *  Handle queries for best cursor size
333706f2543Smrg */
334706f2543Smrgstatic void
335706f2543SmrgQuartzCursorQueryBestSize(int class, unsigned short *width,
336706f2543Smrg                          unsigned short *height, ScreenPtr pScreen)
337706f2543Smrg{
338706f2543Smrg    QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
339706f2543Smrg
340706f2543Smrg    if (class == CursorShape)
341706f2543Smrg    {
342706f2543Smrg        /* FIXME: query window server? */
343706f2543Smrg        *width = 32;
344706f2543Smrg        *height = 32;
345706f2543Smrg    }
346706f2543Smrg    else
347706f2543Smrg    {
348706f2543Smrg        (*ScreenPriv->QueryBestSize)(class, width, height, pScreen);
349706f2543Smrg    }
350706f2543Smrg}
351706f2543Smrg
352706f2543Smrg/*
353706f2543Smrg * QuartzInitCursor
354706f2543Smrg *  Initialize cursor support
355706f2543Smrg */
356706f2543SmrgBool
357706f2543SmrgQuartzInitCursor(ScreenPtr pScreen)
358706f2543Smrg{
359706f2543Smrg    QuartzCursorScreenPtr ScreenPriv;
360706f2543Smrg    miPointerScreenPtr PointPriv;
361706f2543Smrg
362706f2543Smrg    /* initialize software cursor handling (always needed as backup) */
363706f2543Smrg    if (!miDCInitialize(pScreen, &quartzScreenFuncsRec))
364706f2543Smrg        return FALSE;
365706f2543Smrg
366706f2543Smrg    if (!dixRegisterPrivateKey(&darwinCursorScreenKeyRec, PRIVATE_SCREEN, 0))
367706f2543Smrg	return FALSE;
368706f2543Smrg
369706f2543Smrg    ScreenPriv = calloc(1, sizeof(QuartzCursorScreenRec));
370706f2543Smrg    if (ScreenPriv == NULL)
371706f2543Smrg        return FALSE;
372706f2543Smrg
373706f2543Smrg    /* CURSOR_PRIV(pScreen) = ScreenPriv; */
374706f2543Smrg    dixSetPrivate(&pScreen->devPrivates, darwinCursorScreenKey, ScreenPriv);
375706f2543Smrg
376706f2543Smrg    /* override some screen procedures */
377706f2543Smrg    ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
378706f2543Smrg    pScreen->QueryBestSize = QuartzCursorQueryBestSize;
379706f2543Smrg
380706f2543Smrg    PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
381706f2543Smrg
382706f2543Smrg    ScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
383706f2543Smrg
384706f2543Smrg    PointPriv->spriteFuncs->RealizeCursor = QuartzRealizeCursor;
385706f2543Smrg    PointPriv->spriteFuncs->UnrealizeCursor = QuartzUnrealizeCursor;
386706f2543Smrg    PointPriv->spriteFuncs->SetCursor = QuartzSetCursor;
387706f2543Smrg    PointPriv->spriteFuncs->MoveCursor = QuartzMoveCursor;
388706f2543Smrg
389706f2543Smrg    ScreenPriv->cursorVisible = TRUE;
390706f2543Smrg    return TRUE;
391706f2543Smrg}
392706f2543Smrg
393706f2543Smrg/*
394706f2543Smrg * QuartzSuspendXCursor
395706f2543Smrg *  X server is hiding. Restore the Aqua cursor.
396706f2543Smrg */
397706f2543Smrgvoid
398706f2543SmrgQuartzSuspendXCursor(ScreenPtr pScreen)
399706f2543Smrg{
400706f2543Smrg}
401706f2543Smrg
402706f2543Smrg
403706f2543Smrg/*
404706f2543Smrg * QuartzResumeXCursor
405706f2543Smrg *  X server is showing. Restore the X cursor.
406706f2543Smrg */
407706f2543Smrgvoid
408706f2543SmrgQuartzResumeXCursor(ScreenPtr pScreen)
409706f2543Smrg{
410706f2543Smrg    WindowPtr pWin;
411706f2543Smrg    CursorPtr pCursor;
412706f2543Smrg
413706f2543Smrg    /* TODO: Tablet? */
414706f2543Smrg
415706f2543Smrg    pWin = GetSpriteWindow(darwinPointer);
416706f2543Smrg    if (pWin->drawable.pScreen != pScreen)
417706f2543Smrg        return;
418706f2543Smrg
419706f2543Smrg    pCursor = GetSpriteCursor(darwinPointer);
420706f2543Smrg    if (pCursor == NULL)
421706f2543Smrg        return;
422706f2543Smrg
423706f2543Smrg    QuartzSetCursor(darwinPointer, pScreen, pCursor, /* x */ 0, /* y */ 0);
424706f2543Smrg}
425