17823baf2b992567df190d0247d5adfb7e4b6af0
[framework/uifw/xorg/server/xorg-server.git] / hw / xwin / winmultiwindowwndproc.c
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
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
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
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
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
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))) {
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: (%ld, %ld) - %ldx%ld\n", pRect->left,
774                    pRect->top, pRect->right - pRect->left,
775                    pRect->bottom - pRect->top);
776             if (GetClientRect(hwnd, &rc)) {
777                 pRect = &rc;
778                 ErrorF("\tClientRect: (%ld, %ld) - %ldx%ld\n", pRect->left,
779                        pRect->top, pRect->right - pRect->left,
780                        pRect->bottom - pRect->top);
781             }
782             if (GetWindowRect(hwnd, &rc)) {
783                 pRect = &rc;
784                 ErrorF("\tWindowRect: (%ld, %ld) - %ldx%ld\n", pRect->left,
785                        pRect->top, pRect->right - pRect->left,
786                        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) - %d ms\n",
1041                (int) LOWORD(lParam), (int) HIWORD(lParam), buf,
1042                (int) (GetTickCount()));
1043     }
1044 #endif
1045         if (!hasEnteredSizeMove) {
1046             /* Adjust the X Window to the moved Windows window */
1047             winAdjustXWindow(pWin, hwnd);
1048         }
1049         /* else: wait for WM_EXITSIZEMOVE */
1050         return 0;               /* end of WM_SIZE handler */
1051
1052     case WM_STYLECHANGING:
1053         /*
1054            When the style changes, adjust the Windows window size so the client area remains the same size,
1055            and adjust the Windows window position so that the client area remains in the same place.
1056          */
1057     {
1058         RECT newWinRect;
1059         DWORD dwExStyle;
1060         DWORD dwStyle;
1061         DWORD newStyle = ((STYLESTRUCT *) lParam)->styleNew;
1062         WINDOWINFO wi;
1063
1064         dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
1065         dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
1066
1067         winDebug("winTopLevelWindowProc - WM_STYLECHANGING from %08x %08x\n",
1068                  dwStyle, dwExStyle);
1069
1070         if (wParam == GWL_EXSTYLE)
1071             dwExStyle = newStyle;
1072
1073         if (wParam == GWL_STYLE)
1074             dwStyle = newStyle;
1075
1076         winDebug("winTopLevelWindowProc - WM_STYLECHANGING to %08x %08x\n",
1077                  dwStyle, dwExStyle);
1078
1079         /* Get client rect in screen coordinates */
1080         wi.cbSize = sizeof(WINDOWINFO);
1081         GetWindowInfo(hwnd, &wi);
1082
1083         winDebug
1084             ("winTopLevelWindowProc - WM_STYLECHANGING client area {%d, %d, %d, %d}, {%d x %d}\n",
1085              wi.rcClient.left, wi.rcClient.top, wi.rcClient.right,
1086              wi.rcClient.bottom, wi.rcClient.right - wi.rcClient.left,
1087              wi.rcClient.bottom - wi.rcClient.top);
1088
1089         newWinRect = wi.rcClient;
1090         if (!AdjustWindowRectEx(&newWinRect, dwStyle, FALSE, dwExStyle))
1091             winDebug
1092                 ("winTopLevelWindowProc - WM_STYLECHANGING AdjustWindowRectEx failed\n");
1093
1094         winDebug
1095             ("winTopLevelWindowProc - WM_STYLECHANGING window area should be {%d, %d, %d, %d}, {%d x %d}\n",
1096              newWinRect.left, newWinRect.top, newWinRect.right,
1097              newWinRect.bottom, newWinRect.right - newWinRect.left,
1098              newWinRect.bottom - newWinRect.top);
1099
1100         /*
1101            Style change hasn't happened yet, so we can't adjust the window size yet, as the winAdjustXWindow()
1102            which WM_SIZE does will use the current (unchanged) style.  Instead make a note to change it when
1103            WM_STYLECHANGED is received...
1104          */
1105         pWinPriv->hDwp = BeginDeferWindowPos(1);
1106         pWinPriv->hDwp =
1107             DeferWindowPos(pWinPriv->hDwp, hwnd, NULL, newWinRect.left,
1108                            newWinRect.top, newWinRect.right - newWinRect.left,
1109                            newWinRect.bottom - newWinRect.top,
1110                            SWP_NOACTIVATE | SWP_NOZORDER);
1111     }
1112         return 0;
1113
1114     case WM_STYLECHANGED:
1115     {
1116         if (pWinPriv->hDwp) {
1117             EndDeferWindowPos(pWinPriv->hDwp);
1118             pWinPriv->hDwp = NULL;
1119         }
1120         winDebug("winTopLevelWindowProc - WM_STYLECHANGED done\n");
1121     }
1122         return 0;
1123
1124     case WM_MOUSEACTIVATE:
1125
1126         /* Check if this window needs to be made active when clicked */
1127         if (!GetProp(pWinPriv->hWnd, WIN_NEEDMANAGE_PROP)) {
1128 #if CYGMULTIWINDOW_DEBUG
1129             ErrorF("winTopLevelWindowProc - WM_MOUSEACTIVATE - "
1130                    "MA_NOACTIVATE\n");
1131 #endif
1132
1133             /* */
1134             return MA_NOACTIVATE;
1135         }
1136         break;
1137
1138     case WM_SETCURSOR:
1139         if (LOWORD(lParam) == HTCLIENT) {
1140             if (!g_fSoftwareCursor)
1141                 SetCursor(s_pScreenPriv->cursor.handle);
1142             return TRUE;
1143         }
1144         break;
1145
1146     default:
1147         break;
1148     }
1149
1150     ret = DefWindowProc(hwnd, message, wParam, lParam);
1151     /*
1152      * If the window was minized we get the stack change before the window is restored
1153      * and so it gets lost. Ensure there stacking order is correct.
1154      */
1155     if (needRestack)
1156         winReorderWindowsMultiWindow();
1157     return ret;
1158 }