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