aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xwin/wincursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xwin/wincursor.c')
-rw-r--r--xorg-server/hw/xwin/wincursor.c1241
1 files changed, 613 insertions, 628 deletions
diff --git a/xorg-server/hw/xwin/wincursor.c b/xorg-server/hw/xwin/wincursor.c
index 3cae2361b..8f4130207 100644
--- a/xorg-server/hw/xwin/wincursor.c
+++ b/xorg-server/hw/xwin/wincursor.c
@@ -1,628 +1,613 @@
-/*
- *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;
-}
+/*
+ *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;
+}