diff options
Diffstat (limited to 'xorg-server/hw/xwin/wincursor.c')
-rw-r--r-- | xorg-server/hw/xwin/wincursor.c | 1258 |
1 files changed, 628 insertions, 630 deletions
diff --git a/xorg-server/hw/xwin/wincursor.c b/xorg-server/hw/xwin/wincursor.c index a29e90c66..3cae2361b 100644 --- a/xorg-server/hw/xwin/wincursor.c +++ b/xorg-server/hw/xwin/wincursor.c @@ -1,630 +1,628 @@ -/* - *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of the XFree86 Project - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from the XFree86 Project. - * - * Authors: Dakshinamurthy Karra - * Suhaib M Siddiqi - * Peter Busch - * Harold L Hunt II - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include <xwin-config.h> -#endif -#include "win.h" -#include "winmsg.h" -#include <cursorstr.h> -#include <mipointrst.h> -#include <servermd.h> -#include "misc.h" - -extern Bool g_fSoftwareCursor; - -#define BRIGHTNESS(x) (x##Red * 0.299 + x##Green * 0.587 + x##Blue * 0.114) - -#ifdef _MSC_VER -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -/* - * Local function prototypes - */ - -static void -winPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); - -static Bool -winCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y); - -static void -winCrossScreen (ScreenPtr pScreen, Bool fEntering); - -miPointerScreenFuncRec g_winPointerCursorFuncs = -{ - winCursorOffScreen, - winCrossScreen, - winPointerWarpCursor -}; - - -static void -winPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - winScreenPriv(pScreen); - RECT rcClient; - static Bool s_fInitialWarp = TRUE; - - /* Discard first warp call */ - if (s_fInitialWarp) - { - /* First warp moves mouse to center of window, just ignore it */ - - /* Don't ignore subsequent warps */ - s_fInitialWarp = FALSE; - - winDebug ("winPointerWarpCursor - Discarding first warp: %d %d\n", - x, y); - - return; - } - - /* - Only update the Windows cursor position if root window is active, - or we are in a rootless mode - */ - if ((pScreenPriv->hwndScreen == GetForegroundWindow ()) - || pScreenPriv->pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOW - || pScreenPriv->pScreenInfo->fMultiWindow -#endif - ) - { - /* Get the client area coordinates */ - GetClientRect (pScreenPriv->hwndScreen, &rcClient); - - /* Translate the client area coords to screen coords */ - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&rcClient, - 2); - - /* - * Update the Windows cursor position so that we don't - * immediately warp back to the current position. - */ - SetCursorPos (rcClient.left + x, rcClient.top + y); - } - - /* Call the mi warp procedure to do the actual warping in X. */ - miPointerWarpCursor (pDev, pScreen, x, y); -} - -static Bool -winCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y) -{ - return FALSE; -} - -static void -winCrossScreen (ScreenPtr pScreen, Bool fEntering) -{ -} - -static unsigned char -reverse(unsigned char c) -{ - int i; - unsigned char ret = 0; - for (i = 0; i < 8; ++i) - { - ret |= ((c >> i)&1) << (7 - i); - } - return ret; -} - -/* - * Convert X cursor to Windows cursor - * FIXME: Perhaps there are more smart code - */ -static HCURSOR -winLoadCursor (ScreenPtr pScreen, CursorPtr pCursor, int screen) -{ - winScreenPriv(pScreen); - HCURSOR hCursor = NULL; - unsigned char *pAnd; - unsigned char *pXor; - int nCX, nCY; - int nBytes; - double dForeY, dBackY; - BOOL fReverse; - HBITMAP hAnd, hXor; - ICONINFO ii; - unsigned char *pCur; - int x, y; - unsigned char bit; - HDC hDC; - BITMAPV4HEADER bi; - BITMAPINFO *pbmi; - unsigned long *lpBits; - - winDebug("winLoadCursor: Win32: %dx%d X11: %dx%d hotspot: %d,%d\n", - pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy, - pCursor->bits->width, pCursor->bits->height, - pCursor->bits->xhot, pCursor->bits->yhot - ); - - /* We can use only White and Black, so calc brightness of color - * Also check if the cursor is inverted */ - dForeY = BRIGHTNESS(pCursor->fore); - dBackY = BRIGHTNESS(pCursor->back); - fReverse = dForeY < dBackY; - - /* Check wether the X11 cursor is bigger than the win32 cursor */ - if (pScreenPriv->cursor.sm_cx < pCursor->bits->width || - pScreenPriv->cursor.sm_cy < pCursor->bits->height) - { - ErrorF ("winLoadCursor - Windows requires %dx%d cursor but X requires %dx%d\n", - pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy, - pCursor->bits->width, pCursor->bits->height); - } - - /* Get the number of bytes required to store the whole cursor image - * This is roughly (sm_cx * sm_cy) / 8 - * round up to 8 pixel boundary so we can convert whole bytes */ - nBytes = bits_to_bytes(pScreenPriv->cursor.sm_cx) * pScreenPriv->cursor.sm_cy; - - /* Get the effective width and height */ - nCX = min(pScreenPriv->cursor.sm_cx, pCursor->bits->width); - nCY = min(pScreenPriv->cursor.sm_cy, pCursor->bits->height); - - /* Allocate memory for the bitmaps */ - pAnd = malloc (nBytes); - memset (pAnd, 0xFF, nBytes); - pXor = calloc (1, nBytes); - - /* Convert the X11 bitmap to a win32 bitmap - * The first is for an empty mask */ - if (pCursor->bits->emptyMask) - { - int x, y, xmax = bits_to_bytes(nCX); - for (y = 0; y < nCY; ++y) - for (x = 0; x < xmax; ++x) - { - int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x; - int nXPix = BitmapBytePad(pCursor->bits->width) * y + x; - - pAnd[nWinPix] = 0; - if (fReverse) - pXor[nWinPix] = reverse (~pCursor->bits->source[nXPix]); - else - pXor[nWinPix] = reverse (pCursor->bits->source[nXPix]); - } - } - else - { - int x, y, xmax = bits_to_bytes(nCX); - for (y = 0; y < nCY; ++y) - for (x = 0; x < xmax; ++x) - { - int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x; - int nXPix = BitmapBytePad(pCursor->bits->width) * y + x; - - unsigned char mask = pCursor->bits->mask[nXPix]; - pAnd[nWinPix] = reverse (~mask); - if (fReverse) - pXor[nWinPix] = reverse (~pCursor->bits->source[nXPix] & mask); - else - pXor[nWinPix] = reverse (pCursor->bits->source[nXPix] & mask); - } - } - - /* prepare the pointers */ - hCursor = NULL; - lpBits = NULL; - - /* We have a truecolor alpha-blended cursor and can use it! */ - if (pCursor->bits->argb) - { - winDebug("winLoadCursor: Trying truecolor alphablended cursor\n"); - memset (&bi, 0, sizeof (BITMAPV4HEADER)); - bi.bV4Size = sizeof(BITMAPV4HEADER); - bi.bV4Width = pScreenPriv->cursor.sm_cx; - bi.bV4Height = -(pScreenPriv->cursor.sm_cy); /* right-side up */ - bi.bV4Planes = 1; - bi.bV4BitCount = 32; - bi.bV4V4Compression = BI_BITFIELDS; - bi.bV4RedMask = 0x00FF0000; - bi.bV4GreenMask = 0x0000FF00; - bi.bV4BlueMask = 0x000000FF; - bi.bV4AlphaMask = 0xFF000000; - - lpBits = (unsigned long *) calloc (pScreenPriv->cursor.sm_cx*pScreenPriv->cursor.sm_cy, - sizeof (unsigned long)); - - if (lpBits) - { - for (y=0; y<nCY; y++) - { - unsigned long *src, *dst; - src = &(pCursor->bits->argb[y * pCursor->bits->width]); - dst = &(lpBits[y * pScreenPriv->cursor.sm_cx]); - memcpy (dst, src, 4*nCX); - } - } - } /* End if-truecolor-icon */ - - if (!lpBits) - { - /* Bicolor, use a palettized DIB */ - winDebug("winLoadCursor: Trying two color cursor\n"); - pbmi = (BITMAPINFO*)&bi; - memset (pbmi, 0, sizeof (BITMAPINFOHEADER)); - pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - pbmi->bmiHeader.biWidth = pScreenPriv->cursor.sm_cx; - pbmi->bmiHeader.biHeight = -abs(pScreenPriv->cursor.sm_cy); /* right-side up */ - pbmi->bmiHeader.biPlanes = 1; - pbmi->bmiHeader.biBitCount = 8; - pbmi->bmiHeader.biCompression = BI_RGB; - pbmi->bmiHeader.biSizeImage = 0; - pbmi->bmiHeader.biClrUsed = 3; - pbmi->bmiHeader.biClrImportant = 3; - pbmi->bmiColors[0].rgbRed = 0; /* Empty */ - pbmi->bmiColors[0].rgbGreen = 0; - pbmi->bmiColors[0].rgbBlue = 0; - pbmi->bmiColors[0].rgbReserved = 0; - pbmi->bmiColors[1].rgbRed = pCursor->backRed>>8; /* Background */ - pbmi->bmiColors[1].rgbGreen = pCursor->backGreen>>8; - pbmi->bmiColors[1].rgbBlue = pCursor->backBlue>>8; - pbmi->bmiColors[1].rgbReserved = 0; - pbmi->bmiColors[2].rgbRed = pCursor->foreRed>>8; /* Foreground */ - pbmi->bmiColors[2].rgbGreen = pCursor->foreGreen>>8; - pbmi->bmiColors[2].rgbBlue = pCursor->foreBlue>>8; - pbmi->bmiColors[2].rgbReserved = 0; - - lpBits = (unsigned long *) calloc (pScreenPriv->cursor.sm_cx*pScreenPriv->cursor.sm_cy, - sizeof (char)); - - pCur = (unsigned char *)lpBits; - if (lpBits) - { - for (y=0; y<pScreenPriv->cursor.sm_cy; y++) - { - for (x=0; x<pScreenPriv->cursor.sm_cx; x++) - { - if (x>=nCX || y>=nCY) /* Outside of X11 icon bounds */ - (*pCur++) = 0; - else /* Within X11 icon bounds */ - { - int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + (x/8); - - bit = pAnd[nWinPix]; - bit = bit & (1<<(7-(x&7))); - if (!bit) /* Within the cursor mask? */ - { - int nXPix = BitmapBytePad(pCursor->bits->width) * y + (x/8); - bit = ~reverse(~pCursor->bits->source[nXPix] & pCursor->bits->mask[nXPix]); - bit = bit & (1<<(7-(x&7))); - if (bit) /* Draw foreground */ - (*pCur++) = 2; - else /* Draw background */ - (*pCur++) = 1; - } - else /* Outside the cursor mask */ - (*pCur++) = 0; - } - } /* end for (x) */ - } /* end for (y) */ - } /* end if (lpbits) */ - } - - /* If one of the previous two methods gave us the bitmap we need, make a cursor */ - if (lpBits) - { - winDebug("winLoadCursor: Creating bitmap cursor: hotspot %d,%d\n", - pCursor->bits->xhot, pCursor->bits->yhot); - - hAnd = NULL; - hXor = NULL; - - hAnd = CreateBitmap (pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy, 1, 1, pAnd); - - hDC = GetDC (NULL); - if (hDC) - { - hXor = CreateCompatibleBitmap (hDC, pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy); - SetDIBits (hDC, hXor, 0, pScreenPriv->cursor.sm_cy, lpBits, (BITMAPINFO*)&bi, DIB_RGB_COLORS); - ReleaseDC (NULL, hDC); - } - free (lpBits); - - - if (hAnd && hXor) - { - ii.fIcon = FALSE; - ii.xHotspot = pCursor->bits->xhot; - ii.yHotspot = pCursor->bits->yhot; - ii.hbmMask = hAnd; - ii.hbmColor = hXor; - hCursor = (HCURSOR) CreateIconIndirect( &ii ); - - if (hCursor == NULL) - winW32Error("winLoadCursor - CreateIconIndirect failed:"); - else - { - if (GetIconInfo(hCursor, &ii)) - { - if (ii.fIcon) - { - winDebug("winLoadCursor: CreateIconIndirect returned no cursor. Trying again.\n"); - - DestroyCursor(hCursor); - - ii.fIcon = FALSE; - ii.xHotspot = pCursor->bits->xhot; - ii.yHotspot = pCursor->bits->yhot; - hCursor = (HCURSOR) CreateIconIndirect( &ii ); - - if (hCursor == NULL) - winW32Error("winLoadCursor - CreateIconIndirect failed:"); - } - /* GetIconInfo creates new bitmaps. Destroy them again */ - if (ii.hbmMask) - DeleteObject(ii.hbmMask); - if (ii.hbmColor) - DeleteObject(ii.hbmColor); - } - } - } - - if (hAnd) - DeleteObject (hAnd); - if (hXor) - DeleteObject (hXor); - } - - if (!hCursor) - { - /* We couldn't make a color cursor for this screen, use - black and white instead */ - hCursor = CreateCursor (g_hInstance, - pCursor->bits->xhot, pCursor->bits->yhot, - pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy, - pAnd, pXor); - if (hCursor == NULL) - winW32Error("winLoadCursor - CreateCursor failed:"); - } - free (pAnd); - free (pXor); - - return hCursor; -} - -/* -=========================================================================== - - Pointer sprite functions - -=========================================================================== -*/ - -/* - * winRealizeCursor - * Convert the X cursor representation to native format if possible. - */ -static Bool -winRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - if(pCursor == NULL || pCursor->bits == NULL) - return FALSE; - - /* FIXME: cache ARGB8888 representation? */ - - return TRUE; -} - - -/* - * winUnrealizeCursor - * Free the storage space associated with a realized cursor. - */ -static Bool -winUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - return TRUE; -} - - -/* - * winSetCursor - * Set the cursor sprite and position. - */ -static void -winSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) -{ - POINT ptCurPos, ptTemp; - HWND hwnd; - RECT rcClient; - BOOL bInhibit; - winScreenPriv(pScreen); - winDebug("winSetCursor: cursor=%p\n", pCursor); - - /* Inhibit changing the cursor if the mouse is not in a client area */ - bInhibit = FALSE; - if (GetCursorPos (&ptCurPos)) - { - hwnd = WindowFromPoint (ptCurPos); - if (hwnd) - { - if (GetClientRect (hwnd, &rcClient)) - { - ptTemp.x = rcClient.left; - ptTemp.y = rcClient.top; - if (ClientToScreen (hwnd, &ptTemp)) - { - rcClient.left = ptTemp.x; - rcClient.top = ptTemp.y; - ptTemp.x = rcClient.right; - ptTemp.y = rcClient.bottom; - if (ClientToScreen (hwnd, &ptTemp)) - { - rcClient.right = ptTemp.x; - rcClient.bottom = ptTemp.y; - if (!PtInRect (&rcClient, ptCurPos)) - bInhibit = TRUE; - } - } - } - } - } - - if (pCursor == NULL) - { - if (pScreenPriv->cursor.visible) - { - if (!bInhibit && g_fSoftwareCursor) - ShowCursor (FALSE); - pScreenPriv->cursor.visible = FALSE; - } - } - else - { - if (pScreenPriv->cursor.handle) - { - if (!bInhibit) - SetCursor (NULL); - DestroyCursor (pScreenPriv->cursor.handle); - pScreenPriv->cursor.handle = NULL; - } - pScreenPriv->cursor.handle = - winLoadCursor (pScreen, pCursor, pScreen->myNum); - winDebug("winSetCursor: handle=%p\n", pScreenPriv->cursor.handle); - - if (!bInhibit) - SetCursor (pScreenPriv->cursor.handle); - - if (!pScreenPriv->cursor.visible) - { - if (!bInhibit && g_fSoftwareCursor) - ShowCursor (TRUE); - pScreenPriv->cursor.visible = TRUE; - } - } -} - - -/* - * winMoveCursor - * Move the cursor. This is a noop for us. - */ -static void -winMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ -} - -static Bool -winDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr) -{ - winScreenPriv(pScr); - return pScreenPriv->cursor.spriteFuncs->DeviceCursorInitialize(pDev, pScr); -} - -static void -winDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr) -{ - winScreenPriv(pScr); - pScreenPriv->cursor.spriteFuncs->DeviceCursorCleanup(pDev, pScr); -} - -static miPointerSpriteFuncRec winSpriteFuncsRec = { - winRealizeCursor, - winUnrealizeCursor, - winSetCursor, - winMoveCursor, - winDeviceCursorInitialize, - winDeviceCursorCleanup -}; - - -/* -=========================================================================== - - Other screen functions - -=========================================================================== -*/ - -/* - * winCursorQueryBestSize - * Handle queries for best cursor size - */ -static void -winCursorQueryBestSize (int class, unsigned short *width, - unsigned short *height, ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - - if (class == CursorShape) - { - *width = pScreenPriv->cursor.sm_cx; - *height = pScreenPriv->cursor.sm_cy; - } - else - { - if (pScreenPriv->cursor.QueryBestSize) - (*pScreenPriv->cursor.QueryBestSize)(class, width, height, pScreen); - } -} - -/* - * winInitCursor - * Initialize cursor support - */ -Bool -winInitCursor (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - miPointerScreenPtr pPointPriv; - /* override some screen procedures */ - pScreenPriv->cursor.QueryBestSize = pScreen->QueryBestSize; - pScreen->QueryBestSize = winCursorQueryBestSize; - - pPointPriv = (miPointerScreenPtr) - dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); - - if (pPointPriv) - { - pScreenPriv->cursor.spriteFuncs = pPointPriv->spriteFuncs; - pPointPriv->spriteFuncs = &winSpriteFuncsRec; - } - pScreenPriv->cursor.handle = NULL; - pScreenPriv->cursor.visible = FALSE; - - pScreenPriv->cursor.sm_cx = GetSystemMetrics (SM_CXCURSOR); - pScreenPriv->cursor.sm_cy = GetSystemMetrics (SM_CYCURSOR); - - return TRUE; -} +/*
+ *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
+ *
+ *Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ *"Software"), to deal in the Software without restriction, including
+ *without limitation the rights to use, copy, modify, merge, publish,
+ *distribute, sublicense, and/or sell copies of the Software, and to
+ *permit persons to whom the Software is furnished to do so, subject to
+ *the following conditions:
+ *
+ *The above copyright notice and this permission notice shall be
+ *included in all copies or substantial portions of the Software.
+ *
+ *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
+ *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *Except as contained in this notice, the name of the XFree86 Project
+ *shall not be used in advertising or otherwise to promote the sale, use
+ *or other dealings in this Software without prior written authorization
+ *from the XFree86 Project.
+ *
+ * Authors: Dakshinamurthy Karra
+ * Suhaib M Siddiqi
+ * Peter Busch
+ * Harold L Hunt II
+ */
+
+#ifdef HAVE_XWIN_CONFIG_H
+#include <xwin-config.h>
+#endif
+#include "win.h"
+#include "winmsg.h"
+#include <cursorstr.h>
+#include <mipointrst.h>
+#include <servermd.h>
+#include "misc.h"
+
+#define BRIGHTNESS(x) (x##Red * 0.299 + x##Green * 0.587 + x##Blue * 0.114)
+
+#ifdef _MSC_VER
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/*
+ * Local function prototypes
+ */
+
+static void
+winPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y);
+
+static Bool
+winCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y);
+
+static void
+winCrossScreen (ScreenPtr pScreen, Bool fEntering);
+
+miPointerScreenFuncRec g_winPointerCursorFuncs =
+{
+ winCursorOffScreen,
+ winCrossScreen,
+ winPointerWarpCursor
+};
+
+
+static void
+winPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
+{
+ winScreenPriv(pScreen);
+ RECT rcClient;
+ static Bool s_fInitialWarp = TRUE;
+
+ /* Discard first warp call */
+ if (s_fInitialWarp)
+ {
+ /* First warp moves mouse to center of window, just ignore it */
+
+ /* Don't ignore subsequent warps */
+ s_fInitialWarp = FALSE;
+
+ winDebug ("winPointerWarpCursor - Discarding first warp: %d %d\n",
+ x, y);
+
+ return;
+ }
+
+ /*
+ Only update the Windows cursor position if root window is active,
+ or we are in a rootless mode
+ */
+ if ((pScreenPriv->hwndScreen == GetForegroundWindow ())
+ || pScreenPriv->pScreenInfo->fRootless
+#ifdef XWIN_MULTIWINDOW
+ || pScreenPriv->pScreenInfo->fMultiWindow
+#endif
+ )
+ {
+ /* Get the client area coordinates */
+ GetClientRect (pScreenPriv->hwndScreen, &rcClient);
+
+ /* Translate the client area coords to screen coords */
+ MapWindowPoints (pScreenPriv->hwndScreen,
+ HWND_DESKTOP,
+ (LPPOINT)&rcClient,
+ 2);
+
+ /*
+ * Update the Windows cursor position so that we don't
+ * immediately warp back to the current position.
+ */
+ SetCursorPos (rcClient.left + x, rcClient.top + y);
+ }
+
+ /* Call the mi warp procedure to do the actual warping in X. */
+ miPointerWarpCursor (pDev, pScreen, x, y);
+}
+
+static Bool
+winCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y)
+{
+ return FALSE;
+}
+
+static void
+winCrossScreen (ScreenPtr pScreen, Bool fEntering)
+{
+}
+
+static unsigned char
+reverse(unsigned char c)
+{
+ int i;
+ unsigned char ret = 0;
+ for (i = 0; i < 8; ++i)
+ {
+ ret |= ((c >> i)&1) << (7 - i);
+ }
+ return ret;
+}
+
+/*
+ * Convert X cursor to Windows cursor
+ * FIXME: Perhaps there are more smart code
+ */
+static HCURSOR
+winLoadCursor (ScreenPtr pScreen, CursorPtr pCursor, int screen)
+{
+ winScreenPriv(pScreen);
+ HCURSOR hCursor = NULL;
+ unsigned char *pAnd;
+ unsigned char *pXor;
+ int nCX, nCY;
+ int nBytes;
+ double dForeY, dBackY;
+ BOOL fReverse;
+ HBITMAP hAnd, hXor;
+ ICONINFO ii;
+ unsigned char *pCur;
+ int x, y;
+ unsigned char bit;
+ HDC hDC;
+ BITMAPV4HEADER bi;
+ BITMAPINFO *pbmi;
+ unsigned long *lpBits;
+
+ winDebug("winLoadCursor: Win32: %dx%d X11: %dx%d hotspot: %d,%d\n",
+ pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy,
+ pCursor->bits->width, pCursor->bits->height,
+ pCursor->bits->xhot, pCursor->bits->yhot
+ );
+
+ /* We can use only White and Black, so calc brightness of color
+ * Also check if the cursor is inverted */
+ dForeY = BRIGHTNESS(pCursor->fore);
+ dBackY = BRIGHTNESS(pCursor->back);
+ fReverse = dForeY < dBackY;
+
+ /* Check wether the X11 cursor is bigger than the win32 cursor */
+ if (pScreenPriv->cursor.sm_cx < pCursor->bits->width ||
+ pScreenPriv->cursor.sm_cy < pCursor->bits->height)
+ {
+ ErrorF ("winLoadCursor - Windows requires %dx%d cursor but X requires %dx%d\n",
+ pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy,
+ pCursor->bits->width, pCursor->bits->height);
+ }
+
+ /* Get the number of bytes required to store the whole cursor image
+ * This is roughly (sm_cx * sm_cy) / 8
+ * round up to 8 pixel boundary so we can convert whole bytes */
+ nBytes = bits_to_bytes(pScreenPriv->cursor.sm_cx) * pScreenPriv->cursor.sm_cy;
+
+ /* Get the effective width and height */
+ nCX = min(pScreenPriv->cursor.sm_cx, pCursor->bits->width);
+ nCY = min(pScreenPriv->cursor.sm_cy, pCursor->bits->height);
+
+ /* Allocate memory for the bitmaps */
+ pAnd = malloc (nBytes);
+ memset (pAnd, 0xFF, nBytes);
+ pXor = calloc (1, nBytes);
+
+ /* Convert the X11 bitmap to a win32 bitmap
+ * The first is for an empty mask */
+ if (pCursor->bits->emptyMask)
+ {
+ int x, y, xmax = bits_to_bytes(nCX);
+ for (y = 0; y < nCY; ++y)
+ for (x = 0; x < xmax; ++x)
+ {
+ int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x;
+ int nXPix = BitmapBytePad(pCursor->bits->width) * y + x;
+
+ pAnd[nWinPix] = 0;
+ if (fReverse)
+ pXor[nWinPix] = reverse (~pCursor->bits->source[nXPix]);
+ else
+ pXor[nWinPix] = reverse (pCursor->bits->source[nXPix]);
+ }
+ }
+ else
+ {
+ int x, y, xmax = bits_to_bytes(nCX);
+ for (y = 0; y < nCY; ++y)
+ for (x = 0; x < xmax; ++x)
+ {
+ int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x;
+ int nXPix = BitmapBytePad(pCursor->bits->width) * y + x;
+
+ unsigned char mask = pCursor->bits->mask[nXPix];
+ pAnd[nWinPix] = reverse (~mask);
+ if (fReverse)
+ pXor[nWinPix] = reverse (~pCursor->bits->source[nXPix] & mask);
+ else
+ pXor[nWinPix] = reverse (pCursor->bits->source[nXPix] & mask);
+ }
+ }
+
+ /* prepare the pointers */
+ hCursor = NULL;
+ lpBits = NULL;
+
+ /* We have a truecolor alpha-blended cursor and can use it! */
+ if (pCursor->bits->argb)
+ {
+ winDebug("winLoadCursor: Trying truecolor alphablended cursor\n");
+ memset (&bi, 0, sizeof (BITMAPV4HEADER));
+ bi.bV4Size = sizeof(BITMAPV4HEADER);
+ bi.bV4Width = pScreenPriv->cursor.sm_cx;
+ bi.bV4Height = -(pScreenPriv->cursor.sm_cy); /* right-side up */
+ bi.bV4Planes = 1;
+ bi.bV4BitCount = 32;
+ bi.bV4V4Compression = BI_BITFIELDS;
+ bi.bV4RedMask = 0x00FF0000;
+ bi.bV4GreenMask = 0x0000FF00;
+ bi.bV4BlueMask = 0x000000FF;
+ bi.bV4AlphaMask = 0xFF000000;
+
+ lpBits = (unsigned long *) calloc (pScreenPriv->cursor.sm_cx*pScreenPriv->cursor.sm_cy,
+ sizeof (unsigned long));
+
+ if (lpBits)
+ {
+ for (y=0; y<nCY; y++)
+ {
+ unsigned long *src, *dst;
+ src = &(pCursor->bits->argb[y * pCursor->bits->width]);
+ dst = &(lpBits[y * pScreenPriv->cursor.sm_cx]);
+ memcpy (dst, src, 4*nCX);
+ }
+ }
+ } /* End if-truecolor-icon */
+
+ if (!lpBits)
+ {
+ /* Bicolor, use a palettized DIB */
+ winDebug("winLoadCursor: Trying two color cursor\n");
+ pbmi = (BITMAPINFO*)&bi;
+ memset (pbmi, 0, sizeof (BITMAPINFOHEADER));
+ pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pbmi->bmiHeader.biWidth = pScreenPriv->cursor.sm_cx;
+ pbmi->bmiHeader.biHeight = -abs(pScreenPriv->cursor.sm_cy); /* right-side up */
+ pbmi->bmiHeader.biPlanes = 1;
+ pbmi->bmiHeader.biBitCount = 8;
+ pbmi->bmiHeader.biCompression = BI_RGB;
+ pbmi->bmiHeader.biSizeImage = 0;
+ pbmi->bmiHeader.biClrUsed = 3;
+ pbmi->bmiHeader.biClrImportant = 3;
+ pbmi->bmiColors[0].rgbRed = 0; /* Empty */
+ pbmi->bmiColors[0].rgbGreen = 0;
+ pbmi->bmiColors[0].rgbBlue = 0;
+ pbmi->bmiColors[0].rgbReserved = 0;
+ pbmi->bmiColors[1].rgbRed = pCursor->backRed>>8; /* Background */
+ pbmi->bmiColors[1].rgbGreen = pCursor->backGreen>>8;
+ pbmi->bmiColors[1].rgbBlue = pCursor->backBlue>>8;
+ pbmi->bmiColors[1].rgbReserved = 0;
+ pbmi->bmiColors[2].rgbRed = pCursor->foreRed>>8; /* Foreground */
+ pbmi->bmiColors[2].rgbGreen = pCursor->foreGreen>>8;
+ pbmi->bmiColors[2].rgbBlue = pCursor->foreBlue>>8;
+ pbmi->bmiColors[2].rgbReserved = 0;
+
+ lpBits = (unsigned long *) calloc (pScreenPriv->cursor.sm_cx*pScreenPriv->cursor.sm_cy,
+ sizeof (char));
+
+ pCur = (unsigned char *)lpBits;
+ if (lpBits)
+ {
+ for (y=0; y<pScreenPriv->cursor.sm_cy; y++)
+ {
+ for (x=0; x<pScreenPriv->cursor.sm_cx; x++)
+ {
+ if (x>=nCX || y>=nCY) /* Outside of X11 icon bounds */
+ (*pCur++) = 0;
+ else /* Within X11 icon bounds */
+ {
+ int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + (x/8);
+
+ bit = pAnd[nWinPix];
+ bit = bit & (1<<(7-(x&7)));
+ if (!bit) /* Within the cursor mask? */
+ {
+ int nXPix = BitmapBytePad(pCursor->bits->width) * y + (x/8);
+ bit = ~reverse(~pCursor->bits->source[nXPix] & pCursor->bits->mask[nXPix]);
+ bit = bit & (1<<(7-(x&7)));
+ if (bit) /* Draw foreground */
+ (*pCur++) = 2;
+ else /* Draw background */
+ (*pCur++) = 1;
+ }
+ else /* Outside the cursor mask */
+ (*pCur++) = 0;
+ }
+ } /* end for (x) */
+ } /* end for (y) */
+ } /* end if (lpbits) */
+ }
+
+ /* If one of the previous two methods gave us the bitmap we need, make a cursor */
+ if (lpBits)
+ {
+ winDebug("winLoadCursor: Creating bitmap cursor: hotspot %d,%d\n",
+ pCursor->bits->xhot, pCursor->bits->yhot);
+
+ hAnd = NULL;
+ hXor = NULL;
+
+ hAnd = CreateBitmap (pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy, 1, 1, pAnd);
+
+ hDC = GetDC (NULL);
+ if (hDC)
+ {
+ hXor = CreateCompatibleBitmap (hDC, pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy);
+ SetDIBits (hDC, hXor, 0, pScreenPriv->cursor.sm_cy, lpBits, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
+ ReleaseDC (NULL, hDC);
+ }
+ free (lpBits);
+
+
+ if (hAnd && hXor)
+ {
+ ii.fIcon = FALSE;
+ ii.xHotspot = pCursor->bits->xhot;
+ ii.yHotspot = pCursor->bits->yhot;
+ ii.hbmMask = hAnd;
+ ii.hbmColor = hXor;
+ hCursor = (HCURSOR) CreateIconIndirect( &ii );
+
+ if (hCursor == NULL)
+ winW32Error("winLoadCursor - CreateIconIndirect failed:");
+ else
+ {
+ if (GetIconInfo(hCursor, &ii))
+ {
+ if (ii.fIcon)
+ {
+ winDebug("winLoadCursor: CreateIconIndirect returned no cursor. Trying again.\n");
+
+ DestroyCursor(hCursor);
+
+ ii.fIcon = FALSE;
+ ii.xHotspot = pCursor->bits->xhot;
+ ii.yHotspot = pCursor->bits->yhot;
+ hCursor = (HCURSOR) CreateIconIndirect( &ii );
+
+ if (hCursor == NULL)
+ winW32Error("winLoadCursor - CreateIconIndirect failed:");
+ }
+ /* GetIconInfo creates new bitmaps. Destroy them again */
+ if (ii.hbmMask)
+ DeleteObject(ii.hbmMask);
+ if (ii.hbmColor)
+ DeleteObject(ii.hbmColor);
+ }
+ }
+ }
+
+ if (hAnd)
+ DeleteObject (hAnd);
+ if (hXor)
+ DeleteObject (hXor);
+ }
+
+ if (!hCursor)
+ {
+ /* We couldn't make a color cursor for this screen, use
+ black and white instead */
+ hCursor = CreateCursor (g_hInstance,
+ pCursor->bits->xhot, pCursor->bits->yhot,
+ pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy,
+ pAnd, pXor);
+ if (hCursor == NULL)
+ winW32Error("winLoadCursor - CreateCursor failed:");
+ }
+ free (pAnd);
+ free (pXor);
+
+ return hCursor;
+}
+
+/*
+===========================================================================
+
+ Pointer sprite functions
+
+===========================================================================
+*/
+
+/*
+ * winRealizeCursor
+ * Convert the X cursor representation to native format if possible.
+ */
+static Bool
+winRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
+{
+ if(pCursor == NULL || pCursor->bits == NULL)
+ return FALSE;
+
+ /* FIXME: cache ARGB8888 representation? */
+
+ return TRUE;
+}
+
+
+/*
+ * winUnrealizeCursor
+ * Free the storage space associated with a realized cursor.
+ */
+static Bool
+winUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
+{
+ return TRUE;
+}
+
+
+/*
+ * winSetCursor
+ * Set the cursor sprite and position.
+ */
+static void
+winSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
+{
+ POINT ptCurPos, ptTemp;
+ HWND hwnd;
+ RECT rcClient;
+ BOOL bInhibit;
+ winScreenPriv(pScreen);
+ winDebug("winSetCursor: cursor=%p\n", pCursor);
+
+ /* Inhibit changing the cursor if the mouse is not in a client area */
+ bInhibit = FALSE;
+ if (GetCursorPos (&ptCurPos))
+ {
+ hwnd = WindowFromPoint (ptCurPos);
+ if (hwnd)
+ {
+ if (GetClientRect (hwnd, &rcClient))
+ {
+ ptTemp.x = rcClient.left;
+ ptTemp.y = rcClient.top;
+ if (ClientToScreen (hwnd, &ptTemp))
+ {
+ rcClient.left = ptTemp.x;
+ rcClient.top = ptTemp.y;
+ ptTemp.x = rcClient.right;
+ ptTemp.y = rcClient.bottom;
+ if (ClientToScreen (hwnd, &ptTemp))
+ {
+ rcClient.right = ptTemp.x;
+ rcClient.bottom = ptTemp.y;
+ if (!PtInRect (&rcClient, ptCurPos))
+ bInhibit = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ if (pCursor == NULL)
+ {
+ if (pScreenPriv->cursor.visible)
+ {
+ if (!bInhibit && g_fSoftwareCursor)
+ ShowCursor (FALSE);
+ pScreenPriv->cursor.visible = FALSE;
+ }
+ }
+ else
+ {
+ if (pScreenPriv->cursor.handle)
+ {
+ if (!bInhibit)
+ SetCursor (NULL);
+ DestroyCursor (pScreenPriv->cursor.handle);
+ pScreenPriv->cursor.handle = NULL;
+ }
+ pScreenPriv->cursor.handle =
+ winLoadCursor (pScreen, pCursor, pScreen->myNum);
+ winDebug("winSetCursor: handle=%p\n", pScreenPriv->cursor.handle);
+
+ if (!bInhibit)
+ SetCursor (pScreenPriv->cursor.handle);
+
+ if (!pScreenPriv->cursor.visible)
+ {
+ if (!bInhibit && g_fSoftwareCursor)
+ ShowCursor (TRUE);
+ pScreenPriv->cursor.visible = TRUE;
+ }
+ }
+}
+
+
+/*
+ * winMoveCursor
+ * Move the cursor. This is a noop for us.
+ */
+static void
+winMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
+{
+}
+
+static Bool
+winDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr)
+{
+ winScreenPriv(pScr);
+ return pScreenPriv->cursor.spriteFuncs->DeviceCursorInitialize(pDev, pScr);
+}
+
+static void
+winDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr)
+{
+ winScreenPriv(pScr);
+ pScreenPriv->cursor.spriteFuncs->DeviceCursorCleanup(pDev, pScr);
+}
+
+static miPointerSpriteFuncRec winSpriteFuncsRec = {
+ winRealizeCursor,
+ winUnrealizeCursor,
+ winSetCursor,
+ winMoveCursor,
+ winDeviceCursorInitialize,
+ winDeviceCursorCleanup
+};
+
+
+/*
+===========================================================================
+
+ Other screen functions
+
+===========================================================================
+*/
+
+/*
+ * winCursorQueryBestSize
+ * Handle queries for best cursor size
+ */
+static void
+winCursorQueryBestSize (int class, unsigned short *width,
+ unsigned short *height, ScreenPtr pScreen)
+{
+ winScreenPriv(pScreen);
+
+ if (class == CursorShape)
+ {
+ *width = pScreenPriv->cursor.sm_cx;
+ *height = pScreenPriv->cursor.sm_cy;
+ }
+ else
+ {
+ if (pScreenPriv->cursor.QueryBestSize)
+ (*pScreenPriv->cursor.QueryBestSize)(class, width, height, pScreen);
+ }
+}
+
+/*
+ * winInitCursor
+ * Initialize cursor support
+ */
+Bool
+winInitCursor (ScreenPtr pScreen)
+{
+ winScreenPriv(pScreen);
+ miPointerScreenPtr pPointPriv;
+ /* override some screen procedures */
+ pScreenPriv->cursor.QueryBestSize = pScreen->QueryBestSize;
+ pScreen->QueryBestSize = winCursorQueryBestSize;
+
+ pPointPriv = (miPointerScreenPtr)
+ dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
+
+ if (pPointPriv)
+ {
+ pScreenPriv->cursor.spriteFuncs = pPointPriv->spriteFuncs;
+ pPointPriv->spriteFuncs = &winSpriteFuncsRec;
+ }
+ pScreenPriv->cursor.handle = NULL;
+ pScreenPriv->cursor.visible = FALSE;
+
+ pScreenPriv->cursor.sm_cx = GetSystemMetrics (SM_CXCURSOR);
+ pScreenPriv->cursor.sm_cy = GetSystemMetrics (SM_CYCURSOR);
+
+ return TRUE;
+}
|