xref: /OK3568_Linux_fs/external/xserver/hw/xwin/wincursor.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *Permission is hereby granted, free of charge, to any person obtaining
5*4882a593Smuzhiyun  * a copy of this software and associated documentation files (the
6*4882a593Smuzhiyun  *"Software"), to deal in the Software without restriction, including
7*4882a593Smuzhiyun  *without limitation the rights to use, copy, modify, merge, publish,
8*4882a593Smuzhiyun  *distribute, sublicense, and/or sell copies of the Software, and to
9*4882a593Smuzhiyun  *permit persons to whom the Software is furnished to do so, subject to
10*4882a593Smuzhiyun  *the following conditions:
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  *The above copyright notice and this permission notice shall be
13*4882a593Smuzhiyun  *included in all copies or substantial portions of the Software.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*4882a593Smuzhiyun  *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*4882a593Smuzhiyun  *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18*4882a593Smuzhiyun  *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
19*4882a593Smuzhiyun  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20*4882a593Smuzhiyun  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21*4882a593Smuzhiyun  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  *Except as contained in this notice, the name of the XFree86 Project
24*4882a593Smuzhiyun  *shall not be used in advertising or otherwise to promote the sale, use
25*4882a593Smuzhiyun  *or other dealings in this Software without prior written authorization
26*4882a593Smuzhiyun  *from the XFree86 Project.
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  * Authors:	Dakshinamurthy Karra
29*4882a593Smuzhiyun  *		Suhaib M Siddiqi
30*4882a593Smuzhiyun  *		Peter Busch
31*4882a593Smuzhiyun  *		Harold L Hunt II
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #ifdef HAVE_XWIN_CONFIG_H
35*4882a593Smuzhiyun #include <xwin-config.h>
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun #include "win.h"
38*4882a593Smuzhiyun #include "winmsg.h"
39*4882a593Smuzhiyun #include <cursorstr.h>
40*4882a593Smuzhiyun #include <mipointrst.h>
41*4882a593Smuzhiyun #include <servermd.h>
42*4882a593Smuzhiyun #include "misc.h"
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define BRIGHTNESS(x) (x##Red * 0.299 + x##Green * 0.587 + x##Blue * 0.114)
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #if 0
47*4882a593Smuzhiyun #define WIN_DEBUG_MSG winDebug
48*4882a593Smuzhiyun #else
49*4882a593Smuzhiyun #define WIN_DEBUG_MSG(...)
50*4882a593Smuzhiyun #endif
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun  * Local function prototypes
54*4882a593Smuzhiyun  */
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun static void
57*4882a593Smuzhiyun  winPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun static Bool
60*4882a593Smuzhiyun  winCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun static void
63*4882a593Smuzhiyun  winCrossScreen(ScreenPtr pScreen, Bool fEntering);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun miPointerScreenFuncRec g_winPointerCursorFuncs = {
66*4882a593Smuzhiyun     winCursorOffScreen,
67*4882a593Smuzhiyun     winCrossScreen,
68*4882a593Smuzhiyun     winPointerWarpCursor
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun static void
winPointerWarpCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)72*4882a593Smuzhiyun winPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun     winScreenPriv(pScreen);
75*4882a593Smuzhiyun     RECT rcClient;
76*4882a593Smuzhiyun     static Bool s_fInitialWarp = TRUE;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun     /* Discard first warp call */
79*4882a593Smuzhiyun     if (s_fInitialWarp) {
80*4882a593Smuzhiyun         /* First warp moves mouse to center of window, just ignore it */
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun         /* Don't ignore subsequent warps */
83*4882a593Smuzhiyun         s_fInitialWarp = FALSE;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun         winErrorFVerb(2,
86*4882a593Smuzhiyun                       "winPointerWarpCursor - Discarding first warp: %d %d\n",
87*4882a593Smuzhiyun                       x, y);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun         return;
90*4882a593Smuzhiyun     }
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun     /*
93*4882a593Smuzhiyun        Only update the Windows cursor position if root window is active,
94*4882a593Smuzhiyun        or we are in a rootless mode
95*4882a593Smuzhiyun      */
96*4882a593Smuzhiyun     if ((pScreenPriv->hwndScreen == GetForegroundWindow())
97*4882a593Smuzhiyun         || pScreenPriv->pScreenInfo->fRootless
98*4882a593Smuzhiyun         || pScreenPriv->pScreenInfo->fMultiWindow
99*4882a593Smuzhiyun         ) {
100*4882a593Smuzhiyun         /* Get the client area coordinates */
101*4882a593Smuzhiyun         GetClientRect(pScreenPriv->hwndScreen, &rcClient);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun         /* Translate the client area coords to screen coords */
104*4882a593Smuzhiyun         MapWindowPoints(pScreenPriv->hwndScreen,
105*4882a593Smuzhiyun                         HWND_DESKTOP, (LPPOINT) &rcClient, 2);
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun         /*
108*4882a593Smuzhiyun          * Update the Windows cursor position so that we don't
109*4882a593Smuzhiyun          * immediately warp back to the current position.
110*4882a593Smuzhiyun          */
111*4882a593Smuzhiyun         SetCursorPos(rcClient.left + x, rcClient.top + y);
112*4882a593Smuzhiyun     }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun     /* Call the mi warp procedure to do the actual warping in X. */
115*4882a593Smuzhiyun     miPointerWarpCursor(pDev, pScreen, x, y);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun static Bool
winCursorOffScreen(ScreenPtr * ppScreen,int * x,int * y)119*4882a593Smuzhiyun winCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun     return FALSE;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun static void
winCrossScreen(ScreenPtr pScreen,Bool fEntering)125*4882a593Smuzhiyun winCrossScreen(ScreenPtr pScreen, Bool fEntering)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun static unsigned char
reverse(unsigned char c)130*4882a593Smuzhiyun reverse(unsigned char c)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun     int i;
133*4882a593Smuzhiyun     unsigned char ret = 0;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun     for (i = 0; i < 8; ++i) {
136*4882a593Smuzhiyun         ret |= ((c >> i) & 1) << (7 - i);
137*4882a593Smuzhiyun     }
138*4882a593Smuzhiyun     return ret;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun /*
142*4882a593Smuzhiyun  * Convert X cursor to Windows cursor
143*4882a593Smuzhiyun  * FIXME: Perhaps there are more smart code
144*4882a593Smuzhiyun  */
145*4882a593Smuzhiyun static HCURSOR
winLoadCursor(ScreenPtr pScreen,CursorPtr pCursor,int screen)146*4882a593Smuzhiyun winLoadCursor(ScreenPtr pScreen, CursorPtr pCursor, int screen)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun     winScreenPriv(pScreen);
149*4882a593Smuzhiyun     HCURSOR hCursor = NULL;
150*4882a593Smuzhiyun     unsigned char *pAnd;
151*4882a593Smuzhiyun     unsigned char *pXor;
152*4882a593Smuzhiyun     int nCX, nCY;
153*4882a593Smuzhiyun     int nBytes;
154*4882a593Smuzhiyun     double dForeY, dBackY;
155*4882a593Smuzhiyun     BOOL fReverse;
156*4882a593Smuzhiyun     HBITMAP hAnd, hXor;
157*4882a593Smuzhiyun     ICONINFO ii;
158*4882a593Smuzhiyun     unsigned char *pCur;
159*4882a593Smuzhiyun     unsigned char bit;
160*4882a593Smuzhiyun     HDC hDC;
161*4882a593Smuzhiyun     BITMAPV4HEADER bi;
162*4882a593Smuzhiyun     BITMAPINFO *pbmi;
163*4882a593Smuzhiyun     uint32_t *lpBits;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun     WIN_DEBUG_MSG("winLoadCursor: Win32: %dx%d X11: %dx%d hotspot: %d,%d\n",
166*4882a593Smuzhiyun                   pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy,
167*4882a593Smuzhiyun                   pCursor->bits->width, pCursor->bits->height,
168*4882a593Smuzhiyun                   pCursor->bits->xhot, pCursor->bits->yhot);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun     /* We can use only White and Black, so calc brightness of color
171*4882a593Smuzhiyun      * Also check if the cursor is inverted */
172*4882a593Smuzhiyun     dForeY = BRIGHTNESS(pCursor->fore);
173*4882a593Smuzhiyun     dBackY = BRIGHTNESS(pCursor->back);
174*4882a593Smuzhiyun     fReverse = dForeY < dBackY;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun     /* Check wether the X11 cursor is bigger than the win32 cursor */
177*4882a593Smuzhiyun     if (pScreenPriv->cursor.sm_cx < pCursor->bits->width ||
178*4882a593Smuzhiyun         pScreenPriv->cursor.sm_cy < pCursor->bits->height) {
179*4882a593Smuzhiyun         winErrorFVerb(3,
180*4882a593Smuzhiyun                       "winLoadCursor - Windows requires %dx%d cursor but X requires %dx%d\n",
181*4882a593Smuzhiyun                       pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy,
182*4882a593Smuzhiyun                       pCursor->bits->width, pCursor->bits->height);
183*4882a593Smuzhiyun     }
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun     /* Get the number of bytes required to store the whole cursor image
186*4882a593Smuzhiyun      * This is roughly (sm_cx * sm_cy) / 8
187*4882a593Smuzhiyun      * round up to 8 pixel boundary so we can convert whole bytes */
188*4882a593Smuzhiyun     nBytes =
189*4882a593Smuzhiyun         bits_to_bytes(pScreenPriv->cursor.sm_cx) * pScreenPriv->cursor.sm_cy;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun     /* Get the effective width and height */
192*4882a593Smuzhiyun     nCX = min(pScreenPriv->cursor.sm_cx, pCursor->bits->width);
193*4882a593Smuzhiyun     nCY = min(pScreenPriv->cursor.sm_cy, pCursor->bits->height);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun     /* Allocate memory for the bitmaps */
196*4882a593Smuzhiyun     pAnd = malloc(nBytes);
197*4882a593Smuzhiyun     memset(pAnd, 0xFF, nBytes);
198*4882a593Smuzhiyun     pXor = calloc(1, nBytes);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun     /* Convert the X11 bitmap to a win32 bitmap
201*4882a593Smuzhiyun      * The first is for an empty mask */
202*4882a593Smuzhiyun     if (pCursor->bits->emptyMask) {
203*4882a593Smuzhiyun         int x, y, xmax = bits_to_bytes(nCX);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun         for (y = 0; y < nCY; ++y)
206*4882a593Smuzhiyun             for (x = 0; x < xmax; ++x) {
207*4882a593Smuzhiyun                 int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x;
208*4882a593Smuzhiyun                 int nXPix = BitmapBytePad(pCursor->bits->width) * y + x;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun                 pAnd[nWinPix] = 0;
211*4882a593Smuzhiyun                 if (fReverse)
212*4882a593Smuzhiyun                     pXor[nWinPix] = reverse(~pCursor->bits->source[nXPix]);
213*4882a593Smuzhiyun                 else
214*4882a593Smuzhiyun                     pXor[nWinPix] = reverse(pCursor->bits->source[nXPix]);
215*4882a593Smuzhiyun             }
216*4882a593Smuzhiyun     }
217*4882a593Smuzhiyun     else {
218*4882a593Smuzhiyun         int x, y, xmax = bits_to_bytes(nCX);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun         for (y = 0; y < nCY; ++y)
221*4882a593Smuzhiyun             for (x = 0; x < xmax; ++x) {
222*4882a593Smuzhiyun                 int nWinPix = bits_to_bytes(pScreenPriv->cursor.sm_cx) * y + x;
223*4882a593Smuzhiyun                 int nXPix = BitmapBytePad(pCursor->bits->width) * y + x;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun                 unsigned char mask = pCursor->bits->mask[nXPix];
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun                 pAnd[nWinPix] = reverse(~mask);
228*4882a593Smuzhiyun                 if (fReverse)
229*4882a593Smuzhiyun                     pXor[nWinPix] =
230*4882a593Smuzhiyun                         reverse(~pCursor->bits->source[nXPix] & mask);
231*4882a593Smuzhiyun                 else
232*4882a593Smuzhiyun                     pXor[nWinPix] =
233*4882a593Smuzhiyun                         reverse(pCursor->bits->source[nXPix] & mask);
234*4882a593Smuzhiyun             }
235*4882a593Smuzhiyun     }
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun     /* prepare the pointers */
238*4882a593Smuzhiyun     hCursor = NULL;
239*4882a593Smuzhiyun     lpBits = NULL;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun     /* We have a truecolor alpha-blended cursor and can use it! */
242*4882a593Smuzhiyun     if (pCursor->bits->argb) {
243*4882a593Smuzhiyun         WIN_DEBUG_MSG("winLoadCursor: Trying truecolor alphablended cursor\n");
244*4882a593Smuzhiyun         memset(&bi, 0, sizeof(BITMAPV4HEADER));
245*4882a593Smuzhiyun         bi.bV4Size = sizeof(BITMAPV4HEADER);
246*4882a593Smuzhiyun         bi.bV4Width = pScreenPriv->cursor.sm_cx;
247*4882a593Smuzhiyun         bi.bV4Height = -(pScreenPriv->cursor.sm_cy);    /* right-side up */
248*4882a593Smuzhiyun         bi.bV4Planes = 1;
249*4882a593Smuzhiyun         bi.bV4BitCount = 32;
250*4882a593Smuzhiyun         bi.bV4V4Compression = BI_BITFIELDS;
251*4882a593Smuzhiyun         bi.bV4RedMask = 0x00FF0000;
252*4882a593Smuzhiyun         bi.bV4GreenMask = 0x0000FF00;
253*4882a593Smuzhiyun         bi.bV4BlueMask = 0x000000FF;
254*4882a593Smuzhiyun         bi.bV4AlphaMask = 0xFF000000;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun         lpBits = calloc(pScreenPriv->cursor.sm_cx * pScreenPriv->cursor.sm_cy,
257*4882a593Smuzhiyun                         sizeof(uint32_t));
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun         if (lpBits) {
260*4882a593Smuzhiyun             int y;
261*4882a593Smuzhiyun             for (y = 0; y < nCY; y++) {
262*4882a593Smuzhiyun                 void *src, *dst;
263*4882a593Smuzhiyun                 src = &(pCursor->bits->argb[y * pCursor->bits->width]);
264*4882a593Smuzhiyun                 dst = &(lpBits[y * pScreenPriv->cursor.sm_cx]);
265*4882a593Smuzhiyun                 memcpy(dst, src, 4 * nCX);
266*4882a593Smuzhiyun             }
267*4882a593Smuzhiyun         }
268*4882a593Smuzhiyun     }                           /* End if-truecolor-icon */
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun     if (!lpBits) {
271*4882a593Smuzhiyun         RGBQUAD *pbmiColors;
272*4882a593Smuzhiyun         /* Bicolor, use a palettized DIB */
273*4882a593Smuzhiyun         WIN_DEBUG_MSG("winLoadCursor: Trying two color cursor\n");
274*4882a593Smuzhiyun         pbmi = (BITMAPINFO *) &bi;
275*4882a593Smuzhiyun         pbmiColors = &(pbmi->bmiColors[0]);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun         memset(pbmi, 0, sizeof(BITMAPINFOHEADER));
278*4882a593Smuzhiyun         pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
279*4882a593Smuzhiyun         pbmi->bmiHeader.biWidth = pScreenPriv->cursor.sm_cx;
280*4882a593Smuzhiyun         pbmi->bmiHeader.biHeight = -abs(pScreenPriv->cursor.sm_cy);     /* right-side up */
281*4882a593Smuzhiyun         pbmi->bmiHeader.biPlanes = 1;
282*4882a593Smuzhiyun         pbmi->bmiHeader.biBitCount = 8;
283*4882a593Smuzhiyun         pbmi->bmiHeader.biCompression = BI_RGB;
284*4882a593Smuzhiyun         pbmi->bmiHeader.biSizeImage = 0;
285*4882a593Smuzhiyun         pbmi->bmiHeader.biClrUsed = 3;
286*4882a593Smuzhiyun         pbmi->bmiHeader.biClrImportant = 3;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun         pbmiColors[0].rgbRed = 0;  /* Empty */
289*4882a593Smuzhiyun         pbmiColors[0].rgbGreen = 0;
290*4882a593Smuzhiyun         pbmiColors[0].rgbBlue = 0;
291*4882a593Smuzhiyun         pbmiColors[0].rgbReserved = 0;
292*4882a593Smuzhiyun         pbmiColors[1].rgbRed = pCursor->backRed >> 8;      /* Background */
293*4882a593Smuzhiyun         pbmiColors[1].rgbGreen = pCursor->backGreen >> 8;
294*4882a593Smuzhiyun         pbmiColors[1].rgbBlue = pCursor->backBlue >> 8;
295*4882a593Smuzhiyun         pbmiColors[1].rgbReserved = 0;
296*4882a593Smuzhiyun         pbmiColors[2].rgbRed = pCursor->foreRed >> 8;      /* Foreground */
297*4882a593Smuzhiyun         pbmiColors[2].rgbGreen = pCursor->foreGreen >> 8;
298*4882a593Smuzhiyun         pbmiColors[2].rgbBlue = pCursor->foreBlue >> 8;
299*4882a593Smuzhiyun         pbmiColors[2].rgbReserved = 0;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun         lpBits = calloc(pScreenPriv->cursor.sm_cx * pScreenPriv->cursor.sm_cy, 1);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun         pCur = (unsigned char *) lpBits;
304*4882a593Smuzhiyun         if (lpBits) {
305*4882a593Smuzhiyun 	    int x, y;
306*4882a593Smuzhiyun             for (y = 0; y < pScreenPriv->cursor.sm_cy; y++) {
307*4882a593Smuzhiyun                 for (x = 0; x < pScreenPriv->cursor.sm_cx; x++) {
308*4882a593Smuzhiyun                     if (x >= nCX || y >= nCY)   /* Outside of X11 icon bounds */
309*4882a593Smuzhiyun                         (*pCur++) = 0;
310*4882a593Smuzhiyun                     else {      /* Within X11 icon bounds */
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun                         int nWinPix =
313*4882a593Smuzhiyun                             bits_to_bytes(pScreenPriv->cursor.sm_cx) * y +
314*4882a593Smuzhiyun                             (x / 8);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun                         bit = pAnd[nWinPix];
317*4882a593Smuzhiyun                         bit = bit & (1 << (7 - (x & 7)));
318*4882a593Smuzhiyun                         if (!bit) {     /* Within the cursor mask? */
319*4882a593Smuzhiyun                             int nXPix =
320*4882a593Smuzhiyun                                 BitmapBytePad(pCursor->bits->width) * y +
321*4882a593Smuzhiyun                                 (x / 8);
322*4882a593Smuzhiyun                             bit =
323*4882a593Smuzhiyun                                 ~reverse(~pCursor->bits->
324*4882a593Smuzhiyun                                          source[nXPix] & pCursor->bits->
325*4882a593Smuzhiyun                                          mask[nXPix]);
326*4882a593Smuzhiyun                             bit = bit & (1 << (7 - (x & 7)));
327*4882a593Smuzhiyun                             if (bit)    /* Draw foreground */
328*4882a593Smuzhiyun                                 (*pCur++) = 2;
329*4882a593Smuzhiyun                             else        /* Draw background */
330*4882a593Smuzhiyun                                 (*pCur++) = 1;
331*4882a593Smuzhiyun                         }
332*4882a593Smuzhiyun                         else    /* Outside the cursor mask */
333*4882a593Smuzhiyun                             (*pCur++) = 0;
334*4882a593Smuzhiyun                     }
335*4882a593Smuzhiyun                 }               /* end for (x) */
336*4882a593Smuzhiyun             }                   /* end for (y) */
337*4882a593Smuzhiyun         }                       /* end if (lpbits) */
338*4882a593Smuzhiyun     }
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun     /* If one of the previous two methods gave us the bitmap we need, make a cursor */
341*4882a593Smuzhiyun     if (lpBits) {
342*4882a593Smuzhiyun         WIN_DEBUG_MSG("winLoadCursor: Creating bitmap cursor: hotspot %d,%d\n",
343*4882a593Smuzhiyun                       pCursor->bits->xhot, pCursor->bits->yhot);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun         hAnd = NULL;
346*4882a593Smuzhiyun         hXor = NULL;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun         hAnd =
349*4882a593Smuzhiyun             CreateBitmap(pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy,
350*4882a593Smuzhiyun                          1, 1, pAnd);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun         hDC = GetDC(NULL);
353*4882a593Smuzhiyun         if (hDC) {
354*4882a593Smuzhiyun             hXor =
355*4882a593Smuzhiyun                 CreateCompatibleBitmap(hDC, pScreenPriv->cursor.sm_cx,
356*4882a593Smuzhiyun                                        pScreenPriv->cursor.sm_cy);
357*4882a593Smuzhiyun             SetDIBits(hDC, hXor, 0, pScreenPriv->cursor.sm_cy, lpBits,
358*4882a593Smuzhiyun                       (BITMAPINFO *) &bi, DIB_RGB_COLORS);
359*4882a593Smuzhiyun             ReleaseDC(NULL, hDC);
360*4882a593Smuzhiyun         }
361*4882a593Smuzhiyun         free(lpBits);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun         if (hAnd && hXor) {
364*4882a593Smuzhiyun             ii.fIcon = FALSE;
365*4882a593Smuzhiyun             ii.xHotspot = pCursor->bits->xhot;
366*4882a593Smuzhiyun             ii.yHotspot = pCursor->bits->yhot;
367*4882a593Smuzhiyun             ii.hbmMask = hAnd;
368*4882a593Smuzhiyun             ii.hbmColor = hXor;
369*4882a593Smuzhiyun             hCursor = (HCURSOR) CreateIconIndirect(&ii);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun             if (hCursor == NULL)
372*4882a593Smuzhiyun                 winW32Error(2, "winLoadCursor - CreateIconIndirect failed:");
373*4882a593Smuzhiyun             else {
374*4882a593Smuzhiyun                 if (GetIconInfo(hCursor, &ii)) {
375*4882a593Smuzhiyun                     if (ii.fIcon) {
376*4882a593Smuzhiyun                         WIN_DEBUG_MSG
377*4882a593Smuzhiyun                             ("winLoadCursor: CreateIconIndirect returned  no cursor. Trying again.\n");
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun                         DestroyCursor(hCursor);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun                         ii.fIcon = FALSE;
382*4882a593Smuzhiyun                         ii.xHotspot = pCursor->bits->xhot;
383*4882a593Smuzhiyun                         ii.yHotspot = pCursor->bits->yhot;
384*4882a593Smuzhiyun                         hCursor = (HCURSOR) CreateIconIndirect(&ii);
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun                         if (hCursor == NULL)
387*4882a593Smuzhiyun                             winW32Error(2,
388*4882a593Smuzhiyun                                         "winLoadCursor - CreateIconIndirect failed:");
389*4882a593Smuzhiyun                     }
390*4882a593Smuzhiyun                     /* GetIconInfo creates new bitmaps. Destroy them again */
391*4882a593Smuzhiyun                     if (ii.hbmMask)
392*4882a593Smuzhiyun                         DeleteObject(ii.hbmMask);
393*4882a593Smuzhiyun                     if (ii.hbmColor)
394*4882a593Smuzhiyun                         DeleteObject(ii.hbmColor);
395*4882a593Smuzhiyun                 }
396*4882a593Smuzhiyun             }
397*4882a593Smuzhiyun         }
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun         if (hAnd)
400*4882a593Smuzhiyun             DeleteObject(hAnd);
401*4882a593Smuzhiyun         if (hXor)
402*4882a593Smuzhiyun             DeleteObject(hXor);
403*4882a593Smuzhiyun     }
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun     if (!hCursor) {
406*4882a593Smuzhiyun         /* We couldn't make a color cursor for this screen, use
407*4882a593Smuzhiyun            black and white instead */
408*4882a593Smuzhiyun         hCursor = CreateCursor(g_hInstance,
409*4882a593Smuzhiyun                                pCursor->bits->xhot, pCursor->bits->yhot,
410*4882a593Smuzhiyun                                pScreenPriv->cursor.sm_cx,
411*4882a593Smuzhiyun                                pScreenPriv->cursor.sm_cy, pAnd, pXor);
412*4882a593Smuzhiyun         if (hCursor == NULL)
413*4882a593Smuzhiyun             winW32Error(2, "winLoadCursor - CreateCursor failed:");
414*4882a593Smuzhiyun     }
415*4882a593Smuzhiyun     free(pAnd);
416*4882a593Smuzhiyun     free(pXor);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun     return hCursor;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun /*
422*4882a593Smuzhiyun ===========================================================================
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun  Pointer sprite functions
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun ===========================================================================
427*4882a593Smuzhiyun */
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun /*
430*4882a593Smuzhiyun  * winRealizeCursor
431*4882a593Smuzhiyun  *  Convert the X cursor representation to native format if possible.
432*4882a593Smuzhiyun  */
433*4882a593Smuzhiyun static Bool
winRealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)434*4882a593Smuzhiyun winRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun     if (pCursor == NULL || pCursor->bits == NULL)
437*4882a593Smuzhiyun         return FALSE;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun     /* FIXME: cache ARGB8888 representation? */
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun     return TRUE;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun /*
445*4882a593Smuzhiyun  * winUnrealizeCursor
446*4882a593Smuzhiyun  *  Free the storage space associated with a realized cursor.
447*4882a593Smuzhiyun  */
448*4882a593Smuzhiyun static Bool
winUnrealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)449*4882a593Smuzhiyun winUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun     return TRUE;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun /*
455*4882a593Smuzhiyun  * winSetCursor
456*4882a593Smuzhiyun  *  Set the cursor sprite and position.
457*4882a593Smuzhiyun  */
458*4882a593Smuzhiyun static void
winSetCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)459*4882a593Smuzhiyun winSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x,
460*4882a593Smuzhiyun              int y)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun     POINT ptCurPos, ptTemp;
463*4882a593Smuzhiyun     HWND hwnd;
464*4882a593Smuzhiyun     RECT rcClient;
465*4882a593Smuzhiyun     BOOL bInhibit;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun     winScreenPriv(pScreen);
468*4882a593Smuzhiyun     WIN_DEBUG_MSG("winSetCursor: cursor=%p\n", pCursor);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun     /* Inhibit changing the cursor if the mouse is not in a client area */
471*4882a593Smuzhiyun     bInhibit = FALSE;
472*4882a593Smuzhiyun     if (GetCursorPos(&ptCurPos)) {
473*4882a593Smuzhiyun         hwnd = WindowFromPoint(ptCurPos);
474*4882a593Smuzhiyun         if (hwnd) {
475*4882a593Smuzhiyun             if (GetClientRect(hwnd, &rcClient)) {
476*4882a593Smuzhiyun                 ptTemp.x = rcClient.left;
477*4882a593Smuzhiyun                 ptTemp.y = rcClient.top;
478*4882a593Smuzhiyun                 if (ClientToScreen(hwnd, &ptTemp)) {
479*4882a593Smuzhiyun                     rcClient.left = ptTemp.x;
480*4882a593Smuzhiyun                     rcClient.top = ptTemp.y;
481*4882a593Smuzhiyun                     ptTemp.x = rcClient.right;
482*4882a593Smuzhiyun                     ptTemp.y = rcClient.bottom;
483*4882a593Smuzhiyun                     if (ClientToScreen(hwnd, &ptTemp)) {
484*4882a593Smuzhiyun                         rcClient.right = ptTemp.x;
485*4882a593Smuzhiyun                         rcClient.bottom = ptTemp.y;
486*4882a593Smuzhiyun                         if (!PtInRect(&rcClient, ptCurPos))
487*4882a593Smuzhiyun                             bInhibit = TRUE;
488*4882a593Smuzhiyun                     }
489*4882a593Smuzhiyun                 }
490*4882a593Smuzhiyun             }
491*4882a593Smuzhiyun         }
492*4882a593Smuzhiyun     }
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun     if (pCursor == NULL) {
495*4882a593Smuzhiyun         if (pScreenPriv->cursor.visible) {
496*4882a593Smuzhiyun             if (!bInhibit && g_fSoftwareCursor)
497*4882a593Smuzhiyun                 ShowCursor(FALSE);
498*4882a593Smuzhiyun             pScreenPriv->cursor.visible = FALSE;
499*4882a593Smuzhiyun         }
500*4882a593Smuzhiyun     }
501*4882a593Smuzhiyun     else {
502*4882a593Smuzhiyun         if (pScreenPriv->cursor.handle) {
503*4882a593Smuzhiyun             if (!bInhibit)
504*4882a593Smuzhiyun                 SetCursor(NULL);
505*4882a593Smuzhiyun             DestroyCursor(pScreenPriv->cursor.handle);
506*4882a593Smuzhiyun             pScreenPriv->cursor.handle = NULL;
507*4882a593Smuzhiyun         }
508*4882a593Smuzhiyun         pScreenPriv->cursor.handle =
509*4882a593Smuzhiyun             winLoadCursor(pScreen, pCursor, pScreen->myNum);
510*4882a593Smuzhiyun         WIN_DEBUG_MSG("winSetCursor: handle=%p\n", pScreenPriv->cursor.handle);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun         if (!bInhibit)
513*4882a593Smuzhiyun             SetCursor(pScreenPriv->cursor.handle);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun         if (!pScreenPriv->cursor.visible) {
516*4882a593Smuzhiyun             if (!bInhibit && g_fSoftwareCursor)
517*4882a593Smuzhiyun                 ShowCursor(TRUE);
518*4882a593Smuzhiyun             pScreenPriv->cursor.visible = TRUE;
519*4882a593Smuzhiyun         }
520*4882a593Smuzhiyun     }
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun /*
524*4882a593Smuzhiyun  * winMoveCursor
525*4882a593Smuzhiyun  *  Move the cursor. This is a noop for us.
526*4882a593Smuzhiyun  */
527*4882a593Smuzhiyun static void
winMoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)528*4882a593Smuzhiyun winMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun static Bool
winDeviceCursorInitialize(DeviceIntPtr pDev,ScreenPtr pScr)533*4882a593Smuzhiyun winDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun     winScreenPriv(pScr);
536*4882a593Smuzhiyun     return pScreenPriv->cursor.spriteFuncs->DeviceCursorInitialize(pDev, pScr);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun static void
winDeviceCursorCleanup(DeviceIntPtr pDev,ScreenPtr pScr)540*4882a593Smuzhiyun winDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun     winScreenPriv(pScr);
543*4882a593Smuzhiyun     pScreenPriv->cursor.spriteFuncs->DeviceCursorCleanup(pDev, pScr);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun static miPointerSpriteFuncRec winSpriteFuncsRec = {
547*4882a593Smuzhiyun     winRealizeCursor,
548*4882a593Smuzhiyun     winUnrealizeCursor,
549*4882a593Smuzhiyun     winSetCursor,
550*4882a593Smuzhiyun     winMoveCursor,
551*4882a593Smuzhiyun     winDeviceCursorInitialize,
552*4882a593Smuzhiyun     winDeviceCursorCleanup
553*4882a593Smuzhiyun };
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun /*
556*4882a593Smuzhiyun ===========================================================================
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun  Other screen functions
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun ===========================================================================
561*4882a593Smuzhiyun */
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun /*
564*4882a593Smuzhiyun  * winCursorQueryBestSize
565*4882a593Smuzhiyun  *  Handle queries for best cursor size
566*4882a593Smuzhiyun  */
567*4882a593Smuzhiyun static void
winCursorQueryBestSize(int class,unsigned short * width,unsigned short * height,ScreenPtr pScreen)568*4882a593Smuzhiyun winCursorQueryBestSize(int class, unsigned short *width,
569*4882a593Smuzhiyun                        unsigned short *height, ScreenPtr pScreen)
570*4882a593Smuzhiyun {
571*4882a593Smuzhiyun     winScreenPriv(pScreen);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun     if (class == CursorShape) {
574*4882a593Smuzhiyun         *width = pScreenPriv->cursor.sm_cx;
575*4882a593Smuzhiyun         *height = pScreenPriv->cursor.sm_cy;
576*4882a593Smuzhiyun     }
577*4882a593Smuzhiyun     else {
578*4882a593Smuzhiyun         if (pScreenPriv->cursor.QueryBestSize)
579*4882a593Smuzhiyun             (*pScreenPriv->cursor.QueryBestSize) (class, width, height,
580*4882a593Smuzhiyun                                                   pScreen);
581*4882a593Smuzhiyun     }
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun /*
585*4882a593Smuzhiyun  * winInitCursor
586*4882a593Smuzhiyun  *  Initialize cursor support
587*4882a593Smuzhiyun  */
588*4882a593Smuzhiyun Bool
winInitCursor(ScreenPtr pScreen)589*4882a593Smuzhiyun winInitCursor(ScreenPtr pScreen)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun     winScreenPriv(pScreen);
592*4882a593Smuzhiyun     miPointerScreenPtr pPointPriv;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun     /* override some screen procedures */
595*4882a593Smuzhiyun     pScreenPriv->cursor.QueryBestSize = pScreen->QueryBestSize;
596*4882a593Smuzhiyun     pScreen->QueryBestSize = winCursorQueryBestSize;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun     pPointPriv = (miPointerScreenPtr)
599*4882a593Smuzhiyun         dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun     pScreenPriv->cursor.spriteFuncs = pPointPriv->spriteFuncs;
602*4882a593Smuzhiyun     pPointPriv->spriteFuncs = &winSpriteFuncsRec;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun     pScreenPriv->cursor.handle = NULL;
605*4882a593Smuzhiyun     pScreenPriv->cursor.visible = FALSE;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun     pScreenPriv->cursor.sm_cx = GetSystemMetrics(SM_CXCURSOR);
608*4882a593Smuzhiyun     pScreenPriv->cursor.sm_cy = GetSystemMetrics(SM_CYCURSOR);
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun     return TRUE;
611*4882a593Smuzhiyun }
612