2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
4 *Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 *"Software"), to deal in the Software without restriction, including
7 *without limitation the rights to use, copy, modify, merge, publish,
8 *distribute, sublicense, and/or sell copies of the Software, and to
9 *permit persons to whom the Software is furnished to do so, subject to
10 *the following conditions:
12 *The above copyright notice and this permission notice shall be
13 *included in all copies or substantial portions of the Software.
15 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
19 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *Except as contained in this notice, the name of the XFree86 Project
24 *shall not be used in advertising or otherwise to promote the sale, use
25 *or other dealings in this Software without prior written authorization
26 *from the XFree86 Project.
28 * Authors: Dakshinamurthy Karra
34 #ifdef HAVE_XWIN_CONFIG_H
35 #include <xwin-config.h>
39 #include <cursorstr.h>
40 #include <mipointrst.h>
43 extern Bool g_fSoftwareCursor
;
47 #define MIN(x,y) ((x)<(y)?(x):(y))
50 #define BYTE_COUNT(x) (((x) + 7) / 8)
52 #define BRIGHTNESS(x) (x##Red * 0.299 + x##Green * 0.587 + x##Blue * 0.114)
55 # define WIN_DEBUG_MSG winDebug
57 # define WIN_DEBUG_MSG(...)
61 * Local function prototypes
65 winPointerWarpCursor (ScreenPtr pScreen
, int x
, int y
);
68 winCursorOffScreen (ScreenPtr
*ppScreen
, int *x
, int *y
);
71 winCrossScreen (ScreenPtr pScreen
, Bool fEntering
);
73 miPointerScreenFuncRec g_winPointerCursorFuncs
=
82 winPointerWarpCursor (ScreenPtr pScreen
, int x
, int y
)
84 winScreenPriv(pScreen
);
86 static Bool s_fInitialWarp
= TRUE
;
88 /* Discard first warp call */
91 /* First warp moves mouse to center of window, just ignore it */
93 /* Don't ignore subsequent warps */
94 s_fInitialWarp
= FALSE
;
96 winErrorFVerb (2, "winPointerWarpCursor - Discarding first warp: %d %d\n",
102 /* Only update the Windows cursor position if we are active */
103 if (pScreenPriv
->hwndScreen
== GetForegroundWindow ())
105 /* Get the client area coordinates */
106 GetClientRect (pScreenPriv
->hwndScreen
, &rcClient
);
108 /* Translate the client area coords to screen coords */
109 MapWindowPoints (pScreenPriv
->hwndScreen
,
115 * Update the Windows cursor position so that we don't
116 * immediately warp back to the current position.
118 SetCursorPos (rcClient
.left
+ x
, rcClient
.top
+ y
);
121 /* Call the mi warp procedure to do the actual warping in X. */
122 miPointerWarpCursor (pScreen
, x
, y
);
126 winCursorOffScreen (ScreenPtr
*ppScreen
, int *x
, int *y
)
132 winCrossScreen (ScreenPtr pScreen
, Bool fEntering
)
137 reverse(unsigned char c
)
140 unsigned char ret
= 0;
141 for (i
= 0; i
< 8; ++i
)
143 ret
|= ((c
>> i
)&1) << (7 - i
);
149 * Convert X cursor to Windows cursor
150 * FIXME: Perhaps there are more smart code
153 winLoadCursor (ScreenPtr pScreen
, CursorPtr pCursor
, int screen
)
155 winScreenPriv(pScreen
);
156 HCURSOR hCursor
= NULL
;
161 double dForeY
, dBackY
;
171 unsigned long *lpBits
;
173 WIN_DEBUG_MSG("winLoadCursor: Win32: %dx%d X11: %dx%d hotspot: %d,%d\n",
174 pScreenPriv
->cursor
.sm_cx
, pScreenPriv
->cursor
.sm_cy
,
175 pCursor
->bits
->width
, pCursor
->bits
->height
,
176 pCursor
->bits
->xhot
, pCursor
->bits
->yhot
179 /* We can use only White and Black, so calc brightness of color
180 * Also check if the cursor is inverted */
181 dForeY
= BRIGHTNESS(pCursor
->fore
);
182 dBackY
= BRIGHTNESS(pCursor
->back
);
183 fReverse
= dForeY
< dBackY
;
185 /* Check wether the X11 cursor is bigger than the win32 cursor */
186 if (pScreenPriv
->cursor
.sm_cx
< pCursor
->bits
->width
||
187 pScreenPriv
->cursor
.sm_cy
< pCursor
->bits
->height
)
189 winErrorFVerb (2, "winLoadCursor - Windows requires %dx%d cursor\n"
190 "\tbut X requires %dx%d\n",
191 pScreenPriv
->cursor
.sm_cx
, pScreenPriv
->cursor
.sm_cy
,
192 pCursor
->bits
->width
, pCursor
->bits
->height
);
195 /* Get the number of bytes required to store the whole cursor image
196 * This is roughly (sm_cx * sm_cy) / 8
197 * round up to 8 pixel boundary so we can convert whole bytes */
198 nBytes
= BYTE_COUNT(pScreenPriv
->cursor
.sm_cx
) * pScreenPriv
->cursor
.sm_cy
;
200 /* Get the effective width and height */
201 nCX
= MIN(pScreenPriv
->cursor
.sm_cx
, pCursor
->bits
->width
);
202 nCY
= MIN(pScreenPriv
->cursor
.sm_cy
, pCursor
->bits
->height
);
204 /* Allocate memory for the bitmaps */
205 pAnd
= malloc (nBytes
);
206 memset (pAnd
, 0xFF, nBytes
);
207 pXor
= malloc (nBytes
);
208 memset (pXor
, 0x00, nBytes
);
210 /* Convert the X11 bitmap to a win32 bitmap
211 * The first is for an empty mask */
212 if (pCursor
->bits
->emptyMask
)
214 int x
, y
, xmax
= BYTE_COUNT(nCX
);
215 for (y
= 0; y
< nCY
; ++y
)
216 for (x
= 0; x
< xmax
; ++x
)
218 int nWinPix
= BYTE_COUNT(pScreenPriv
->cursor
.sm_cx
) * y
+ x
;
219 int nXPix
= BitmapBytePad(pCursor
->bits
->width
) * y
+ x
;
223 pXor
[nWinPix
] = reverse (~pCursor
->bits
->source
[nXPix
]);
225 pXor
[nWinPix
] = reverse (pCursor
->bits
->source
[nXPix
]);
230 int x
, y
, xmax
= BYTE_COUNT(nCX
);
231 for (y
= 0; y
< nCY
; ++y
)
232 for (x
= 0; x
< xmax
; ++x
)
234 int nWinPix
= BYTE_COUNT(pScreenPriv
->cursor
.sm_cx
) * y
+ x
;
235 int nXPix
= BitmapBytePad(pCursor
->bits
->width
) * y
+ x
;
237 unsigned char mask
= pCursor
->bits
->mask
[nXPix
];
238 pAnd
[nWinPix
] = reverse (~mask
);
240 pXor
[nWinPix
] = reverse (~pCursor
->bits
->source
[nXPix
] & mask
);
242 pXor
[nWinPix
] = reverse (pCursor
->bits
->source
[nXPix
] & mask
);
246 /* prepare the pointers */
250 /* We have a truecolor alpha-blended cursor and can use it! */
251 if (pCursor
->bits
->argb
)
253 WIN_DEBUG_MSG("winLoadCursor: Trying truecolor alphablended cursor\n");
254 memset (&bi
, 0, sizeof (BITMAPV4HEADER
));
255 bi
.bV4Size
= sizeof(BITMAPV4HEADER
);
256 bi
.bV4Width
= pScreenPriv
->cursor
.sm_cx
;
257 bi
.bV4Height
= -(pScreenPriv
->cursor
.sm_cy
); /* right-side up */
260 bi
.bV4V4Compression
= BI_BITFIELDS
;
261 bi
.bV4RedMask
= 0x00FF0000;
262 bi
.bV4GreenMask
= 0x0000FF00;
263 bi
.bV4BlueMask
= 0x000000FF;
264 bi
.bV4AlphaMask
= 0xFF000000;
266 lpBits
= (unsigned long *) calloc (pScreenPriv
->cursor
.sm_cx
*pScreenPriv
->cursor
.sm_cy
,
267 sizeof (unsigned long));
271 for (y
=0; y
<nCY
; y
++)
273 unsigned long *src
, *dst
;
274 src
= &(pCursor
->bits
->argb
[y
* pCursor
->bits
->width
]);
275 dst
= &(lpBits
[y
* pScreenPriv
->cursor
.sm_cx
]);
276 memcpy (dst
, src
, 4*nCX
);
279 } /* End if-truecolor-icon */
283 /* Bicolor, use a palettized DIB */
284 WIN_DEBUG_MSG("winLoadCursor: Trying two color cursor\n");
285 pbmi
= (BITMAPINFO
*)&bi
;
286 memset (pbmi
, 0, sizeof (BITMAPINFOHEADER
));
287 pbmi
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
288 pbmi
->bmiHeader
.biWidth
= pScreenPriv
->cursor
.sm_cx
;
289 pbmi
->bmiHeader
.biHeight
= -abs(pScreenPriv
->cursor
.sm_cy
); /* right-side up */
290 pbmi
->bmiHeader
.biPlanes
= 1;
291 pbmi
->bmiHeader
.biBitCount
= 8;
292 pbmi
->bmiHeader
.biCompression
= BI_RGB
;
293 pbmi
->bmiHeader
.biSizeImage
= 0;
294 pbmi
->bmiHeader
.biClrUsed
= 3;
295 pbmi
->bmiHeader
.biClrImportant
= 3;
296 pbmi
->bmiColors
[0].rgbRed
= 0; /* Empty */
297 pbmi
->bmiColors
[0].rgbGreen
= 0;
298 pbmi
->bmiColors
[0].rgbBlue
= 0;
299 pbmi
->bmiColors
[0].rgbReserved
= 0;
300 pbmi
->bmiColors
[1].rgbRed
= pCursor
->backRed
>>8; /* Background */
301 pbmi
->bmiColors
[1].rgbGreen
= pCursor
->backGreen
>>8;
302 pbmi
->bmiColors
[1].rgbBlue
= pCursor
->backBlue
>>8;
303 pbmi
->bmiColors
[1].rgbReserved
= 0;
304 pbmi
->bmiColors
[2].rgbRed
= pCursor
->foreRed
>>8; /* Foreground */
305 pbmi
->bmiColors
[2].rgbGreen
= pCursor
->foreGreen
>>8;
306 pbmi
->bmiColors
[2].rgbBlue
= pCursor
->foreBlue
>>8;
307 pbmi
->bmiColors
[2].rgbReserved
= 0;
309 lpBits
= (unsigned long *) calloc (pScreenPriv
->cursor
.sm_cx
*pScreenPriv
->cursor
.sm_cy
,
312 pCur
= (unsigned char *)lpBits
;
315 for (y
=0; y
<pScreenPriv
->cursor
.sm_cy
; y
++)
317 for (x
=0; x
<pScreenPriv
->cursor
.sm_cx
; x
++)
319 if (x
>=nCX
|| y
>=nCY
) /* Outside of X11 icon bounds */
321 else /* Within X11 icon bounds */
323 int nWinPix
= BYTE_COUNT(pScreenPriv
->cursor
.sm_cx
) * y
+ (x
/8);
326 bit
= bit
& (1<<(7-(x
&7)));
327 if (!bit
) /* Within the cursor mask? */
329 int nXPix
= BitmapBytePad(pCursor
->bits
->width
) * y
+ (x
/8);
330 bit
= ~reverse(~pCursor
->bits
->source
[nXPix
] & pCursor
->bits
->mask
[nXPix
]);
331 bit
= bit
& (1<<(7-(x
&7)));
332 if (bit
) /* Draw foreground */
334 else /* Draw background */
337 else /* Outside the cursor mask */
342 } /* end if (lpbits) */
345 /* If one of the previous two methods gave us the bitmap we need, make a cursor */
348 WIN_DEBUG_MSG("winLoadCursor: Creating bitmap cursor: hotspot %d,%d\n",
349 pCursor
->bits
->xhot
, pCursor
->bits
->yhot
);
354 hAnd
= CreateBitmap (pScreenPriv
->cursor
.sm_cx
, pScreenPriv
->cursor
.sm_cy
, 1, 1, pAnd
);
359 hXor
= CreateCompatibleBitmap (hDC
, pScreenPriv
->cursor
.sm_cx
, pScreenPriv
->cursor
.sm_cy
);
360 SetDIBits (hDC
, hXor
, 0, pScreenPriv
->cursor
.sm_cy
, lpBits
, (BITMAPINFO
*)&bi
, DIB_RGB_COLORS
);
361 ReleaseDC (NULL
, hDC
);
369 ii
.xHotspot
= pCursor
->bits
->xhot
;
370 ii
.yHotspot
= pCursor
->bits
->yhot
;
373 hCursor
= (HCURSOR
) CreateIconIndirect( &ii
);
376 winW32Error(2, "winLoadCursor - CreateIconIndirect failed:");
379 if (GetIconInfo(hCursor
, &ii
))
383 WIN_DEBUG_MSG("winLoadCursor: CreateIconIndirect returned no cursor. Trying again.\n");
385 DestroyCursor(hCursor
);
388 ii
.xHotspot
= pCursor
->bits
->xhot
;
389 ii
.yHotspot
= pCursor
->bits
->yhot
;
390 hCursor
= (HCURSOR
) CreateIconIndirect( &ii
);
393 winW32Error(2, "winLoadCursor - CreateIconIndirect failed:");
395 /* GetIconInfo creates new bitmaps. Destroy them again */
397 DeleteObject(ii
.hbmMask
);
399 DeleteObject(ii
.hbmColor
);
412 /* We couldn't make a color cursor for this screen, use
413 black and white instead */
414 hCursor
= CreateCursor (g_hInstance
,
415 pCursor
->bits
->xhot
, pCursor
->bits
->yhot
,
416 pScreenPriv
->cursor
.sm_cx
, pScreenPriv
->cursor
.sm_cy
,
419 winW32Error(2, "winLoadCursor - CreateCursor failed:");
428 ===========================================================================
430 Pointer sprite functions
432 ===========================================================================
437 * Convert the X cursor representation to native format if possible.
440 winRealizeCursor (ScreenPtr pScreen
, CursorPtr pCursor
)
442 if(pCursor
== NULL
|| pCursor
->bits
== NULL
)
445 /* FIXME: cache ARGB8888 representation? */
453 * Free the storage space associated with a realized cursor.
456 winUnrealizeCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
464 * Set the cursor sprite and position.
467 winSetCursor (ScreenPtr pScreen
, CursorPtr pCursor
, int x
, int y
)
469 POINT ptCurPos
, ptTemp
;
473 winScreenPriv(pScreen
);
474 WIN_DEBUG_MSG("winSetCursor: cursor=%p\n", pCursor
);
476 /* Inhibit changing the cursor if the mouse is not in a client area */
478 if (GetCursorPos (&ptCurPos
))
480 hwnd
= WindowFromPoint (ptCurPos
);
483 if (GetClientRect (hwnd
, &rcClient
))
485 ptTemp
.x
= rcClient
.left
;
486 ptTemp
.y
= rcClient
.top
;
487 if (ClientToScreen (hwnd
, &ptTemp
))
489 rcClient
.left
= ptTemp
.x
;
490 rcClient
.top
= ptTemp
.y
;
491 ptTemp
.x
= rcClient
.right
;
492 ptTemp
.y
= rcClient
.bottom
;
493 if (ClientToScreen (hwnd
, &ptTemp
))
495 rcClient
.right
= ptTemp
.x
;
496 rcClient
.bottom
= ptTemp
.y
;
497 if (!PtInRect (&rcClient
, ptCurPos
))
507 if (pScreenPriv
->cursor
.visible
)
509 if (!bInhibit
&& g_fSoftwareCursor
)
511 pScreenPriv
->cursor
.visible
= FALSE
;
516 if (pScreenPriv
->cursor
.handle
)
520 DestroyCursor (pScreenPriv
->cursor
.handle
);
521 pScreenPriv
->cursor
.handle
= NULL
;
523 pScreenPriv
->cursor
.handle
=
524 winLoadCursor (pScreen
, pCursor
, pScreen
->myNum
);
525 WIN_DEBUG_MSG("winSetCursor: handle=%p\n", pScreenPriv
->cursor
.handle
);
528 SetCursor (pScreenPriv
->cursor
.handle
);
530 if (!pScreenPriv
->cursor
.visible
)
532 if (!bInhibit
&& g_fSoftwareCursor
)
534 pScreenPriv
->cursor
.visible
= TRUE
;
542 * Move the cursor. This is a noop for us.
545 winMoveCursor (ScreenPtr pScreen
, int x
, int y
)
550 static miPointerSpriteFuncRec winSpriteFuncsRec
= {
559 ===========================================================================
561 Other screen functions
563 ===========================================================================
567 * winCursorQueryBestSize
568 * Handle queries for best cursor size
571 winCursorQueryBestSize (int class, unsigned short *width
,
572 unsigned short *height
, ScreenPtr pScreen
)
574 winScreenPriv(pScreen
);
576 if (class == CursorShape
)
578 *width
= pScreenPriv
->cursor
.sm_cx
;
579 *height
= pScreenPriv
->cursor
.sm_cy
;
583 if (pScreenPriv
->cursor
.QueryBestSize
)
584 (*pScreenPriv
->cursor
.QueryBestSize
)(class, width
, height
, pScreen
);
590 * Initialize cursor support
593 winInitCursor (ScreenPtr pScreen
)
595 winScreenPriv(pScreen
);
596 miPointerScreenPtr pPointPriv
;
597 /* override some screen procedures */
598 pScreenPriv
->cursor
.QueryBestSize
= pScreen
->QueryBestSize
;
599 pScreen
->QueryBestSize
= winCursorQueryBestSize
;
601 pPointPriv
= (miPointerScreenPtr
) pScreen
->devPrivates
[miPointerScreenIndex
].ptr
;
603 pScreenPriv
->cursor
.spriteFuncs
= pPointPriv
->spriteFuncs
;
604 pPointPriv
->spriteFuncs
= &winSpriteFuncsRec
;
606 pScreenPriv
->cursor
.handle
= NULL
;
607 pScreenPriv
->cursor
.visible
= FALSE
;
609 pScreenPriv
->cursor
.sm_cx
= GetSystemMetrics (SM_CXCURSOR
);
610 pScreenPriv
->cursor
.sm_cy
= GetSystemMetrics (SM_CYCURSOR
);