1/**************************************************************
2 *
3 * Xplugin cursor support
4 *
5 * Copyright (c) 2001 Torrey T. Lyons and Greg Parker.
6 * Copyright (c) 2002 Apple Computer, Inc.
7 *                 All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the sale,
29 * use or other dealings in this Software without prior written authorization.
30 */
31
32#include "sanitizedCarbon.h"
33
34#ifdef HAVE_DIX_CONFIG_H
35#include <dix-config.h>
36#endif
37
38#include "quartz.h"
39#include "xpr.h"
40#include "darwin.h"
41#include "darwinEvents.h"
42#include <Xplugin.h>
43
44#include "mi.h"
45#include "scrnintstr.h"
46#include "cursorstr.h"
47#include "mipointrst.h"
48#include "windowstr.h"
49#include "globals.h"
50#include "servermd.h"
51#include "dixevents.h"
52#include "x-hash.h"
53
54typedef struct {
55    int                     cursorVisible;
56    QueryBestSizeProcPtr    QueryBestSize;
57    miPointerSpriteFuncPtr  spriteFuncs;
58} QuartzCursorScreenRec, *QuartzCursorScreenPtr;
59
60static DevPrivateKeyRec darwinCursorScreenKeyRec;
61#define darwinCursorScreenKey (&darwinCursorScreenKeyRec)
62
63#define CURSOR_PRIV(pScreen) ((QuartzCursorScreenPtr) \
64    dixLookupPrivate(&pScreen->devPrivates, darwinCursorScreenKey))
65
66static Bool
67load_cursor(CursorPtr src, int screen)
68{
69    uint32_t *data;
70    Bool free_data = FALSE;
71    uint32_t rowbytes;
72    int width, height;
73    int hot_x, hot_y;
74
75    uint32_t fg_color, bg_color;
76    uint8_t *srow, *sptr;
77    uint8_t *mrow, *mptr;
78    uint32_t *drow, *dptr;
79    unsigned xcount, ycount;
80
81    xp_error err;
82
83    width = src->bits->width;
84    height = src->bits->height;
85    hot_x = src->bits->xhot;
86    hot_y = src->bits->yhot;
87
88#ifdef ARGB_CURSOR
89    if (src->bits->argb != NULL)
90    {
91#if BITMAP_BIT_ORDER == MSBFirst
92        rowbytes = src->bits->width * sizeof (CARD32);
93        data = (uint32_t *) src->bits->argb;
94#else
95        const uint32_t *be_data=(uint32_t *) src->bits->argb;
96        unsigned i;
97        rowbytes = src->bits->width * sizeof (CARD32);
98        data = malloc(rowbytes * src->bits->height);
99        free_data = TRUE;
100        if(!data) {
101            FatalError("Failed to allocate memory in %s\n", __func__);
102        }
103        for(i=0;i<(src->bits->width*src->bits->height);i++)
104            data[i]=ntohl(be_data[i]);
105#endif
106    }
107    else
108#endif
109    {
110        fg_color = 0xFF00 | (src->foreRed >> 8);
111        fg_color <<= 16;
112        fg_color |= src->foreGreen & 0xFF00;
113        fg_color |= src->foreBlue >> 8;
114
115        bg_color = 0xFF00 | (src->backRed >> 8);
116        bg_color <<= 16;
117        bg_color |= src->backGreen & 0xFF00;
118        bg_color |= src->backBlue >> 8;
119
120        fg_color = htonl(fg_color);
121        bg_color = htonl(bg_color);
122
123        /* round up to 8 pixel boundary so we can convert whole bytes */
124        rowbytes = ((src->bits->width * 4) + 31) & ~31;
125        data = malloc(rowbytes * src->bits->height);
126        free_data = TRUE;
127        if(!data) {
128            FatalError("Failed to allocate memory in %s\n", __func__);
129        }
130
131        if (!src->bits->emptyMask)
132        {
133            ycount = src->bits->height;
134            srow = src->bits->source; mrow = src->bits->mask;
135            drow = data;
136
137            while (ycount-- > 0)
138            {
139                xcount = bits_to_bytes(src->bits->width);
140                sptr = srow; mptr = mrow;
141                dptr = drow;
142
143                while (xcount-- > 0)
144                {
145                    uint8_t s, m;
146                    int i;
147
148                    s = *sptr++; m = *mptr++;
149                    for (i = 0; i < 8; i++)
150                    {
151#if BITMAP_BIT_ORDER == MSBFirst
152                        if (m & 128)
153                            *dptr++ = (s & 128) ? fg_color : bg_color;
154                        else
155                            *dptr++ = 0;
156                        s <<= 1; m <<= 1;
157#else
158                        if (m & 1)
159                            *dptr++ = (s & 1) ? fg_color : bg_color;
160                        else
161                            *dptr++ = 0;
162                        s >>= 1; m >>= 1;
163#endif
164                    }
165                }
166
167                srow += BitmapBytePad(src->bits->width);
168                mrow += BitmapBytePad(src->bits->width);
169                drow = (uint32_t *) ((char *) drow + rowbytes);
170            }
171        }
172        else
173        {
174            memset(data, 0, src->bits->height * rowbytes);
175        }
176    }
177
178    err = xp_set_cursor(width, height, hot_x, hot_y, data, rowbytes);
179    if(free_data)
180        free(data);
181    return err == Success;
182}
183
184
185/*
186===========================================================================
187
188 Pointer sprite functions
189
190===========================================================================
191*/
192
193/*
194 * QuartzRealizeCursor
195 *  Convert the X cursor representation to native format if possible.
196 */
197static Bool
198QuartzRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
199{
200    if(pCursor == NULL || pCursor->bits == NULL)
201        return FALSE;
202
203    /* FIXME: cache ARGB8888 representation? */
204
205    return TRUE;
206}
207
208
209/*
210 * QuartzUnrealizeCursor
211 *  Free the storage space associated with a realized cursor.
212 */
213static Bool
214QuartzUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
215{
216    return TRUE;
217}
218
219
220/*
221 * QuartzSetCursor
222 *  Set the cursor sprite and position.
223 */
224static void
225QuartzSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
226{
227    QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
228
229    if (!XQuartzServerVisible)
230        return;
231
232    if (pCursor == NULL)
233    {
234        if (ScreenPriv->cursorVisible)
235        {
236            xp_hide_cursor();
237            ScreenPriv->cursorVisible = FALSE;
238        }
239    }
240    else
241    {
242        load_cursor(pCursor, pScreen->myNum);
243
244        if (!ScreenPriv->cursorVisible)
245        {
246            xp_show_cursor();
247            ScreenPriv->cursorVisible = TRUE;
248        }
249    }
250}
251
252/*
253 * QuartzMoveCursor
254 *  Move the cursor. This is a noop for us.
255 */
256static void
257QuartzMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
258{
259}
260
261/*
262===========================================================================
263
264 Pointer screen functions
265
266===========================================================================
267*/
268
269/*
270 * QuartzCursorOffScreen
271 */
272static Bool
273QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y)
274{
275    return FALSE;
276}
277
278
279/*
280 * QuartzCrossScreen
281 */
282static void
283QuartzCrossScreen(ScreenPtr pScreen, Bool entering)
284{
285    return;
286}
287
288
289/*
290 * QuartzWarpCursor
291 *  Change the cursor position without generating an event or motion history.
292 *  The input coordinates (x,y) are in pScreen-local X11 coordinates.
293 *
294 */
295static void
296QuartzWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
297{
298    if (XQuartzServerVisible)
299    {
300        int sx, sy;
301
302        sx = pScreen->x + darwinMainScreenX;
303        sy = pScreen->y + darwinMainScreenY;
304
305        CGWarpMouseCursorPosition(CGPointMake(sx + x, sy + y));
306    }
307
308    miPointerWarpCursor(pDev, pScreen, x, y);
309    miPointerUpdateSprite(pDev);
310}
311
312
313static miPointerScreenFuncRec quartzScreenFuncsRec = {
314    QuartzCursorOffScreen,
315    QuartzCrossScreen,
316    QuartzWarpCursor,
317    NULL,
318    NULL
319};
320
321
322/*
323===========================================================================
324
325 Other screen functions
326
327===========================================================================
328*/
329
330/*
331 * QuartzCursorQueryBestSize
332 *  Handle queries for best cursor size
333 */
334static void
335QuartzCursorQueryBestSize(int class, unsigned short *width,
336                          unsigned short *height, ScreenPtr pScreen)
337{
338    QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen);
339
340    if (class == CursorShape)
341    {
342        /* FIXME: query window server? */
343        *width = 32;
344        *height = 32;
345    }
346    else
347    {
348        (*ScreenPriv->QueryBestSize)(class, width, height, pScreen);
349    }
350}
351
352/*
353 * QuartzInitCursor
354 *  Initialize cursor support
355 */
356Bool
357QuartzInitCursor(ScreenPtr pScreen)
358{
359    QuartzCursorScreenPtr ScreenPriv;
360    miPointerScreenPtr PointPriv;
361
362    /* initialize software cursor handling (always needed as backup) */
363    if (!miDCInitialize(pScreen, &quartzScreenFuncsRec))
364        return FALSE;
365
366    if (!dixRegisterPrivateKey(&darwinCursorScreenKeyRec, PRIVATE_SCREEN, 0))
367	return FALSE;
368
369    ScreenPriv = calloc(1, sizeof(QuartzCursorScreenRec));
370    if (ScreenPriv == NULL)
371        return FALSE;
372
373    /* CURSOR_PRIV(pScreen) = ScreenPriv; */
374    dixSetPrivate(&pScreen->devPrivates, darwinCursorScreenKey, ScreenPriv);
375
376    /* override some screen procedures */
377    ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
378    pScreen->QueryBestSize = QuartzCursorQueryBestSize;
379
380    PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
381
382    ScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
383
384    PointPriv->spriteFuncs->RealizeCursor = QuartzRealizeCursor;
385    PointPriv->spriteFuncs->UnrealizeCursor = QuartzUnrealizeCursor;
386    PointPriv->spriteFuncs->SetCursor = QuartzSetCursor;
387    PointPriv->spriteFuncs->MoveCursor = QuartzMoveCursor;
388
389    ScreenPriv->cursorVisible = TRUE;
390    return TRUE;
391}
392
393/*
394 * QuartzSuspendXCursor
395 *  X server is hiding. Restore the Aqua cursor.
396 */
397void
398QuartzSuspendXCursor(ScreenPtr pScreen)
399{
400}
401
402
403/*
404 * QuartzResumeXCursor
405 *  X server is showing. Restore the X cursor.
406 */
407void
408QuartzResumeXCursor(ScreenPtr pScreen)
409{
410    WindowPtr pWin;
411    CursorPtr pCursor;
412
413    /* TODO: Tablet? */
414
415    pWin = GetSpriteWindow(darwinPointer);
416    if (pWin->drawable.pScreen != pScreen)
417        return;
418
419    pCursor = GetSpriteCursor(darwinPointer);
420    if (pCursor == NULL)
421        return;
422
423    QuartzSetCursor(darwinPointer, pScreen, pCursor, /* x */ 0, /* y */ 0);
424}
425