1 /*
2  *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3  *Copyright (C) Colin Harrison 2005-2008
4  *
5  *Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  *"Software"), to deal in the Software without restriction, including
8  *without limitation the rights to use, copy, modify, merge, publish,
9  *distribute, sublicense, and/or sell copies of the Software, and to
10  *permit persons to whom the Software is furnished to do so, subject to
11  *the following conditions:
12  *
13  *The above copyright notice and this permission notice shall be
14  *included in all copies or substantial portions of the Software.
15  *
16  *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
20  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  *Except as contained in this notice, the name of the XFree86 Project
25  *shall not be used in advertising or otherwise to promote the sale, use
26  *or other dealings in this Software without prior written authorization
27  *from the XFree86 Project.
28  *
29  * Authors:	Kensuke Matsuzaki
30  *		Earle F. Philhower, III
31  *		Harold L Hunt II
32  *              Colin Harrison
33  */
34 
35 #ifdef HAVE_XWIN_CONFIG_H
36 #include <xwin-config.h>
37 #endif
38 
39 #include "win.h"
40 #include "dixevents.h"
41 #include "winmultiwindowclass.h"
42 #include "winprefs.h"
43 #include "winmsg.h"
44 #include "inputstr.h"
45 #include <dwmapi.h>
46 
47 #ifndef WM_DWMCOMPOSITIONCHANGED
48 #define WM_DWMCOMPOSITIONCHANGED 0x031e
49 #endif
50 
51 extern void winUpdateWindowPosition(HWND hWnd, HWND * zstyle);
52 
53 /*
54  * Local globals
55  */
56 
57 static UINT_PTR g_uipMousePollingTimerID = 0;
58 
59 /*
60  * Constant defines
61  */
62 
63 #define WIN_MULTIWINDOW_SHAPE		YES
64 
65 /*
66  * ConstrainSize - Taken from TWM sources - Respects hints for sizing
67  */
68 #define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
69 static void
ConstrainSize(WinXSizeHints hints,int * widthp,int * heightp)70 ConstrainSize(WinXSizeHints hints, int *widthp, int *heightp)
71 {
72     int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
73     int baseWidth, baseHeight;
74     int dwidth = *widthp, dheight = *heightp;
75 
76     if (hints.flags & PMinSize) {
77         minWidth = hints.min_width;
78         minHeight = hints.min_height;
79     }
80     else if (hints.flags & PBaseSize) {
81         minWidth = hints.base_width;
82         minHeight = hints.base_height;
83     }
84     else
85         minWidth = minHeight = 1;
86 
87     if (hints.flags & PBaseSize) {
88         baseWidth = hints.base_width;
89         baseHeight = hints.base_height;
90     }
91     else if (hints.flags & PMinSize) {
92         baseWidth = hints.min_width;
93         baseHeight = hints.min_height;
94     }
95     else
96         baseWidth = baseHeight = 0;
97 
98     if (hints.flags & PMaxSize) {
99         maxWidth = hints.max_width;
100         maxHeight = hints.max_height;
101     }
102     else {
103         maxWidth = MAXINT;
104         maxHeight = MAXINT;
105     }
106 
107     if (hints.flags & PResizeInc) {
108         xinc = hints.width_inc;
109         yinc = hints.height_inc;
110     }
111     else
112         xinc = yinc = 1;
113 
114     /*
115      * First, clamp to min and max values
116      */
117     if (dwidth < minWidth)
118         dwidth = minWidth;
119     if (dheight < minHeight)
120         dheight = minHeight;
121 
122     if (dwidth > maxWidth)
123         dwidth = maxWidth;
124     if (dheight > maxHeight)
125         dheight = maxHeight;
126 
127     /*
128      * Second, fit to base + N * inc
129      */
130     dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
131     dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
132 
133     /*
134      * Third, adjust for aspect ratio
135      */
136 
137     /*
138      * The math looks like this:
139      *
140      * minAspectX    dwidth     maxAspectX
141      * ---------- <= ------- <= ----------
142      * minAspectY    dheight    maxAspectY
143      *
144      * If that is multiplied out, then the width and height are
145      * invalid in the following situations:
146      *
147      * minAspectX * dheight > minAspectY * dwidth
148      * maxAspectX * dheight < maxAspectY * dwidth
149      *
150      */
151 
152     if (hints.flags & PAspect) {
153         if (hints.min_aspect.x * dheight > hints.min_aspect.y * dwidth) {
154             delta =
155                 makemult(hints.min_aspect.x * dheight / hints.min_aspect.y -
156                          dwidth, xinc);
157             if (dwidth + delta <= maxWidth)
158                 dwidth += delta;
159             else {
160                 delta =
161                     makemult(dheight -
162                              dwidth * hints.min_aspect.y / hints.min_aspect.x,
163                              yinc);
164                 if (dheight - delta >= minHeight)
165                     dheight -= delta;
166             }
167         }
168 
169         if (hints.max_aspect.x * dheight < hints.max_aspect.y * dwidth) {
170             delta =
171                 makemult(dwidth * hints.max_aspect.y / hints.max_aspect.x -
172                          dheight, yinc);
173             if (dheight + delta <= maxHeight)
174                 dheight += delta;
175             else {
176                 delta =
177                     makemult(dwidth -
178                              hints.max_aspect.x * dheight / hints.max_aspect.y,
179                              xinc);
180                 if (dwidth - delta >= minWidth)
181                     dwidth -= delta;
182             }
183         }
184     }
185 
186     /* Return computed values */
187     *widthp = dwidth;
188     *heightp = dheight;
189 }
190 
191 #undef makemult
192 
193 /*
194  * ValidateSizing - Ensures size request respects hints
195  */
196 static int
ValidateSizing(HWND hwnd,WindowPtr pWin,WPARAM wParam,LPARAM lParam)197 ValidateSizing(HWND hwnd, WindowPtr pWin, WPARAM wParam, LPARAM lParam)
198 {
199     WinXSizeHints sizeHints;
200     RECT *rect;
201     int iWidth, iHeight;
202     RECT rcClient, rcWindow;
203     int iBorderWidthX, iBorderWidthY;
204 
205     /* Invalid input checking */
206     if (pWin == NULL || lParam == 0)
207         return FALSE;
208 
209     /* No size hints, no checking */
210     if (!winMultiWindowGetWMNormalHints(pWin, &sizeHints))
211         return FALSE;
212 
213     /* Avoid divide-by-zero */
214     if (sizeHints.flags & PResizeInc) {
215         if (sizeHints.width_inc == 0)
216             sizeHints.width_inc = 1;
217         if (sizeHints.height_inc == 0)
218             sizeHints.height_inc = 1;
219     }
220 
221     rect = (RECT *) lParam;
222 
223     iWidth = rect->right - rect->left;
224     iHeight = rect->bottom - rect->top;
225 
226     /* Now remove size of any borders and title bar */
227     GetClientRect(hwnd, &rcClient);
228     GetWindowRect(hwnd, &rcWindow);
229     iBorderWidthX =
230         (rcWindow.right - rcWindow.left) - (rcClient.right - rcClient.left);
231     iBorderWidthY =
232         (rcWindow.bottom - rcWindow.top) - (rcClient.bottom - rcClient.top);
233     iWidth -= iBorderWidthX;
234     iHeight -= iBorderWidthY;
235 
236     /* Constrain the size to legal values */
237     ConstrainSize(sizeHints, &iWidth, &iHeight);
238 
239     /* Add back the size of borders and title bar */
240     iWidth += iBorderWidthX;
241     iHeight += iBorderWidthY;
242 
243     /* Adjust size according to where we're dragging from */
244     switch (wParam) {
245     case WMSZ_TOP:
246     case WMSZ_TOPRIGHT:
247     case WMSZ_BOTTOM:
248     case WMSZ_BOTTOMRIGHT:
249     case WMSZ_RIGHT:
250         rect->right = rect->left + iWidth;
251         break;
252     default:
253         rect->left = rect->right - iWidth;
254         break;
255     }
256     switch (wParam) {
257     case WMSZ_BOTTOM:
258     case WMSZ_BOTTOMRIGHT:
259     case WMSZ_BOTTOMLEFT:
260     case WMSZ_RIGHT:
261     case WMSZ_LEFT:
262         rect->bottom = rect->top + iHeight;
263         break;
264     default:
265         rect->top = rect->bottom - iHeight;
266         break;
267     }
268     return TRUE;
269 }
270 
271 extern Bool winInDestroyWindowsWindow;
272 static Bool winInRaiseWindow = FALSE;
273 static void
winRaiseWindow(WindowPtr pWin)274 winRaiseWindow(WindowPtr pWin)
275 {
276     if (!winInDestroyWindowsWindow && !winInRaiseWindow) {
277         BOOL oldstate = winInRaiseWindow;
278         XID vlist[1] = { 0 };
279         winInRaiseWindow = TRUE;
280         /* Call configure window directly to make sure it gets processed
281          * in time
282          */
283         ConfigureWindow(pWin, CWStackMode, vlist, serverClient);
284         winInRaiseWindow = oldstate;
285     }
286 }
287 
288 static
289     void
winStartMousePolling(winPrivScreenPtr s_pScreenPriv)290 winStartMousePolling(winPrivScreenPtr s_pScreenPriv)
291 {
292     /*
293      * Timer to poll mouse position.  This is needed to make
294      * programs like xeyes follow the mouse properly when the
295      * mouse pointer is outside of any X window.
296      */
297     if (g_uipMousePollingTimerID == 0)
298         g_uipMousePollingTimerID = SetTimer(s_pScreenPriv->hwndScreen,
299                                             WIN_POLLING_MOUSE_TIMER_ID,
300                                             MOUSE_POLLING_INTERVAL, NULL);
301 }
302 
303 /* Undocumented */
304 typedef struct _ACCENTPOLICY
305 {
306     ULONG AccentState;
307     ULONG AccentFlags;
308     ULONG GradientColor;
309     ULONG AnimationId;
310 } ACCENTPOLICY;
311 
312 #define ACCENT_ENABLE_BLURBEHIND 3
313 
314 typedef struct _WINCOMPATTR
315 {
316     DWORD attribute;
317     PVOID pData;
318     ULONG dataSize;
319 } WINCOMPATTR;
320 
321 #define WCA_ACCENT_POLICY 19
322 
323 typedef WINBOOL WINAPI (*PFNSETWINDOWCOMPOSITIONATTRIBUTE)(HWND, WINCOMPATTR *);
324 
325 static void
CheckForAlpha(HWND hWnd,WindowPtr pWin,winScreenInfo * pScreenInfo)326 CheckForAlpha(HWND hWnd, WindowPtr pWin, winScreenInfo *pScreenInfo)
327 {
328     /* Check (once) which API we should use */
329     static Bool doOnce = TRUE;
330     static PFNSETWINDOWCOMPOSITIONATTRIBUTE pSetWindowCompositionAttribute = NULL;
331     static Bool useDwmEnableBlurBehindWindow = FALSE;
332 
333     if (doOnce)
334         {
335             OSVERSIONINFOEX osvi = {0};
336             osvi.dwOSVersionInfoSize = sizeof(osvi);
337             GetVersionEx((LPOSVERSIONINFO)&osvi);
338 
339             /* SetWindowCompositionAttribute() exists on Windows 7 and later,
340                but doesn't work for this purpose, so first check for Windows 10
341                or later */
342             if (osvi.dwMajorVersion >= 10)
343                 {
344                     HMODULE hUser32 = GetModuleHandle("user32");
345 
346                     if (hUser32)
347                         pSetWindowCompositionAttribute = (PFNSETWINDOWCOMPOSITIONATTRIBUTE) GetProcAddress(hUser32, "SetWindowCompositionAttribute");
348                     winDebug("SetWindowCompositionAttribute %s\n", pSetWindowCompositionAttribute ? "found" : "not found");
349                 }
350             /* On Windows 7 and Windows Vista, use DwmEnableBlurBehindWindow() */
351             else if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion <= 1))
352                 {
353                     useDwmEnableBlurBehindWindow = TRUE;
354                 }
355             /* On Windows 8 and Windows 8.1, using the alpha channel on those
356                seems near impossible, so we don't do anything. */
357 
358             doOnce = FALSE;
359         }
360 
361     /* alpha-channel use is wanted */
362     if (!g_fCompositeAlpha || !pScreenInfo->fCompositeWM)
363         return;
364 
365     /* Image has alpha ... */
366     if (pWin->drawable.depth != 32)
367         return;
368 
369     /* ... and we can do something useful with it? */
370     if (pSetWindowCompositionAttribute)
371         {
372             WINBOOL rc;
373             /* Use the (undocumented) SetWindowCompositionAttribute, if
374                available, to turn on alpha channel use on Windows 10. */
375             ACCENTPOLICY policy = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 } ;
376             WINCOMPATTR data = { WCA_ACCENT_POLICY,  &policy, sizeof(ACCENTPOLICY) };
377 
378             /* This turns on DWM looking at the alpha-channel of this window */
379             winDebug("enabling alpha for XID %08x hWnd %p, using SetWindowCompositionAttribute()\n", (unsigned int)pWin->drawable.id, hWnd);
380             rc = pSetWindowCompositionAttribute(hWnd, &data);
381             if (!rc)
382                 ErrorF("SetWindowCompositionAttribute failed: %d\n", (int)GetLastError());
383         }
384     else if (useDwmEnableBlurBehindWindow)
385         {
386             HRESULT rc;
387             WINBOOL enabled;
388 
389             rc = DwmIsCompositionEnabled(&enabled);
390             if ((rc == S_OK) && enabled)
391                 {
392                     /* Use DwmEnableBlurBehindWindow, to turn on alpha channel
393                        use on Windows Vista and Windows 7 */
394                     DWM_BLURBEHIND bbh;
395                     bbh.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION | DWM_BB_TRANSITIONONMAXIMIZED;
396                     bbh.fEnable = TRUE;
397                     bbh.hRgnBlur = NULL;
398                     bbh.fTransitionOnMaximized = TRUE; /* What does this do ??? */
399 
400                     /* This terribly-named function actually controls if DWM
401                        looks at the alpha channel of this window */
402                     winDebug("enabling alpha for XID %08x hWnd %p, using DwmEnableBlurBehindWindow()\n", (unsigned int)pWin->drawable.id, hWnd);
403                     rc = DwmEnableBlurBehindWindow(hWnd, &bbh);
404                     if (rc != S_OK)
405                         ErrorF("DwmEnableBlurBehindWindow failed: %x, %d\n", (int)rc, (int)GetLastError());
406                 }
407         }
408 }
409 
410 /*
411  * winTopLevelWindowProc - Window procedure for all top-level Windows windows.
412  */
413 
414 LRESULT CALLBACK
winTopLevelWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)415 winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
416 {
417     POINT ptMouse;
418     PAINTSTRUCT ps;
419     WindowPtr pWin = NULL;
420     winPrivWinPtr pWinPriv = NULL;
421     ScreenPtr s_pScreen = NULL;
422     winPrivScreenPtr s_pScreenPriv = NULL;
423     winScreenInfo *s_pScreenInfo = NULL;
424     HWND hwndScreen = NULL;
425     DrawablePtr pDraw = NULL;
426     winWMMessageRec wmMsg;
427     Bool fWMMsgInitialized = FALSE;
428     static Bool s_fTracking = FALSE;
429     Bool needRestack = FALSE;
430     LRESULT ret;
431     static Bool hasEnteredSizeMove = FALSE;
432 
433 #if CYGDEBUG
434     winDebugWin32Message("winTopLevelWindowProc", hwnd, message, wParam,
435                          lParam);
436 #endif
437 
438     /*
439        If this is WM_CREATE, set up the Windows window properties which point to
440        X window information, before we populate local convenience variables...
441      */
442     if (message == WM_CREATE) {
443         SetProp(hwnd,
444                 WIN_WINDOW_PROP,
445                 (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams);
446         SetProp(hwnd,
447                 WIN_WID_PROP,
448                 (HANDLE) (INT_PTR)winGetWindowID(((LPCREATESTRUCT) lParam)->
449                                                  lpCreateParams));
450     }
451 
452     /* Check if the Windows window property for our X window pointer is valid */
453     if ((pWin = GetProp(hwnd, WIN_WINDOW_PROP)) != NULL) {
454         /* Our X window pointer is valid */
455 
456         /* Get pointers to the drawable and the screen */
457         pDraw = &pWin->drawable;
458         s_pScreen = pWin->drawable.pScreen;
459 
460         /* Get a pointer to our window privates */
461         pWinPriv = winGetWindowPriv(pWin);
462 
463         /* Get pointers to our screen privates and screen info */
464         s_pScreenPriv = pWinPriv->pScreenPriv;
465         s_pScreenInfo = s_pScreenPriv->pScreenInfo;
466 
467         /* Get the handle for our screen-sized window */
468         hwndScreen = s_pScreenPriv->hwndScreen;
469 
470         /* */
471         wmMsg.msg = 0;
472         wmMsg.hwndWindow = hwnd;
473         wmMsg.iWindow = (Window) (INT_PTR) GetProp(hwnd, WIN_WID_PROP);
474 
475         wmMsg.iX = pDraw->x;
476         wmMsg.iY = pDraw->y;
477         wmMsg.iWidth = pDraw->width;
478         wmMsg.iHeight = pDraw->height;
479 
480         fWMMsgInitialized = TRUE;
481 
482 #if 0
483         /*
484          * Print some debugging information
485          */
486 
487         ErrorF("hWnd %08X\n", hwnd);
488         ErrorF("pWin %08X\n", pWin);
489         ErrorF("pDraw %08X\n", pDraw);
490         ErrorF("\ttype %08X\n", pWin->drawable.type);
491         ErrorF("\tclass %08X\n", pWin->drawable.class);
492         ErrorF("\tdepth %08X\n", pWin->drawable.depth);
493         ErrorF("\tbitsPerPixel %08X\n", pWin->drawable.bitsPerPixel);
494         ErrorF("\tid %08X\n", pWin->drawable.id);
495         ErrorF("\tx %08X\n", pWin->drawable.x);
496         ErrorF("\ty %08X\n", pWin->drawable.y);
497         ErrorF("\twidth %08X\n", pWin->drawable.width);
498         ErrorF("\thenght %08X\n", pWin->drawable.height);
499         ErrorF("\tpScreen %08X\n", pWin->drawable.pScreen);
500         ErrorF("\tserialNumber %08X\n", pWin->drawable.serialNumber);
501         ErrorF("g_iWindowPrivateKey %p\n", g_iWindowPrivateKey);
502         ErrorF("pWinPriv %08X\n", pWinPriv);
503         ErrorF("s_pScreenPriv %08X\n", s_pScreenPriv);
504         ErrorF("s_pScreenInfo %08X\n", s_pScreenInfo);
505         ErrorF("hwndScreen %08X\n", hwndScreen);
506 #endif
507     }
508 
509     /* Branch on message type */
510     switch (message) {
511     case WM_CREATE:
512         /*
513          * Make X windows' Z orders sync with Windows windows because
514          * there can be AlwaysOnTop windows overlapped on the window
515          * currently being created.
516          */
517         winReorderWindowsMultiWindow();
518 
519         /* Fix a 'round title bar corner background should be transparent not black' problem when first painted */
520         {
521             RECT rWindow;
522             HRGN hRgnWindow;
523 
524             GetWindowRect(hwnd, &rWindow);
525             hRgnWindow = CreateRectRgnIndirect(&rWindow);
526             SetWindowRgn(hwnd, hRgnWindow, TRUE);
527             DeleteObject(hRgnWindow);
528         }
529 
530         SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) XMING_SIGNATURE);
531 
532         CheckForAlpha(hwnd, pWin, s_pScreenInfo);
533 
534         return 0;
535 
536     case WM_INIT_SYS_MENU:
537         /*
538          * Add whatever the setup file wants to for this window
539          */
540         SetupSysMenu(hwnd);
541         return 0;
542 
543     case WM_SYSCOMMAND:
544         /*
545          * Any window menu items go through here
546          */
547         if (HandleCustomWM_COMMAND(hwnd, LOWORD(wParam), s_pScreenPriv)) {
548             /* Don't pass customized menus to DefWindowProc */
549             return 0;
550         }
551         if (wParam == SC_RESTORE || wParam == SC_MAXIMIZE) {
552             WINDOWPLACEMENT wndpl;
553 
554             wndpl.length = sizeof(wndpl);
555             if (GetWindowPlacement(hwnd, &wndpl) &&
556                 wndpl.showCmd == SW_SHOWMINIMIZED)
557                 needRestack = TRUE;
558         }
559         break;
560 
561     case WM_INITMENU:
562         /* Checks/Unchecks any menu items before they are displayed */
563         HandleCustomWM_INITMENU(hwnd, (HMENU)wParam);
564         break;
565 
566     case WM_ERASEBKGND:
567         /*
568          * Pretend that we did erase the background but we don't care,
569          * since we repaint the entire region anyhow
570          * This avoids some flickering when resizing.
571          */
572         return TRUE;
573 
574     case WM_PAINT:
575         /* Only paint if our window handle is valid */
576         if (hwnd == NULL)
577             break;
578 
579 #ifdef XWIN_GLX_WINDOWS
580         if (pWinPriv->fWglUsed) {
581             /*
582                For regions which are being drawn by GL, the shadow framebuffer doesn't have the
583                correct bits, so don't bitblt from the shadow framebuffer
584 
585                XXX: For now, just leave it alone, but ideally we want to send an expose event to
586                the window so it really redraws the affected region...
587              */
588             BeginPaint(hwnd, &ps);
589             ValidateRect(hwnd, &(ps.rcPaint));
590             EndPaint(hwnd, &ps);
591         }
592         else
593 #endif
594             /* Call the engine dependent repainter */
595             if (*s_pScreenPriv->pwinBltExposedWindowRegion)
596                 (*s_pScreenPriv->pwinBltExposedWindowRegion) (s_pScreen, pWin);
597 
598         return 0;
599 
600     case WM_MOUSEMOVE:
601         /* Unpack the client area mouse coordinates */
602         ptMouse.x = GET_X_LPARAM(lParam);
603         ptMouse.y = GET_Y_LPARAM(lParam);
604 
605         /* Translate the client area mouse coordinates to screen coordinates */
606         ClientToScreen(hwnd, &ptMouse);
607 
608         /* Screen Coords from (-X, -Y) -> Root Window (0, 0) */
609         ptMouse.x -= GetSystemMetrics(SM_XVIRTUALSCREEN);
610         ptMouse.y -= GetSystemMetrics(SM_YVIRTUALSCREEN);
611 
612         /* We can't do anything without privates */
613         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
614             break;
615 
616         /* Has the mouse pointer crossed screens? */
617         if (s_pScreen != miPointerGetScreen(g_pwinPointer))
618             miPointerSetScreen(g_pwinPointer, s_pScreenInfo->dwScreen,
619                                ptMouse.x - s_pScreenInfo->dwXOffset,
620                                ptMouse.y - s_pScreenInfo->dwYOffset);
621 
622         /* Are we tracking yet? */
623         if (!s_fTracking) {
624             TRACKMOUSEEVENT tme;
625 
626             /* Setup data structure */
627             ZeroMemory(&tme, sizeof(tme));
628             tme.cbSize = sizeof(tme);
629             tme.dwFlags = TME_LEAVE;
630             tme.hwndTrack = hwnd;
631 
632             /* Call the tracking function */
633             if (!TrackMouseEvent(&tme))
634                 ErrorF("winTopLevelWindowProc - TrackMouseEvent failed\n");
635 
636             /* Flag that we are tracking now */
637             s_fTracking = TRUE;
638         }
639 
640         /* Hide or show the Windows mouse cursor */
641         if (g_fSoftwareCursor && g_fCursor) {
642             /* Hide Windows cursor */
643             g_fCursor = FALSE;
644             ShowCursor(FALSE);
645         }
646 
647         /* Kill the timer used to poll mouse events */
648         if (g_uipMousePollingTimerID != 0) {
649             KillTimer(s_pScreenPriv->hwndScreen, WIN_POLLING_MOUSE_TIMER_ID);
650             g_uipMousePollingTimerID = 0;
651         }
652 
653         /* Deliver absolute cursor position to X Server */
654         winEnqueueMotion(ptMouse.x - s_pScreenInfo->dwXOffset,
655                          ptMouse.y - s_pScreenInfo->dwYOffset);
656 
657         return 0;
658 
659     case WM_NCMOUSEMOVE:
660         /*
661          * We break instead of returning 0 since we need to call
662          * DefWindowProc to get the mouse cursor changes
663          * and min/max/close button highlighting in Windows XP.
664          * The Platform SDK says that you should return 0 if you
665          * process this message, but it fails to mention that you
666          * will give up any default functionality if you do return 0.
667          */
668 
669         /* We can't do anything without privates */
670         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
671             break;
672 
673         /* Non-client mouse movement, show Windows cursor */
674         if (g_fSoftwareCursor && !g_fCursor) {
675             g_fCursor = TRUE;
676             ShowCursor(TRUE);
677         }
678 
679         winStartMousePolling(s_pScreenPriv);
680 
681         break;
682 
683     case WM_MOUSELEAVE:
684         /* Mouse has left our client area */
685 
686         /* Flag that we are no longer tracking */
687         s_fTracking = FALSE;
688 
689         /* Show the mouse cursor, if necessary */
690         if (g_fSoftwareCursor && !g_fCursor) {
691             g_fCursor = TRUE;
692             ShowCursor(TRUE);
693         }
694 
695         winStartMousePolling(s_pScreenPriv);
696 
697         return 0;
698 
699     case WM_LBUTTONDBLCLK:
700     case WM_LBUTTONDOWN:
701         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
702             break;
703         g_fButton[0] = TRUE;
704         SetCapture(hwnd);
705         return winMouseButtonsHandle(s_pScreen, ButtonPress, Button1, wParam);
706 
707     case WM_LBUTTONUP:
708         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
709             break;
710         g_fButton[0] = FALSE;
711         ReleaseCapture();
712         winStartMousePolling(s_pScreenPriv);
713         return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button1, wParam);
714 
715     case WM_MBUTTONDBLCLK:
716     case WM_MBUTTONDOWN:
717         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
718             break;
719         g_fButton[1] = TRUE;
720         SetCapture(hwnd);
721         return winMouseButtonsHandle(s_pScreen, ButtonPress, Button2, wParam);
722 
723     case WM_MBUTTONUP:
724         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
725             break;
726         g_fButton[1] = FALSE;
727         ReleaseCapture();
728         winStartMousePolling(s_pScreenPriv);
729         return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button2, wParam);
730 
731     case WM_RBUTTONDBLCLK:
732     case WM_RBUTTONDOWN:
733         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
734             break;
735         g_fButton[2] = TRUE;
736         SetCapture(hwnd);
737         return winMouseButtonsHandle(s_pScreen, ButtonPress, Button3, wParam);
738 
739     case WM_RBUTTONUP:
740         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
741             break;
742         g_fButton[2] = FALSE;
743         ReleaseCapture();
744         winStartMousePolling(s_pScreenPriv);
745         return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button3, wParam);
746 
747     case WM_XBUTTONDBLCLK:
748     case WM_XBUTTONDOWN:
749         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
750             break;
751         SetCapture(hwnd);
752         return winMouseButtonsHandle(s_pScreen, ButtonPress, HIWORD(wParam) + 7,
753                                      wParam);
754 
755     case WM_XBUTTONUP:
756         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
757             break;
758         ReleaseCapture();
759         winStartMousePolling(s_pScreenPriv);
760         return winMouseButtonsHandle(s_pScreen, ButtonRelease,
761                                      HIWORD(wParam) + 7, wParam);
762 
763     case WM_MOUSEWHEEL:
764         if (SendMessage
765             (hwnd, WM_NCHITTEST, 0,
766              MAKELONG(GET_X_LPARAM(lParam),
767                       GET_Y_LPARAM(lParam))) == HTCLIENT) {
768             /* Pass the message to the root window */
769             SendMessage(hwndScreen, message, wParam, lParam);
770             return 0;
771         }
772         else
773             break;
774 
775     case WM_MOUSEHWHEEL:
776         if (SendMessage
777             (hwnd, WM_NCHITTEST, 0,
778              MAKELONG(GET_X_LPARAM(lParam),
779                       GET_Y_LPARAM(lParam))) == HTCLIENT) {
780             /* Pass the message to the root window */
781             SendMessage(hwndScreen, message, wParam, lParam);
782             return 0;
783         }
784         else
785             break;
786 
787     case WM_SETFOCUS:
788         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
789             break;
790 
791         {
792             /* Get the parent window for transient handling */
793             HWND hParent = GetParent(hwnd);
794 
795             if (hParent && IsIconic(hParent))
796                 ShowWindow(hParent, SW_RESTORE);
797         }
798 
799         winRestoreModeKeyStates();
800 
801         /* Add the keyboard hook if possible */
802         if (g_fKeyboardHookLL)
803             g_fKeyboardHookLL = winInstallKeyboardHookLL();
804         return 0;
805 
806     case WM_KILLFOCUS:
807         /* Pop any pressed keys since we are losing keyboard focus */
808         winKeybdReleaseKeys();
809 
810         /* Remove our keyboard hook if it is installed */
811         winRemoveKeyboardHookLL();
812 
813         /* Revert the X focus as well, but only if the Windows focus is going to another window */
814         if (!wParam && pWin)
815             DeleteWindowFromAnyEvents(pWin, FALSE);
816 
817         return 0;
818 
819     case WM_SYSDEADCHAR:
820     case WM_DEADCHAR:
821         /*
822          * NOTE: We do nothing with WM_*CHAR messages,
823          * nor does the root window, so we can just toss these messages.
824          */
825         return 0;
826 
827     case WM_SYSKEYDOWN:
828     case WM_KEYDOWN:
829 
830         /*
831          * Don't pass Alt-F4 key combo to root window,
832          * let Windows translate to WM_CLOSE and close this top-level window.
833          *
834          * NOTE: We purposely don't check the fUseWinKillKey setting because
835          * it should only apply to the key handling for the root window,
836          * not for top-level window-manager windows.
837          *
838          * ALSO NOTE: We do pass Ctrl-Alt-Backspace to the root window
839          * because that is a key combo that no X app should be expecting to
840          * receive, since it has historically been used to shutdown the X server.
841          * Passing Ctrl-Alt-Backspace to the root window preserves that
842          * behavior, assuming that -unixkill has been passed as a parameter.
843          */
844         if (wParam == VK_F4 && (GetKeyState(VK_MENU) & 0x8000))
845             break;
846 
847 #if CYGWINDOWING_DEBUG
848         if (wParam == VK_ESCAPE) {
849             /* Place for debug: put any tests and dumps here */
850             WINDOWPLACEMENT windPlace;
851             RECT rc;
852             LPRECT pRect;
853 
854             windPlace.length = sizeof(WINDOWPLACEMENT);
855             GetWindowPlacement(hwnd, &windPlace);
856             pRect = &windPlace.rcNormalPosition;
857             ErrorF("\nCYGWINDOWING Dump:\n"
858                    "\tdrawable: (%hd, %hd) - %hdx%hd\n", pDraw->x,
859                    pDraw->y, pDraw->width, pDraw->height);
860             ErrorF("\twindPlace: (%d, %d) - %dx%d\n", (int)pRect->left,
861                    (int)pRect->top, (int)(pRect->right - pRect->left),
862                    (int)(pRect->bottom - pRect->top));
863             if (GetClientRect(hwnd, &rc)) {
864                 pRect = &rc;
865                 ErrorF("\tClientRect: (%d, %d) - %dx%d\n", (int)pRect->left,
866                        (int)pRect->top, (int)(pRect->right - pRect->left),
867                        (int)(pRect->bottom - pRect->top));
868             }
869             if (GetWindowRect(hwnd, &rc)) {
870                 pRect = &rc;
871                 ErrorF("\tWindowRect: (%d, %d) - %dx%d\n", (int)pRect->left,
872                        (int)pRect->top, (int)(pRect->right - pRect->left),
873                        (int)(pRect->bottom - pRect->top));
874             }
875             ErrorF("\n");
876         }
877 #endif
878 
879         /* Pass the message to the root window */
880         return winWindowProc(hwndScreen, message, wParam, lParam);
881 
882     case WM_SYSKEYUP:
883     case WM_KEYUP:
884 
885         /* Pass the message to the root window */
886         return winWindowProc(hwndScreen, message, wParam, lParam);
887 
888     case WM_HOTKEY:
889 
890         /* Pass the message to the root window */
891         SendMessage(hwndScreen, message, wParam, lParam);
892         return 0;
893 
894     case WM_ACTIVATE:
895 
896         /* Pass the message to the root window */
897         SendMessage(hwndScreen, message, wParam, lParam);
898 
899         if (LOWORD(wParam) != WA_INACTIVE) {
900             /* Raise the window to the top in Z order */
901             /* ago: Activate does not mean putting it to front! */
902             /*
903                wmMsg.msg = WM_WM_RAISE;
904                if (fWMMsgInitialized)
905                winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
906              */
907 
908             /* Tell our Window Manager thread to activate the window */
909             wmMsg.msg = WM_WM_ACTIVATE;
910             if (fWMMsgInitialized)
911                 if (!pWin || !pWin->overrideRedirect)   /* for OOo menus */
912                     winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
913         }
914         /* Prevent the mouse wheel from stalling when another window is minimized */
915         if (HIWORD(wParam) == 0 && LOWORD(wParam) == WA_ACTIVE &&
916             (HWND) lParam != NULL && (HWND) lParam != GetParent(hwnd))
917             SetFocus(hwnd);
918         return 0;
919 
920     case WM_ACTIVATEAPP:
921         /*
922          * This message is also sent to the root window
923          * so we do nothing for individual multiwindow windows
924          */
925         break;
926 
927     case WM_CLOSE:
928         /* Remove AppUserModelID property */
929         winSetAppUserModelID(hwnd, NULL);
930         /* Branch on if the window was killed in X already */
931         if (pWinPriv->fXKilled) {
932             /* Window was killed, go ahead and destroy the window */
933             DestroyWindow(hwnd);
934         }
935         else {
936             /* Tell our Window Manager thread to kill the window */
937             wmMsg.msg = WM_WM_KILL;
938             if (fWMMsgInitialized)
939                 winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
940         }
941         return 0;
942 
943     case WM_DESTROY:
944 
945         /* Branch on if the window was killed in X already */
946         if (pWinPriv && !pWinPriv->fXKilled) {
947             ErrorF("winTopLevelWindowProc - WM_DESTROY - WM_WM_KILL\n");
948 
949             /* Tell our Window Manager thread to kill the window */
950             wmMsg.msg = WM_WM_KILL;
951             if (fWMMsgInitialized)
952                 winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
953         }
954 
955         RemoveProp(hwnd, WIN_WINDOW_PROP);
956         RemoveProp(hwnd, WIN_WID_PROP);
957         RemoveProp(hwnd, WIN_NEEDMANAGE_PROP);
958 
959         break;
960 
961     case WM_MOVE:
962         /* Adjust the X Window to the moved Windows window */
963         if (!hasEnteredSizeMove)
964             winAdjustXWindow(pWin, hwnd);
965         /* else: Wait for WM_EXITSIZEMOVE */
966         return 0;
967 
968     case WM_SHOWWINDOW:
969         /* Bail out if the window is being hidden */
970         if (!wParam)
971             return 0;
972 
973         /* */
974         if (!pWin->overrideRedirect) {
975             HWND zstyle = HWND_NOTOPMOST;
976 
977             /* Flag that this window needs to be made active when clicked */
978             SetProp(hwnd, WIN_NEEDMANAGE_PROP, (HANDLE) 1);
979 
980             /* Set the transient style flags */
981             if (GetParent(hwnd))
982                 SetWindowLongPtr(hwnd, GWL_STYLE,
983                                  WS_POPUP | WS_OVERLAPPED | WS_SYSMENU |
984                                  WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
985             /* Set the window standard style flags */
986             else
987                 SetWindowLongPtr(hwnd, GWL_STYLE,
988                                  (WS_POPUP | WS_OVERLAPPEDWINDOW |
989                                   WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
990                                  & ~WS_CAPTION & ~WS_SIZEBOX);
991 
992             winUpdateWindowPosition(hwnd, &zstyle);
993 
994             {
995                 WinXWMHints hints;
996 
997                 if (winMultiWindowGetWMHints(pWin, &hints)) {
998                     /*
999                        Give the window focus, unless it has an InputHint
1000                        which is FALSE (this is used by e.g. glean to
1001                        avoid every test window grabbing the focus)
1002                      */
1003                     if (!((hints.flags & InputHint) && (!hints.input))) {
1004                         SetForegroundWindow(hwnd);
1005                     }
1006                 }
1007             }
1008             wmMsg.msg = WM_WM_MAP_MANAGED;
1009         }
1010         else {                  /* It is an overridden window so make it top of Z stack */
1011 
1012             HWND forHwnd = GetForegroundWindow();
1013 
1014 #if CYGWINDOWING_DEBUG
1015             ErrorF("overridden window is shown\n");
1016 #endif
1017             if (forHwnd != NULL) {
1018                 if (GetWindowLongPtr(forHwnd, GWLP_USERDATA) & (LONG_PTR)
1019                     XMING_SIGNATURE) {
1020                     if (GetWindowLongPtr(forHwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
1021                         SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
1022                                      SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1023                     else
1024                         SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
1025                                      SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1026                 }
1027             }
1028             wmMsg.msg = WM_WM_MAP_UNMANAGED;
1029         }
1030 
1031         /* Tell our Window Manager thread to map the window */
1032         if (fWMMsgInitialized)
1033             winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
1034 
1035         winStartMousePolling(s_pScreenPriv);
1036 
1037         return 0;
1038 
1039     case WM_SIZING:
1040         /* Need to legalize the size according to WM_NORMAL_HINTS */
1041         /* for applications like xterm */
1042         return ValidateSizing(hwnd, pWin, wParam, lParam);
1043 
1044     case WM_WINDOWPOSCHANGED:
1045     {
1046         LPWINDOWPOS pWinPos = (LPWINDOWPOS) lParam;
1047 
1048         if (!(pWinPos->flags & SWP_NOZORDER)) {
1049 #if CYGWINDOWING_DEBUG
1050             winDebug("\twindow z order was changed\n");
1051 #endif
1052             if (pWinPos->hwndInsertAfter == HWND_TOP
1053                 || pWinPos->hwndInsertAfter == HWND_TOPMOST
1054                 || pWinPos->hwndInsertAfter == HWND_NOTOPMOST) {
1055 #if CYGWINDOWING_DEBUG
1056                 winDebug("\traise to top\n");
1057 #endif
1058                 /* Raise the window to the top in Z order */
1059                 winRaiseWindow(pWin);
1060             }
1061             else if (pWinPos->hwndInsertAfter == HWND_BOTTOM) {
1062             }
1063             else {
1064                 /* Check if this window is top of X windows. */
1065                 HWND hWndAbove = NULL;
1066                 DWORD dwCurrentProcessID = GetCurrentProcessId();
1067                 DWORD dwWindowProcessID = 0;
1068 
1069                 for (hWndAbove = pWinPos->hwndInsertAfter;
1070                      hWndAbove != NULL;
1071                      hWndAbove = GetNextWindow(hWndAbove, GW_HWNDPREV)) {
1072                     /* Ignore other XWin process's window */
1073                     GetWindowThreadProcessId(hWndAbove, &dwWindowProcessID);
1074 
1075                     if ((dwWindowProcessID == dwCurrentProcessID)
1076                         && GetProp(hWndAbove, WIN_WINDOW_PROP)
1077                         && !IsWindowVisible(hWndAbove)
1078                         && !IsIconic(hWndAbove))        /* ignore minimized windows */
1079                         break;
1080                 }
1081                 /* If this is top of X windows in Windows stack,
1082                    raise it in X stack. */
1083                 if (hWndAbove == NULL) {
1084 #if CYGWINDOWING_DEBUG
1085                     winDebug("\traise to top\n");
1086 #endif
1087                     winRaiseWindow(pWin);
1088                 }
1089             }
1090         }
1091     }
1092         /*
1093          * Pass the message to DefWindowProc to let the function
1094          * break down WM_WINDOWPOSCHANGED to WM_MOVE and WM_SIZE.
1095          */
1096         break;
1097 
1098     case WM_ENTERSIZEMOVE:
1099         hasEnteredSizeMove = TRUE;
1100         return 0;
1101 
1102     case WM_EXITSIZEMOVE:
1103         /* Adjust the X Window to the moved Windows window */
1104         hasEnteredSizeMove = FALSE;
1105         winAdjustXWindow(pWin, hwnd);
1106         return 0;
1107 
1108     case WM_SIZE:
1109         /* see dix/window.c */
1110 #if CYGWINDOWING_DEBUG
1111     {
1112         char buf[64];
1113 
1114         switch (wParam) {
1115         case SIZE_MINIMIZED:
1116             strcpy(buf, "SIZE_MINIMIZED");
1117             break;
1118         case SIZE_MAXIMIZED:
1119             strcpy(buf, "SIZE_MAXIMIZED");
1120             break;
1121         case SIZE_RESTORED:
1122             strcpy(buf, "SIZE_RESTORED");
1123             break;
1124         default:
1125             strcpy(buf, "UNKNOWN_FLAG");
1126         }
1127         ErrorF("winTopLevelWindowProc - WM_SIZE to %dx%d (%s)\n",
1128                (int) LOWORD(lParam), (int) HIWORD(lParam), buf);
1129     }
1130 #endif
1131         if (!hasEnteredSizeMove) {
1132             /* Adjust the X Window to the moved Windows window */
1133             winAdjustXWindow(pWin, hwnd);
1134         }
1135         /* else: wait for WM_EXITSIZEMOVE */
1136         return 0;               /* end of WM_SIZE handler */
1137 
1138     case WM_STYLECHANGING:
1139         /*
1140            When the style changes, adjust the Windows window size so the client area remains the same size,
1141            and adjust the Windows window position so that the client area remains in the same place.
1142          */
1143     {
1144         RECT newWinRect;
1145         DWORD dwExStyle;
1146         DWORD dwStyle;
1147         DWORD newStyle = ((STYLESTRUCT *) lParam)->styleNew;
1148         WINDOWINFO wi;
1149 
1150         dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
1151         dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
1152 
1153         winDebug("winTopLevelWindowProc - WM_STYLECHANGING from %08x %08x\n",
1154                  (unsigned int)dwStyle, (unsigned int)dwExStyle);
1155 
1156         if (wParam == GWL_EXSTYLE)
1157             dwExStyle = newStyle;
1158 
1159         if (wParam == GWL_STYLE)
1160             dwStyle = newStyle;
1161 
1162         winDebug("winTopLevelWindowProc - WM_STYLECHANGING to %08x %08x\n",
1163                  (unsigned int)dwStyle, (unsigned int)dwExStyle);
1164 
1165         /* Get client rect in screen coordinates */
1166         wi.cbSize = sizeof(WINDOWINFO);
1167         GetWindowInfo(hwnd, &wi);
1168 
1169         winDebug
1170             ("winTopLevelWindowProc - WM_STYLECHANGING client area {%d, %d, %d, %d}, {%d x %d}\n",
1171              (int)wi.rcClient.left, (int)wi.rcClient.top, (int)wi.rcClient.right,
1172              (int)wi.rcClient.bottom, (int)(wi.rcClient.right - wi.rcClient.left),
1173              (int)(wi.rcClient.bottom - wi.rcClient.top));
1174 
1175         newWinRect = wi.rcClient;
1176         if (!AdjustWindowRectEx(&newWinRect, dwStyle, FALSE, dwExStyle))
1177             winDebug
1178                 ("winTopLevelWindowProc - WM_STYLECHANGING AdjustWindowRectEx failed\n");
1179 
1180         winDebug
1181             ("winTopLevelWindowProc - WM_STYLECHANGING window area should be {%d, %d, %d, %d}, {%d x %d}\n",
1182              (int)newWinRect.left, (int)newWinRect.top, (int)newWinRect.right,
1183              (int)newWinRect.bottom, (int)(newWinRect.right - newWinRect.left),
1184              (int)(newWinRect.bottom - newWinRect.top));
1185 
1186         /*
1187            Style change hasn't happened yet, so we can't adjust the window size yet, as the winAdjustXWindow()
1188            which WM_SIZE does will use the current (unchanged) style.  Instead make a note to change it when
1189            WM_STYLECHANGED is received...
1190          */
1191         pWinPriv->hDwp = BeginDeferWindowPos(1);
1192         pWinPriv->hDwp =
1193             DeferWindowPos(pWinPriv->hDwp, hwnd, NULL, newWinRect.left,
1194                            newWinRect.top, newWinRect.right - newWinRect.left,
1195                            newWinRect.bottom - newWinRect.top,
1196                            SWP_NOACTIVATE | SWP_NOZORDER);
1197     }
1198         return 0;
1199 
1200     case WM_STYLECHANGED:
1201     {
1202         if (pWinPriv->hDwp) {
1203             EndDeferWindowPos(pWinPriv->hDwp);
1204             pWinPriv->hDwp = NULL;
1205         }
1206         winDebug("winTopLevelWindowProc - WM_STYLECHANGED done\n");
1207     }
1208         return 0;
1209 
1210     case WM_MOUSEACTIVATE:
1211 
1212         /* Check if this window needs to be made active when clicked */
1213         if (!GetProp(pWinPriv->hWnd, WIN_NEEDMANAGE_PROP)) {
1214 #if CYGMULTIWINDOW_DEBUG
1215             ErrorF("winTopLevelWindowProc - WM_MOUSEACTIVATE - "
1216                    "MA_NOACTIVATE\n");
1217 #endif
1218 
1219             /* */
1220             return MA_NOACTIVATE;
1221         }
1222         break;
1223 
1224     case WM_SETCURSOR:
1225         if (LOWORD(lParam) == HTCLIENT) {
1226             if (!g_fSoftwareCursor)
1227                 SetCursor(s_pScreenPriv->cursor.handle);
1228             return TRUE;
1229         }
1230         break;
1231 
1232 
1233     case WM_DWMCOMPOSITIONCHANGED:
1234         /* This message is only sent on Vista/W7 */
1235         CheckForAlpha(hwnd, pWin, s_pScreenInfo);
1236 
1237         return 0;
1238     default:
1239         break;
1240     }
1241 
1242     ret = DefWindowProc(hwnd, message, wParam, lParam);
1243     /*
1244      * If the window was minized we get the stack change before the window is restored
1245      * and so it gets lost. Ensure there stacking order is correct.
1246      */
1247     if (needRestack)
1248         winReorderWindowsMultiWindow();
1249     return ret;
1250 }
1251