First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xwin / wincursor.c
blobc1e619bf87f9d6ff1e622a4af3d0c68fea615ef8
1 /*
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
29 * Suhaib M Siddiqi
30 * Peter Busch
31 * Harold L Hunt II
34 #ifdef HAVE_XWIN_CONFIG_H
35 #include <xwin-config.h>
36 #endif
37 #include "win.h"
38 #include "winmsg.h"
39 #include <cursorstr.h>
40 #include <mipointrst.h>
41 #include <servermd.h>
43 extern Bool g_fSoftwareCursor;
46 #ifndef MIN
47 #define MIN(x,y) ((x)<(y)?(x):(y))
48 #endif
50 #define BYTE_COUNT(x) (((x) + 7) / 8)
52 #define BRIGHTNESS(x) (x##Red * 0.299 + x##Green * 0.587 + x##Blue * 0.114)
54 #if 0
55 # define WIN_DEBUG_MSG winDebug
56 #else
57 # define WIN_DEBUG_MSG(...)
58 #endif
61 * Local function prototypes
64 static void
65 winPointerWarpCursor (ScreenPtr pScreen, int x, int y);
67 static Bool
68 winCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y);
70 static void
71 winCrossScreen (ScreenPtr pScreen, Bool fEntering);
73 miPointerScreenFuncRec g_winPointerCursorFuncs =
75 winCursorOffScreen,
76 winCrossScreen,
77 winPointerWarpCursor
81 static void
82 winPointerWarpCursor (ScreenPtr pScreen, int x, int y)
84 winScreenPriv(pScreen);
85 RECT rcClient;
86 static Bool s_fInitialWarp = TRUE;
88 /* Discard first warp call */
89 if (s_fInitialWarp)
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",
97 x, y);
99 return;
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,
110 HWND_DESKTOP,
111 (LPPOINT)&rcClient,
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);
125 static Bool
126 winCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y)
128 return FALSE;
131 static void
132 winCrossScreen (ScreenPtr pScreen, Bool fEntering)
136 static unsigned char
137 reverse(unsigned char c)
139 int i;
140 unsigned char ret = 0;
141 for (i = 0; i < 8; ++i)
143 ret |= ((c >> i)&1) << (7 - i);
145 return ret;
149 * Convert X cursor to Windows cursor
150 * FIXME: Perhaps there are more smart code
152 static HCURSOR
153 winLoadCursor (ScreenPtr pScreen, CursorPtr pCursor, int screen)
155 winScreenPriv(pScreen);
156 HCURSOR hCursor = NULL;
157 unsigned char *pAnd;
158 unsigned char *pXor;
159 int nCX, nCY;
160 int nBytes;
161 double dForeY, dBackY;
162 BOOL fReverse;
163 HBITMAP hAnd, hXor;
164 ICONINFO ii;
165 unsigned char *pCur;
166 int x, y;
167 unsigned char bit;
168 HDC hDC;
169 BITMAPV4HEADER bi;
170 BITMAPINFO *pbmi;
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;
221 pAnd[nWinPix] = 0;
222 if (fReverse)
223 pXor[nWinPix] = reverse (~pCursor->bits->source[nXPix]);
224 else
225 pXor[nWinPix] = reverse (pCursor->bits->source[nXPix]);
228 else
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);
239 if (fReverse)
240 pXor[nWinPix] = reverse (~pCursor->bits->source[nXPix] & mask);
241 else
242 pXor[nWinPix] = reverse (pCursor->bits->source[nXPix] & mask);
246 /* prepare the pointers */
247 hCursor = NULL;
248 lpBits = NULL;
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 */
258 bi.bV4Planes = 1;
259 bi.bV4BitCount = 32;
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));
269 if (lpBits)
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 */
281 if (!lpBits)
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,
310 sizeof (char));
312 pCur = (unsigned char *)lpBits;
313 if (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 */
320 (*pCur++) = 0;
321 else /* Within X11 icon bounds */
323 int nWinPix = BYTE_COUNT(pScreenPriv->cursor.sm_cx) * y + (x/8);
325 bit = pAnd[nWinPix];
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 */
333 (*pCur++) = 2;
334 else /* Draw background */
335 (*pCur++) = 1;
337 else /* Outside the cursor mask */
338 (*pCur++) = 0;
340 } /* end for (x) */
341 } /* end for (y) */
342 } /* end if (lpbits) */
345 /* If one of the previous two methods gave us the bitmap we need, make a cursor */
346 if (lpBits)
348 WIN_DEBUG_MSG("winLoadCursor: Creating bitmap cursor: hotspot %d,%d\n",
349 pCursor->bits->xhot, pCursor->bits->yhot);
351 hAnd = NULL;
352 hXor = NULL;
354 hAnd = CreateBitmap (pScreenPriv->cursor.sm_cx, pScreenPriv->cursor.sm_cy, 1, 1, pAnd);
356 hDC = GetDC (NULL);
357 if (hDC)
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);
363 free (lpBits);
366 if (hAnd && hXor)
368 ii.fIcon = FALSE;
369 ii.xHotspot = pCursor->bits->xhot;
370 ii.yHotspot = pCursor->bits->yhot;
371 ii.hbmMask = hAnd;
372 ii.hbmColor = hXor;
373 hCursor = (HCURSOR) CreateIconIndirect( &ii );
375 if (hCursor == NULL)
376 winW32Error(2, "winLoadCursor - CreateIconIndirect failed:");
377 else
379 if (GetIconInfo(hCursor, &ii))
381 if (ii.fIcon)
383 WIN_DEBUG_MSG("winLoadCursor: CreateIconIndirect returned no cursor. Trying again.\n");
385 DestroyCursor(hCursor);
387 ii.fIcon = FALSE;
388 ii.xHotspot = pCursor->bits->xhot;
389 ii.yHotspot = pCursor->bits->yhot;
390 hCursor = (HCURSOR) CreateIconIndirect( &ii );
392 if (hCursor == NULL)
393 winW32Error(2, "winLoadCursor - CreateIconIndirect failed:");
395 /* GetIconInfo creates new bitmaps. Destroy them again */
396 if (ii.hbmMask)
397 DeleteObject(ii.hbmMask);
398 if (ii.hbmColor)
399 DeleteObject(ii.hbmColor);
404 if (hAnd)
405 DeleteObject (hAnd);
406 if (hXor)
407 DeleteObject (hXor);
410 if (!hCursor)
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,
417 pAnd, pXor);
418 if (hCursor == NULL)
419 winW32Error(2, "winLoadCursor - CreateCursor failed:");
421 free (pAnd);
422 free (pXor);
424 return hCursor;
428 ===========================================================================
430 Pointer sprite functions
432 ===========================================================================
436 * winRealizeCursor
437 * Convert the X cursor representation to native format if possible.
439 static Bool
440 winRealizeCursor (ScreenPtr pScreen, CursorPtr pCursor)
442 if(pCursor == NULL || pCursor->bits == NULL)
443 return FALSE;
445 /* FIXME: cache ARGB8888 representation? */
447 return TRUE;
452 * winUnrealizeCursor
453 * Free the storage space associated with a realized cursor.
455 static Bool
456 winUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
458 return TRUE;
463 * winSetCursor
464 * Set the cursor sprite and position.
466 static void
467 winSetCursor (ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
469 POINT ptCurPos, ptTemp;
470 HWND hwnd;
471 RECT rcClient;
472 BOOL bInhibit;
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 */
477 bInhibit = FALSE;
478 if (GetCursorPos (&ptCurPos))
480 hwnd = WindowFromPoint (ptCurPos);
481 if (hwnd)
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))
498 bInhibit = TRUE;
505 if (pCursor == NULL)
507 if (pScreenPriv->cursor.visible)
509 if (!bInhibit && g_fSoftwareCursor)
510 ShowCursor (FALSE);
511 pScreenPriv->cursor.visible = FALSE;
514 else
516 if (pScreenPriv->cursor.handle)
518 if (!bInhibit)
519 SetCursor (NULL);
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);
527 if (!bInhibit)
528 SetCursor (pScreenPriv->cursor.handle);
530 if (!pScreenPriv->cursor.visible)
532 if (!bInhibit && g_fSoftwareCursor)
533 ShowCursor (TRUE);
534 pScreenPriv->cursor.visible = TRUE;
541 * QuartzMoveCursor
542 * Move the cursor. This is a noop for us.
544 static void
545 winMoveCursor (ScreenPtr pScreen, int x, int y)
550 static miPointerSpriteFuncRec winSpriteFuncsRec = {
551 winRealizeCursor,
552 winUnrealizeCursor,
553 winSetCursor,
554 winMoveCursor
559 ===========================================================================
561 Other screen functions
563 ===========================================================================
567 * winCursorQueryBestSize
568 * Handle queries for best cursor size
570 static void
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;
581 else
583 if (pScreenPriv->cursor.QueryBestSize)
584 (*pScreenPriv->cursor.QueryBestSize)(class, width, height, pScreen);
589 * winInitCursor
590 * Initialize cursor support
592 Bool
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);
612 return TRUE;