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