105b261ecSmrg/*
205b261ecSmrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
305b261ecSmrg *
405b261ecSmrg *Permission is hereby granted, free of charge, to any person obtaining
505b261ecSmrg * a copy of this software and associated documentation files (the
605b261ecSmrg *"Software"), to deal in the Software without restriction, including
705b261ecSmrg *without limitation the rights to use, copy, modify, merge, publish,
805b261ecSmrg *distribute, sublicense, and/or sell copies of the Software, and to
905b261ecSmrg *permit persons to whom the Software is furnished to do so, subject to
1005b261ecSmrg *the following conditions:
1105b261ecSmrg *
1205b261ecSmrg *The above copyright notice and this permission notice shall be
1305b261ecSmrg *included in all copies or substantial portions of the Software.
1405b261ecSmrg *
1505b261ecSmrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1605b261ecSmrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1705b261ecSmrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1805b261ecSmrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
1905b261ecSmrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
2005b261ecSmrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2105b261ecSmrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2205b261ecSmrg *
2305b261ecSmrg *Except as contained in this notice, the name of the XFree86 Project
2405b261ecSmrg *shall not be used in advertising or otherwise to promote the sale, use
2505b261ecSmrg *or other dealings in this Software without prior written authorization
2605b261ecSmrg *from the XFree86 Project.
2705b261ecSmrg *
2805b261ecSmrg * Authors:	Dakshinamurthy Karra
2905b261ecSmrg *		Suhaib M Siddiqi
3005b261ecSmrg *		Peter Busch
3105b261ecSmrg *		Harold L Hunt II
3205b261ecSmrg */
3305b261ecSmrg
3405b261ecSmrg#ifdef HAVE_XWIN_CONFIG_H
3505b261ecSmrg#include <xwin-config.h>
3605b261ecSmrg#endif
3705b261ecSmrg#include "win.h"
3805b261ecSmrg#include "winmsg.h"
3905b261ecSmrg#include <cursorstr.h>
4005b261ecSmrg#include <mipointrst.h>
4105b261ecSmrg#include <servermd.h>
426747b715Smrg#include "misc.h"
4305b261ecSmrg
4405b261ecSmrg#define BRIGHTNESS(x) (x##Red * 0.299 + x##Green * 0.587 + x##Blue * 0.114)
4505b261ecSmrg
4605b261ecSmrg#if 0
4735c4bbdfSmrg#define WIN_DEBUG_MSG winDebug
4805b261ecSmrg#else
4935c4bbdfSmrg#define WIN_DEBUG_MSG(...)
5005b261ecSmrg#endif
5105b261ecSmrg
5205b261ecSmrg/*
5305b261ecSmrg * Local function prototypes
5405b261ecSmrg */
5505b261ecSmrg
5605b261ecSmrgstatic void
5735c4bbdfSmrg winPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y);
5805b261ecSmrg
5905b261ecSmrgstatic Bool
6035c4bbdfSmrg winCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y);
6105b261ecSmrg
6205b261ecSmrgstatic void
6335c4bbdfSmrg winCrossScreen(ScreenPtr pScreen, Bool fEntering);
6405b261ecSmrg
6535c4bbdfSmrgmiPointerScreenFuncRec g_winPointerCursorFuncs = {
6635c4bbdfSmrg    winCursorOffScreen,
6735c4bbdfSmrg    winCrossScreen,
6835c4bbdfSmrg    winPointerWarpCursor
6905b261ecSmrg};
7005b261ecSmrg
7105b261ecSmrgstatic void
7235c4bbdfSmrgwinPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
7305b261ecSmrg{
7435c4bbdfSmrg    winScreenPriv(pScreen);
7535c4bbdfSmrg    RECT rcClient;
7635c4bbdfSmrg    static Bool s_fInitialWarp = TRUE;
7735c4bbdfSmrg
7835c4bbdfSmrg    /* Discard first warp call */
7935c4bbdfSmrg    if (s_fInitialWarp) {
8035c4bbdfSmrg        /* First warp moves mouse to center of window, just ignore it */
8135c4bbdfSmrg
8235c4bbdfSmrg        /* Don't ignore subsequent warps */
8335c4bbdfSmrg        s_fInitialWarp = FALSE;
8435c4bbdfSmrg
8535c4bbdfSmrg        winErrorFVerb(2,
8635c4bbdfSmrg                      "winPointerWarpCursor - Discarding first warp: %d %d\n",
8735c4bbdfSmrg                      x, y);
8835c4bbdfSmrg
8935c4bbdfSmrg        return;
9005b261ecSmrg    }
9105b261ecSmrg
9235c4bbdfSmrg    /*
9335c4bbdfSmrg       Only update the Windows cursor position if root window is active,
9435c4bbdfSmrg       or we are in a rootless mode
9535c4bbdfSmrg     */
9635c4bbdfSmrg    if ((pScreenPriv->hwndScreen == GetForegroundWindow())
9735c4bbdfSmrg        || pScreenPriv->pScreenInfo->fRootless
9835c4bbdfSmrg        || pScreenPriv->pScreenInfo->fMultiWindow
9935c4bbdfSmrg        ) {
10035c4bbdfSmrg        /* Get the client area coordinates */
10135c4bbdfSmrg        GetClientRect(pScreenPriv->hwndScreen, &rcClient);
10235c4bbdfSmrg
10335c4bbdfSmrg        /* Translate the client area coords to screen coords */
10435c4bbdfSmrg        MapWindowPoints(pScreenPriv->hwndScreen,
10535c4bbdfSmrg                        HWND_DESKTOP, (LPPOINT) &rcClient, 2);
10635c4bbdfSmrg
10735c4bbdfSmrg        /*
10835c4bbdfSmrg         * Update the Windows cursor position so that we don't
10935c4bbdfSmrg         * immediately warp back to the current position.
11035c4bbdfSmrg         */
11135c4bbdfSmrg        SetCursorPos(rcClient.left + x, rcClient.top + y);
11205b261ecSmrg    }
11305b261ecSmrg
11435c4bbdfSmrg    /* Call the mi warp procedure to do the actual warping in X. */
11535c4bbdfSmrg    miPointerWarpCursor(pDev, pScreen, x, y);
11605b261ecSmrg}
11705b261ecSmrg
11805b261ecSmrgstatic Bool
11935c4bbdfSmrgwinCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
12005b261ecSmrg{
12135c4bbdfSmrg    return FALSE;
12205b261ecSmrg}
12305b261ecSmrg
12405b261ecSmrgstatic void
12535c4bbdfSmrgwinCrossScreen(ScreenPtr pScreen, Bool fEntering)
12605b261ecSmrg{
12705b261ecSmrg}
12805b261ecSmrg
12905b261ecSmrgstatic unsigned char
13005b261ecSmrgreverse(unsigned char c)
13105b261ecSmrg{
13235c4bbdfSmrg    int i;
13335c4bbdfSmrg    unsigned char ret = 0;
13435c4bbdfSmrg
13535c4bbdfSmrg    for (i = 0; i < 8; ++i) {
13635c4bbdfSmrg        ret |= ((c >> i) & 1) << (7 - i);
13705b261ecSmrg    }
13835c4bbdfSmrg    return ret;
13905b261ecSmrg}
14005b261ecSmrg
14105b261ecSmrg/*
14205b261ecSmrg * Convert X cursor to Windows cursor
14305b261ecSmrg * FIXME: Perhaps there are more smart code
14405b261ecSmrg */
14505b261ecSmrgstatic HCURSOR
14635c4bbdfSmrgwinLoadCursor(ScreenPtr pScreen, CursorPtr pCursor, int screen)
14705b261ecSmrg{
14835c4bbdfSmrg    winScreenPriv(pScreen);
14935c4bbdfSmrg    HCURSOR hCursor = NULL;
15035c4bbdfSmrg    unsigned char *pAnd;
15135c4bbdfSmrg    unsigned char *pXor;
15235c4bbdfSmrg    int nCX, nCY;
15335c4bbdfSmrg    int nBytes;
15435c4bbdfSmrg    double dForeY, dBackY;
15535c4bbdfSmrg    BOOL fReverse;
15635c4bbdfSmrg    HBITMAP hAnd, hXor;
15735c4bbdfSmrg    ICONINFO ii;
15835c4bbdfSmrg    unsigned char *pCur;
15935c4bbdfSmrg    unsigned char bit;
16035c4bbdfSmrg    HDC hDC;
16135c4bbdfSmrg    BITMAPV4HEADER bi;
16235c4bbdfSmrg    BITMAPINFO *pbmi;
16335c4bbdfSmrg    uint32_t *lpBits;
16435c4bbdfSmrg
16535c4bbdfSmrg    WIN_DEBUG_MSG("winLoadCursor: Win32: %dx%d X11: %dx%d hotspot: %d,%d\n",
16635c4bbdfSmrg                  pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy,
16735c4bbdfSmrg                  pCursor->bits->width, pCursor->bits->height,
16835c4bbdfSmrg                  pCursor->bits->xhot, pCursor->bits->yhot);
16935c4bbdfSmrg
17035c4bbdfSmrg    /* We can use only White and Black, so calc brightness of color
17135c4bbdfSmrg     * Also check if the cursor is inverted */
17235c4bbdfSmrg    dForeY = BRIGHTNESS(pCursor->fore);
17335c4bbdfSmrg    dBackY = BRIGHTNESS(pCursor->back);
17435c4bbdfSmrg    fReverse = dForeY < dBackY;
17535c4bbdfSmrg
176ed6184dfSmrg    /* Check whether the X11 cursor is bigger than the win32 cursor */
17735c4bbdfSmrg    if (pScreenPriv->cursor.sm_cx < pCursor->bits->width ||
17835c4bbdfSmrg        pScreenPriv->cursor.sm_cy < pCursor->bits->height) {
17935c4bbdfSmrg        winErrorFVerb(3,
18035c4bbdfSmrg                      "winLoadCursor - Windows requires %dx%d cursor but X requires %dx%d\n",
18135c4bbdfSmrg                      pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy,
18235c4bbdfSmrg                      pCursor->bits->width, pCursor->bits->height);
18305b261ecSmrg    }
18405b261ecSmrg
18535c4bbdfSmrg    /* Get the number of bytes required to store the whole cursor image
18635c4bbdfSmrg     * This is roughly (sm_cx * sm_cy) / 8
18735c4bbdfSmrg     * round up to 8 pixel boundary so we can convert whole bytes */
18835c4bbdfSmrg    nBytes =
18935c4bbdfSmrg        bits_to_bytes(pScreenPriv->cursor.sm_cx) * pScreenPriv->cursor.sm_cy;
19035c4bbdfSmrg
19135c4bbdfSmrg    /* Get the effective width and height */
19235c4bbdfSmrg    nCX = min(pScreenPriv->cursor.sm_cx, pCursor->bits->width);
19335c4bbdfSmrg    nCY = min(pScreenPriv->cursor.sm_cy, pCursor->bits->height);
19435c4bbdfSmrg
19535c4bbdfSmrg    /* Allocate memory for the bitmaps */
19635c4bbdfSmrg    pAnd = malloc(nBytes);
19735c4bbdfSmrg    memset(pAnd, 0xFF, nBytes);
19835c4bbdfSmrg    pXor = calloc(1, nBytes);
19935c4bbdfSmrg
20035c4bbdfSmrg    /* Convert the X11 bitmap to a win32 bitmap
20135c4bbdfSmrg     * The first is for an empty mask */
20235c4bbdfSmrg    if (pCursor->bits->emptyMask) {
20335c4bbdfSmrg        int x, y, xmax = bits_to_bytes(nCX);
20435c4bbdfSmrg
20535c4bbdfSmrg        for (y = 0; y < nCY; ++y)
20635c4bbdfSmrg            for (x = 0; x < xmax; ++x) {
20735c4bbdfSmrg                int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x;
20835c4bbdfSmrg                int nXPix = BitmapBytePad(pCursor->bits->width) * y + x;
20935c4bbdfSmrg
21035c4bbdfSmrg                pAnd[nWinPix] = 0;
21135c4bbdfSmrg                if (fReverse)
21235c4bbdfSmrg                    pXor[nWinPix] = reverse(~pCursor->bits->source[nXPix]);
21335c4bbdfSmrg                else
21435c4bbdfSmrg                    pXor[nWinPix] = reverse(pCursor->bits->source[nXPix]);
21535c4bbdfSmrg            }
21605b261ecSmrg    }
21735c4bbdfSmrg    else {
21835c4bbdfSmrg        int x, y, xmax = bits_to_bytes(nCX);
21935c4bbdfSmrg
22035c4bbdfSmrg        for (y = 0; y < nCY; ++y)
22135c4bbdfSmrg            for (x = 0; x < xmax; ++x) {
22235c4bbdfSmrg                int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x;
22335c4bbdfSmrg                int nXPix = BitmapBytePad(pCursor->bits->width) * y + x;
22435c4bbdfSmrg
22535c4bbdfSmrg                unsigned char mask = pCursor->bits->mask[nXPix];
22635c4bbdfSmrg
22735c4bbdfSmrg                pAnd[nWinPix] = reverse(~mask);
22835c4bbdfSmrg                if (fReverse)
22935c4bbdfSmrg                    pXor[nWinPix] =
23035c4bbdfSmrg                        reverse(~pCursor->bits->source[nXPix] & mask);
23135c4bbdfSmrg                else
23235c4bbdfSmrg                    pXor[nWinPix] =
23335c4bbdfSmrg                        reverse(pCursor->bits->source[nXPix] & mask);
23435c4bbdfSmrg            }
23505b261ecSmrg    }
23605b261ecSmrg
23735c4bbdfSmrg    /* prepare the pointers */
23835c4bbdfSmrg    hCursor = NULL;
23935c4bbdfSmrg    lpBits = NULL;
24035c4bbdfSmrg
24135c4bbdfSmrg    /* We have a truecolor alpha-blended cursor and can use it! */
24235c4bbdfSmrg    if (pCursor->bits->argb) {
24335c4bbdfSmrg        WIN_DEBUG_MSG("winLoadCursor: Trying truecolor alphablended cursor\n");
24435c4bbdfSmrg        memset(&bi, 0, sizeof(BITMAPV4HEADER));
24535c4bbdfSmrg        bi.bV4Size = sizeof(BITMAPV4HEADER);
24635c4bbdfSmrg        bi.bV4Width = pScreenPriv->cursor.sm_cx;
24735c4bbdfSmrg        bi.bV4Height = -(pScreenPriv->cursor.sm_cy);    /* right-side up */
24835c4bbdfSmrg        bi.bV4Planes = 1;
24935c4bbdfSmrg        bi.bV4BitCount = 32;
25035c4bbdfSmrg        bi.bV4V4Compression = BI_BITFIELDS;
25135c4bbdfSmrg        bi.bV4RedMask = 0x00FF0000;
25235c4bbdfSmrg        bi.bV4GreenMask = 0x0000FF00;
25335c4bbdfSmrg        bi.bV4BlueMask = 0x000000FF;
25435c4bbdfSmrg        bi.bV4AlphaMask = 0xFF000000;
25535c4bbdfSmrg
25635c4bbdfSmrg        lpBits = calloc(pScreenPriv->cursor.sm_cx * pScreenPriv->cursor.sm_cy,
25735c4bbdfSmrg                        sizeof(uint32_t));
25835c4bbdfSmrg
25935c4bbdfSmrg        if (lpBits) {
26035c4bbdfSmrg            int y;
26135c4bbdfSmrg            for (y = 0; y < nCY; y++) {
26235c4bbdfSmrg                void *src, *dst;
26335c4bbdfSmrg                src = &(pCursor->bits->argb[y * pCursor->bits->width]);
26435c4bbdfSmrg                dst = &(lpBits[y * pScreenPriv->cursor.sm_cx]);
26535c4bbdfSmrg                memcpy(dst, src, 4 * nCX);
26635c4bbdfSmrg            }
26735c4bbdfSmrg        }
26835c4bbdfSmrg    }                           /* End if-truecolor-icon */
26935c4bbdfSmrg
27035c4bbdfSmrg    if (!lpBits) {
27135c4bbdfSmrg        RGBQUAD *pbmiColors;
27235c4bbdfSmrg        /* Bicolor, use a palettized DIB */
27335c4bbdfSmrg        WIN_DEBUG_MSG("winLoadCursor: Trying two color cursor\n");
27435c4bbdfSmrg        pbmi = (BITMAPINFO *) &bi;
27535c4bbdfSmrg        pbmiColors = &(pbmi->bmiColors[0]);
27635c4bbdfSmrg
27735c4bbdfSmrg        memset(pbmi, 0, sizeof(BITMAPINFOHEADER));
27835c4bbdfSmrg        pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
27935c4bbdfSmrg        pbmi->bmiHeader.biWidth = pScreenPriv->cursor.sm_cx;
28035c4bbdfSmrg        pbmi->bmiHeader.biHeight = -abs(pScreenPriv->cursor.sm_cy);     /* right-side up */
28135c4bbdfSmrg        pbmi->bmiHeader.biPlanes = 1;
28235c4bbdfSmrg        pbmi->bmiHeader.biBitCount = 8;
28335c4bbdfSmrg        pbmi->bmiHeader.biCompression = BI_RGB;
28435c4bbdfSmrg        pbmi->bmiHeader.biSizeImage = 0;
28535c4bbdfSmrg        pbmi->bmiHeader.biClrUsed = 3;
28635c4bbdfSmrg        pbmi->bmiHeader.biClrImportant = 3;
28735c4bbdfSmrg
28835c4bbdfSmrg        pbmiColors[0].rgbRed = 0;  /* Empty */
28935c4bbdfSmrg        pbmiColors[0].rgbGreen = 0;
29035c4bbdfSmrg        pbmiColors[0].rgbBlue = 0;
29135c4bbdfSmrg        pbmiColors[0].rgbReserved = 0;
29235c4bbdfSmrg        pbmiColors[1].rgbRed = pCursor->backRed >> 8;      /* Background */
29335c4bbdfSmrg        pbmiColors[1].rgbGreen = pCursor->backGreen >> 8;
29435c4bbdfSmrg        pbmiColors[1].rgbBlue = pCursor->backBlue >> 8;
29535c4bbdfSmrg        pbmiColors[1].rgbReserved = 0;
29635c4bbdfSmrg        pbmiColors[2].rgbRed = pCursor->foreRed >> 8;      /* Foreground */
29735c4bbdfSmrg        pbmiColors[2].rgbGreen = pCursor->foreGreen >> 8;
29835c4bbdfSmrg        pbmiColors[2].rgbBlue = pCursor->foreBlue >> 8;
29935c4bbdfSmrg        pbmiColors[2].rgbReserved = 0;
30035c4bbdfSmrg
30135c4bbdfSmrg        lpBits = calloc(pScreenPriv->cursor.sm_cx * pScreenPriv->cursor.sm_cy, 1);
30235c4bbdfSmrg
30335c4bbdfSmrg        pCur = (unsigned char *) lpBits;
30435c4bbdfSmrg        if (lpBits) {
30535c4bbdfSmrg	    int x, y;
30635c4bbdfSmrg            for (y = 0; y < pScreenPriv->cursor.sm_cy; y++) {
30735c4bbdfSmrg                for (x = 0; x < pScreenPriv->cursor.sm_cx; x++) {
30835c4bbdfSmrg                    if (x >= nCX || y >= nCY)   /* Outside of X11 icon bounds */
30935c4bbdfSmrg                        (*pCur++) = 0;
31035c4bbdfSmrg                    else {      /* Within X11 icon bounds */
31135c4bbdfSmrg
31235c4bbdfSmrg                        int nWinPix =
31335c4bbdfSmrg                            bits_to_bytes(pScreenPriv->cursor.sm_cx) * y +
31435c4bbdfSmrg                            (x / 8);
31535c4bbdfSmrg
31635c4bbdfSmrg                        bit = pAnd[nWinPix];
31735c4bbdfSmrg                        bit = bit & (1 << (7 - (x & 7)));
31835c4bbdfSmrg                        if (!bit) {     /* Within the cursor mask? */
31935c4bbdfSmrg                            int nXPix =
32035c4bbdfSmrg                                BitmapBytePad(pCursor->bits->width) * y +
32135c4bbdfSmrg                                (x / 8);
32235c4bbdfSmrg                            bit =
32335c4bbdfSmrg                                ~reverse(~pCursor->bits->
32435c4bbdfSmrg                                         source[nXPix] & pCursor->bits->
32535c4bbdfSmrg                                         mask[nXPix]);
32635c4bbdfSmrg                            bit = bit & (1 << (7 - (x & 7)));
32735c4bbdfSmrg                            if (bit)    /* Draw foreground */
32835c4bbdfSmrg                                (*pCur++) = 2;
32935c4bbdfSmrg                            else        /* Draw background */
33035c4bbdfSmrg                                (*pCur++) = 1;
33135c4bbdfSmrg                        }
33235c4bbdfSmrg                        else    /* Outside the cursor mask */
33335c4bbdfSmrg                            (*pCur++) = 0;
33435c4bbdfSmrg                    }
33535c4bbdfSmrg                }               /* end for (x) */
33635c4bbdfSmrg            }                   /* end for (y) */
33735c4bbdfSmrg        }                       /* end if (lpbits) */
33805b261ecSmrg    }
33905b261ecSmrg
34035c4bbdfSmrg    /* If one of the previous two methods gave us the bitmap we need, make a cursor */
34135c4bbdfSmrg    if (lpBits) {
34235c4bbdfSmrg        WIN_DEBUG_MSG("winLoadCursor: Creating bitmap cursor: hotspot %d,%d\n",
34335c4bbdfSmrg                      pCursor->bits->xhot, pCursor->bits->yhot);
34435c4bbdfSmrg
34535c4bbdfSmrg        hAnd = NULL;
34635c4bbdfSmrg        hXor = NULL;
34735c4bbdfSmrg
34835c4bbdfSmrg        hAnd =
34935c4bbdfSmrg            CreateBitmap(pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy,
35035c4bbdfSmrg                         1, 1, pAnd);
35135c4bbdfSmrg
35235c4bbdfSmrg        hDC = GetDC(NULL);
35335c4bbdfSmrg        if (hDC) {
35435c4bbdfSmrg            hXor =
35535c4bbdfSmrg                CreateCompatibleBitmap(hDC, pScreenPriv->cursor.sm_cx,
35635c4bbdfSmrg                                       pScreenPriv->cursor.sm_cy);
35735c4bbdfSmrg            SetDIBits(hDC, hXor, 0, pScreenPriv->cursor.sm_cy, lpBits,
35835c4bbdfSmrg                      (BITMAPINFO *) &bi, DIB_RGB_COLORS);
35935c4bbdfSmrg            ReleaseDC(NULL, hDC);
36035c4bbdfSmrg        }
36135c4bbdfSmrg        free(lpBits);
36235c4bbdfSmrg
36335c4bbdfSmrg        if (hAnd && hXor) {
36435c4bbdfSmrg            ii.fIcon = FALSE;
36535c4bbdfSmrg            ii.xHotspot = pCursor->bits->xhot;
36635c4bbdfSmrg            ii.yHotspot = pCursor->bits->yhot;
36735c4bbdfSmrg            ii.hbmMask = hAnd;
36835c4bbdfSmrg            ii.hbmColor = hXor;
36935c4bbdfSmrg            hCursor = (HCURSOR) CreateIconIndirect(&ii);
37035c4bbdfSmrg
37135c4bbdfSmrg            if (hCursor == NULL)
37235c4bbdfSmrg                winW32Error(2, "winLoadCursor - CreateIconIndirect failed:");
37335c4bbdfSmrg            else {
37435c4bbdfSmrg                if (GetIconInfo(hCursor, &ii)) {
37535c4bbdfSmrg                    if (ii.fIcon) {
37635c4bbdfSmrg                        WIN_DEBUG_MSG
37735c4bbdfSmrg                            ("winLoadCursor: CreateIconIndirect returned  no cursor. Trying again.\n");
37835c4bbdfSmrg
37935c4bbdfSmrg                        DestroyCursor(hCursor);
38035c4bbdfSmrg
38135c4bbdfSmrg                        ii.fIcon = FALSE;
38235c4bbdfSmrg                        ii.xHotspot = pCursor->bits->xhot;
38335c4bbdfSmrg                        ii.yHotspot = pCursor->bits->yhot;
38435c4bbdfSmrg                        hCursor = (HCURSOR) CreateIconIndirect(&ii);
38535c4bbdfSmrg
38635c4bbdfSmrg                        if (hCursor == NULL)
38735c4bbdfSmrg                            winW32Error(2,
38835c4bbdfSmrg                                        "winLoadCursor - CreateIconIndirect failed:");
38935c4bbdfSmrg                    }
39035c4bbdfSmrg                    /* GetIconInfo creates new bitmaps. Destroy them again */
39135c4bbdfSmrg                    if (ii.hbmMask)
39235c4bbdfSmrg                        DeleteObject(ii.hbmMask);
39335c4bbdfSmrg                    if (ii.hbmColor)
39435c4bbdfSmrg                        DeleteObject(ii.hbmColor);
39535c4bbdfSmrg                }
39635c4bbdfSmrg            }
39735c4bbdfSmrg        }
39835c4bbdfSmrg
39935c4bbdfSmrg        if (hAnd)
40035c4bbdfSmrg            DeleteObject(hAnd);
40135c4bbdfSmrg        if (hXor)
40235c4bbdfSmrg            DeleteObject(hXor);
40305b261ecSmrg    }
40405b261ecSmrg
40535c4bbdfSmrg    if (!hCursor) {
40635c4bbdfSmrg        /* We couldn't make a color cursor for this screen, use
40735c4bbdfSmrg           black and white instead */
40835c4bbdfSmrg        hCursor = CreateCursor(g_hInstance,
40935c4bbdfSmrg                               pCursor->bits->xhot, pCursor->bits->yhot,
41035c4bbdfSmrg                               pScreenPriv->cursor.sm_cx,
41135c4bbdfSmrg                               pScreenPriv->cursor.sm_cy, pAnd, pXor);
41235c4bbdfSmrg        if (hCursor == NULL)
41335c4bbdfSmrg            winW32Error(2, "winLoadCursor - CreateCursor failed:");
41405b261ecSmrg    }
41535c4bbdfSmrg    free(pAnd);
41635c4bbdfSmrg    free(pXor);
41705b261ecSmrg
41835c4bbdfSmrg    return hCursor;
41905b261ecSmrg}
42005b261ecSmrg
42105b261ecSmrg/*
42205b261ecSmrg===========================================================================
42305b261ecSmrg
42405b261ecSmrg Pointer sprite functions
42505b261ecSmrg
42605b261ecSmrg===========================================================================
42705b261ecSmrg*/
42805b261ecSmrg
42905b261ecSmrg/*
43005b261ecSmrg * winRealizeCursor
43105b261ecSmrg *  Convert the X cursor representation to native format if possible.
43205b261ecSmrg */
43305b261ecSmrgstatic Bool
43435c4bbdfSmrgwinRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
43505b261ecSmrg{
43635c4bbdfSmrg    if (pCursor == NULL || pCursor->bits == NULL)
43735c4bbdfSmrg        return FALSE;
43805b261ecSmrg
43935c4bbdfSmrg    /* FIXME: cache ARGB8888 representation? */
44005b261ecSmrg
44135c4bbdfSmrg    return TRUE;
44235c4bbdfSmrg}
44305b261ecSmrg
44405b261ecSmrg/*
44505b261ecSmrg * winUnrealizeCursor
44605b261ecSmrg *  Free the storage space associated with a realized cursor.
44705b261ecSmrg */
44805b261ecSmrgstatic Bool
4496747b715SmrgwinUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
45005b261ecSmrg{
45135c4bbdfSmrg    return TRUE;
45205b261ecSmrg}
45305b261ecSmrg
45405b261ecSmrg/*
45505b261ecSmrg * winSetCursor
45605b261ecSmrg *  Set the cursor sprite and position.
45705b261ecSmrg */
45805b261ecSmrgstatic void
45935c4bbdfSmrgwinSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x,
46035c4bbdfSmrg             int y)
46105b261ecSmrg{
46235c4bbdfSmrg    POINT ptCurPos, ptTemp;
46335c4bbdfSmrg    HWND hwnd;
46435c4bbdfSmrg    RECT rcClient;
46535c4bbdfSmrg    BOOL bInhibit;
46635c4bbdfSmrg
46735c4bbdfSmrg    winScreenPriv(pScreen);
46835c4bbdfSmrg    WIN_DEBUG_MSG("winSetCursor: cursor=%p\n", pCursor);
46935c4bbdfSmrg
47035c4bbdfSmrg    /* Inhibit changing the cursor if the mouse is not in a client area */
47135c4bbdfSmrg    bInhibit = FALSE;
47235c4bbdfSmrg    if (GetCursorPos(&ptCurPos)) {
47335c4bbdfSmrg        hwnd = WindowFromPoint(ptCurPos);
47435c4bbdfSmrg        if (hwnd) {
47535c4bbdfSmrg            if (GetClientRect(hwnd, &rcClient)) {
47635c4bbdfSmrg                ptTemp.x = rcClient.left;
47735c4bbdfSmrg                ptTemp.y = rcClient.top;
47835c4bbdfSmrg                if (ClientToScreen(hwnd, &ptTemp)) {
47935c4bbdfSmrg                    rcClient.left = ptTemp.x;
48035c4bbdfSmrg                    rcClient.top = ptTemp.y;
48135c4bbdfSmrg                    ptTemp.x = rcClient.right;
48235c4bbdfSmrg                    ptTemp.y = rcClient.bottom;
48335c4bbdfSmrg                    if (ClientToScreen(hwnd, &ptTemp)) {
48435c4bbdfSmrg                        rcClient.right = ptTemp.x;
48535c4bbdfSmrg                        rcClient.bottom = ptTemp.y;
48635c4bbdfSmrg                        if (!PtInRect(&rcClient, ptCurPos))
48735c4bbdfSmrg                            bInhibit = TRUE;
48835c4bbdfSmrg                    }
48935c4bbdfSmrg                }
49035c4bbdfSmrg            }
49135c4bbdfSmrg        }
49205b261ecSmrg    }
49305b261ecSmrg
49435c4bbdfSmrg    if (pCursor == NULL) {
49535c4bbdfSmrg        if (pScreenPriv->cursor.visible) {
49635c4bbdfSmrg            if (!bInhibit && g_fSoftwareCursor)
49735c4bbdfSmrg                ShowCursor(FALSE);
49835c4bbdfSmrg            pScreenPriv->cursor.visible = FALSE;
49935c4bbdfSmrg        }
50005b261ecSmrg    }
50135c4bbdfSmrg    else {
50235c4bbdfSmrg        if (pScreenPriv->cursor.handle) {
50335c4bbdfSmrg            if (!bInhibit)
50435c4bbdfSmrg                SetCursor(NULL);
50535c4bbdfSmrg            DestroyCursor(pScreenPriv->cursor.handle);
50635c4bbdfSmrg            pScreenPriv->cursor.handle = NULL;
50735c4bbdfSmrg        }
50835c4bbdfSmrg        pScreenPriv->cursor.handle =
50935c4bbdfSmrg            winLoadCursor(pScreen, pCursor, pScreen->myNum);
51035c4bbdfSmrg        WIN_DEBUG_MSG("winSetCursor: handle=%p\n", pScreenPriv->cursor.handle);
51135c4bbdfSmrg
51235c4bbdfSmrg        if (!bInhibit)
51335c4bbdfSmrg            SetCursor(pScreenPriv->cursor.handle);
51435c4bbdfSmrg
51535c4bbdfSmrg        if (!pScreenPriv->cursor.visible) {
51635c4bbdfSmrg            if (!bInhibit && g_fSoftwareCursor)
51735c4bbdfSmrg                ShowCursor(TRUE);
51835c4bbdfSmrg            pScreenPriv->cursor.visible = TRUE;
51935c4bbdfSmrg        }
52005b261ecSmrg    }
52105b261ecSmrg}
52205b261ecSmrg
52305b261ecSmrg/*
5246747b715Smrg * winMoveCursor
52505b261ecSmrg *  Move the cursor. This is a noop for us.
52605b261ecSmrg */
52705b261ecSmrgstatic void
52835c4bbdfSmrgwinMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
5296747b715Smrg{
5306747b715Smrg}
5316747b715Smrg
5326747b715Smrgstatic Bool
5336747b715SmrgwinDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr)
53405b261ecSmrg{
53535c4bbdfSmrg    winScreenPriv(pScr);
53635c4bbdfSmrg    return pScreenPriv->cursor.spriteFuncs->DeviceCursorInitialize(pDev, pScr);
53705b261ecSmrg}
53805b261ecSmrg
5396747b715Smrgstatic void
5406747b715SmrgwinDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr)
5416747b715Smrg{
54235c4bbdfSmrg    winScreenPriv(pScr);
54335c4bbdfSmrg    pScreenPriv->cursor.spriteFuncs->DeviceCursorCleanup(pDev, pScr);
5446747b715Smrg}
54505b261ecSmrg
54605b261ecSmrgstatic miPointerSpriteFuncRec winSpriteFuncsRec = {
54735c4bbdfSmrg    winRealizeCursor,
54835c4bbdfSmrg    winUnrealizeCursor,
54935c4bbdfSmrg    winSetCursor,
55035c4bbdfSmrg    winMoveCursor,
55135c4bbdfSmrg    winDeviceCursorInitialize,
55235c4bbdfSmrg    winDeviceCursorCleanup
55305b261ecSmrg};
55405b261ecSmrg
55505b261ecSmrg/*
55605b261ecSmrg===========================================================================
55705b261ecSmrg
55805b261ecSmrg Other screen functions
55905b261ecSmrg
56005b261ecSmrg===========================================================================
56105b261ecSmrg*/
56205b261ecSmrg
56305b261ecSmrg/*
56405b261ecSmrg * winCursorQueryBestSize
56505b261ecSmrg *  Handle queries for best cursor size
56605b261ecSmrg */
56705b261ecSmrgstatic void
56835c4bbdfSmrgwinCursorQueryBestSize(int class, unsigned short *width,
56935c4bbdfSmrg                       unsigned short *height, ScreenPtr pScreen)
57005b261ecSmrg{
57135c4bbdfSmrg    winScreenPriv(pScreen);
57235c4bbdfSmrg
57335c4bbdfSmrg    if (class == CursorShape) {
57435c4bbdfSmrg        *width = pScreenPriv->cursor.sm_cx;
57535c4bbdfSmrg        *height = pScreenPriv->cursor.sm_cy;
57605b261ecSmrg    }
57735c4bbdfSmrg    else {
57835c4bbdfSmrg        if (pScreenPriv->cursor.QueryBestSize)
57935c4bbdfSmrg            (*pScreenPriv->cursor.QueryBestSize) (class, width, height,
58035c4bbdfSmrg                                                  pScreen);
58105b261ecSmrg    }
58205b261ecSmrg}
58305b261ecSmrg
58405b261ecSmrg/*
58505b261ecSmrg * winInitCursor
58605b261ecSmrg *  Initialize cursor support
58705b261ecSmrg */
58805b261ecSmrgBool
58935c4bbdfSmrgwinInitCursor(ScreenPtr pScreen)
59005b261ecSmrg{
59135c4bbdfSmrg    winScreenPriv(pScreen);
59235c4bbdfSmrg    miPointerScreenPtr pPointPriv;
59335c4bbdfSmrg
59435c4bbdfSmrg    /* override some screen procedures */
59535c4bbdfSmrg    pScreenPriv->cursor.QueryBestSize = pScreen->QueryBestSize;
59635c4bbdfSmrg    pScreen->QueryBestSize = winCursorQueryBestSize;
59735c4bbdfSmrg
59835c4bbdfSmrg    pPointPriv = (miPointerScreenPtr)
59935c4bbdfSmrg        dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
60035c4bbdfSmrg
60135c4bbdfSmrg    pScreenPriv->cursor.spriteFuncs = pPointPriv->spriteFuncs;
60235c4bbdfSmrg    pPointPriv->spriteFuncs = &winSpriteFuncsRec;
60335c4bbdfSmrg
60435c4bbdfSmrg    pScreenPriv->cursor.handle = NULL;
60535c4bbdfSmrg    pScreenPriv->cursor.visible = FALSE;
60635c4bbdfSmrg
60735c4bbdfSmrg    pScreenPriv->cursor.sm_cx = GetSystemMetrics(SM_CXCURSOR);
60835c4bbdfSmrg    pScreenPriv->cursor.sm_cy = GetSystemMetrics(SM_CYCURSOR);
60935c4bbdfSmrg
61035c4bbdfSmrg    return TRUE;
61105b261ecSmrg}
612