af917d6fcd59033dd199fad53a12d7a816ea5399
[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, Bool reshape, 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
320 #if CYGDEBUG
321     winDebugWin32Message("winTopLevelWindowProc", hwnd, message, wParam,
322                          lParam);
323 #endif
324
325     /* Check if the Windows window property for our X window pointer is valid */
326     if ((pWin = GetProp(hwnd, WIN_WINDOW_PROP)) != NULL) {
327         /* Our X window pointer is valid */
328
329         /* Get pointers to the drawable and the screen */
330         pDraw = &pWin->drawable;
331         s_pScreen = pWin->drawable.pScreen;
332
333         /* Get a pointer to our window privates */
334         pWinPriv = winGetWindowPriv(pWin);
335
336         /* Get pointers to our screen privates and screen info */
337         s_pScreenPriv = pWinPriv->pScreenPriv;
338         s_pScreenInfo = s_pScreenPriv->pScreenInfo;
339
340         /* Get the handle for our screen-sized window */
341         hwndScreen = s_pScreenPriv->hwndScreen;
342
343         /* */
344         wmMsg.msg = 0;
345         wmMsg.hwndWindow = hwnd;
346         wmMsg.iWindow = (Window) GetProp(hwnd, WIN_WID_PROP);
347
348         wmMsg.iX = pDraw->x;
349         wmMsg.iY = pDraw->y;
350         wmMsg.iWidth = pDraw->width;
351         wmMsg.iHeight = pDraw->height;
352
353         fWMMsgInitialized = TRUE;
354
355 #if 0
356         /*
357          * Print some debugging information
358          */
359
360         ErrorF("hWnd %08X\n", hwnd);
361         ErrorF("pWin %08X\n", pWin);
362         ErrorF("pDraw %08X\n", pDraw);
363         ErrorF("\ttype %08X\n", pWin->drawable.type);
364         ErrorF("\tclass %08X\n", pWin->drawable.class);
365         ErrorF("\tdepth %08X\n", pWin->drawable.depth);
366         ErrorF("\tbitsPerPixel %08X\n", pWin->drawable.bitsPerPixel);
367         ErrorF("\tid %08X\n", pWin->drawable.id);
368         ErrorF("\tx %08X\n", pWin->drawable.x);
369         ErrorF("\ty %08X\n", pWin->drawable.y);
370         ErrorF("\twidth %08X\n", pWin->drawable.width);
371         ErrorF("\thenght %08X\n", pWin->drawable.height);
372         ErrorF("\tpScreen %08X\n", pWin->drawable.pScreen);
373         ErrorF("\tserialNumber %08X\n", pWin->drawable.serialNumber);
374         ErrorF("g_iWindowPrivateKey %p\n", g_iWindowPrivateKey);
375         ErrorF("pWinPriv %08X\n", pWinPriv);
376         ErrorF("s_pScreenPriv %08X\n", s_pScreenPriv);
377         ErrorF("s_pScreenInfo %08X\n", s_pScreenInfo);
378         ErrorF("hwndScreen %08X\n", hwndScreen);
379 #endif
380     }
381
382     /* Branch on message type */
383     switch (message) {
384     case WM_CREATE:
385
386         /* */
387         SetProp(hwnd,
388                 WIN_WINDOW_PROP,
389                 (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams);
390
391         /* */
392         SetProp(hwnd,
393                 WIN_WID_PROP,
394                 (HANDLE) winGetWindowID(((LPCREATESTRUCT) lParam)->
395                                         lpCreateParams));
396
397         /*
398          * Make X windows' Z orders sync with Windows windows because
399          * there can be AlwaysOnTop windows overlapped on the window
400          * currently being created.
401          */
402         winReorderWindowsMultiWindow();
403
404         /* Fix a 'round title bar corner background should be transparent not black' problem when first painted */
405         {
406             RECT rWindow;
407             HRGN hRgnWindow;
408
409             GetWindowRect(hwnd, &rWindow);
410             hRgnWindow = CreateRectRgnIndirect(&rWindow);
411             SetWindowRgn(hwnd, hRgnWindow, TRUE);
412             DeleteObject(hRgnWindow);
413         }
414
415         SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) XMING_SIGNATURE);
416
417         return 0;
418
419     case WM_INIT_SYS_MENU:
420         /*
421          * Add whatever the setup file wants to for this window
422          */
423         SetupSysMenu((unsigned long) hwnd);
424         return 0;
425
426     case WM_SYSCOMMAND:
427         /*
428          * Any window menu items go through here
429          */
430         if (HandleCustomWM_COMMAND((unsigned long) hwnd, LOWORD(wParam))) {
431             /* Don't pass customized menus to DefWindowProc */
432             return 0;
433         }
434         if (wParam == SC_RESTORE || wParam == SC_MAXIMIZE) {
435             WINDOWPLACEMENT wndpl;
436
437             wndpl.length = sizeof(wndpl);
438             if (GetWindowPlacement(hwnd, &wndpl) &&
439                 wndpl.showCmd == SW_SHOWMINIMIZED)
440                 needRestack = TRUE;
441         }
442         break;
443
444     case WM_INITMENU:
445         /* Checks/Unchecks any menu items before they are displayed */
446         HandleCustomWM_INITMENU((unsigned long) hwnd, wParam);
447         break;
448
449     case WM_ERASEBKGND:
450         /*
451          * Pretend that we did erase the background but we don't care,
452          * since we repaint the entire region anyhow
453          * This avoids some flickering when resizing.
454          */
455         return TRUE;
456
457     case WM_PAINT:
458         /* Only paint if our window handle is valid */
459         if (hwndScreen == NULL)
460             break;
461
462         /* BeginPaint gives us an hdc that clips to the invalidated region */
463         hdcUpdate = BeginPaint(hwnd, &ps);
464         /* Avoid the BitBlt's if the PAINTSTRUCT is bogus */
465         if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 &&
466             ps.rcPaint.left == 0 && ps.rcPaint.top == 0) {
467             EndPaint(hwnd, &ps);
468             return 0;
469         }
470
471 #ifdef XWIN_GLX_WINDOWS
472         if (pWinPriv->fWglUsed) {
473             /*
474                For regions which are being drawn by GL, the shadow framebuffer doesn't have the
475                correct bits, so don't bitblt from the shadow framebuffer
476
477                XXX: For now, just leave it alone, but ideally we want to send an expose event to
478                the window so it really redraws the affected region...
479              */
480             ValidateRect(hwnd, &(ps.rcPaint));
481         }
482         else
483 #endif
484             /* Try to copy from the shadow buffer */
485         if (!BitBlt(hdcUpdate,
486                         ps.rcPaint.left, ps.rcPaint.top,
487                         ps.rcPaint.right - ps.rcPaint.left,
488                         ps.rcPaint.bottom - ps.rcPaint.top,
489                         s_pScreenPriv->hdcShadow,
490                         ps.rcPaint.left + pWin->drawable.x,
491                         ps.rcPaint.top + pWin->drawable.y, SRCCOPY)) {
492             LPVOID lpMsgBuf;
493
494             /* Display a fancy error message */
495             FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
496                           FORMAT_MESSAGE_FROM_SYSTEM |
497                           FORMAT_MESSAGE_IGNORE_INSERTS,
498                           NULL,
499                           GetLastError(),
500                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
501                           (LPTSTR) & lpMsgBuf, 0, NULL);
502
503             ErrorF("winTopLevelWindowProc - BitBlt failed: %s\n",
504                    (LPSTR) lpMsgBuf);
505             LocalFree(lpMsgBuf);
506         }
507
508         /* EndPaint frees the DC */
509         EndPaint(hwnd, &ps);
510         return 0;
511
512     case WM_MOUSEMOVE:
513         /* Unpack the client area mouse coordinates */
514         ptMouse.x = GET_X_LPARAM(lParam);
515         ptMouse.y = GET_Y_LPARAM(lParam);
516
517         /* Translate the client area mouse coordinates to screen coordinates */
518         ClientToScreen(hwnd, &ptMouse);
519
520         /* Screen Coords from (-X, -Y) -> Root Window (0, 0) */
521         ptMouse.x -= GetSystemMetrics(SM_XVIRTUALSCREEN);
522         ptMouse.y -= GetSystemMetrics(SM_YVIRTUALSCREEN);
523
524         /* We can't do anything without privates */
525         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
526             break;
527
528         /* Has the mouse pointer crossed screens? */
529         if (s_pScreen != miPointerGetScreen(g_pwinPointer))
530             miPointerSetScreen(g_pwinPointer, s_pScreenInfo->dwScreen,
531                                ptMouse.x - s_pScreenInfo->dwXOffset,
532                                ptMouse.y - s_pScreenInfo->dwYOffset);
533
534         /* Are we tracking yet? */
535         if (!s_fTracking) {
536             TRACKMOUSEEVENT tme;
537
538             /* Setup data structure */
539             ZeroMemory(&tme, sizeof(tme));
540             tme.cbSize = sizeof(tme);
541             tme.dwFlags = TME_LEAVE;
542             tme.hwndTrack = hwnd;
543
544             /* Call the tracking function */
545             if (!TrackMouseEvent(&tme))
546                 ErrorF("winTopLevelWindowProc - TrackMouseEvent failed\n");
547
548             /* Flag that we are tracking now */
549             s_fTracking = TRUE;
550         }
551
552         /* Hide or show the Windows mouse cursor */
553         if (g_fSoftwareCursor && g_fCursor) {
554             /* Hide Windows cursor */
555             g_fCursor = FALSE;
556             ShowCursor(FALSE);
557         }
558
559         /* Kill the timer used to poll mouse events */
560         if (g_uipMousePollingTimerID != 0) {
561             KillTimer(s_pScreenPriv->hwndScreen, WIN_POLLING_MOUSE_TIMER_ID);
562             g_uipMousePollingTimerID = 0;
563         }
564
565         /* Deliver absolute cursor position to X Server */
566         winEnqueueMotion(ptMouse.x - s_pScreenInfo->dwXOffset,
567                          ptMouse.y - s_pScreenInfo->dwYOffset);
568
569         return 0;
570
571     case WM_NCMOUSEMOVE:
572         /*
573          * We break instead of returning 0 since we need to call
574          * DefWindowProc to get the mouse cursor changes
575          * and min/max/close button highlighting in Windows XP.
576          * The Platform SDK says that you should return 0 if you
577          * process this message, but it fails to mention that you
578          * will give up any default functionality if you do return 0.
579          */
580
581         /* We can't do anything without privates */
582         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
583             break;
584
585         /* Non-client mouse movement, show Windows cursor */
586         if (g_fSoftwareCursor && !g_fCursor) {
587             g_fCursor = TRUE;
588             ShowCursor(TRUE);
589         }
590
591         winStartMousePolling(s_pScreenPriv);
592
593         break;
594
595     case WM_MOUSELEAVE:
596         /* Mouse has left our client area */
597
598         /* Flag that we are no longer tracking */
599         s_fTracking = FALSE;
600
601         /* Show the mouse cursor, if necessary */
602         if (g_fSoftwareCursor && !g_fCursor) {
603             g_fCursor = TRUE;
604             ShowCursor(TRUE);
605         }
606
607         winStartMousePolling(s_pScreenPriv);
608
609         return 0;
610
611     case WM_LBUTTONDBLCLK:
612     case WM_LBUTTONDOWN:
613         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
614             break;
615         g_fButton[0] = TRUE;
616         SetCapture(hwnd);
617         return winMouseButtonsHandle(s_pScreen, ButtonPress, Button1, wParam);
618
619     case WM_LBUTTONUP:
620         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
621             break;
622         g_fButton[0] = FALSE;
623         ReleaseCapture();
624         winStartMousePolling(s_pScreenPriv);
625         return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button1, wParam);
626
627     case WM_MBUTTONDBLCLK:
628     case WM_MBUTTONDOWN:
629         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
630             break;
631         g_fButton[1] = TRUE;
632         SetCapture(hwnd);
633         return winMouseButtonsHandle(s_pScreen, ButtonPress, Button2, wParam);
634
635     case WM_MBUTTONUP:
636         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
637             break;
638         g_fButton[1] = FALSE;
639         ReleaseCapture();
640         winStartMousePolling(s_pScreenPriv);
641         return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button2, wParam);
642
643     case WM_RBUTTONDBLCLK:
644     case WM_RBUTTONDOWN:
645         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
646             break;
647         g_fButton[2] = TRUE;
648         SetCapture(hwnd);
649         return winMouseButtonsHandle(s_pScreen, ButtonPress, Button3, wParam);
650
651     case WM_RBUTTONUP:
652         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
653             break;
654         g_fButton[2] = FALSE;
655         ReleaseCapture();
656         winStartMousePolling(s_pScreenPriv);
657         return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button3, wParam);
658
659     case WM_XBUTTONDBLCLK:
660     case WM_XBUTTONDOWN:
661         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
662             break;
663         SetCapture(hwnd);
664         return winMouseButtonsHandle(s_pScreen, ButtonPress, HIWORD(wParam) + 5,
665                                      wParam);
666
667     case WM_XBUTTONUP:
668         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
669             break;
670         ReleaseCapture();
671         winStartMousePolling(s_pScreenPriv);
672         return winMouseButtonsHandle(s_pScreen, ButtonRelease,
673                                      HIWORD(wParam) + 5, wParam);
674
675     case WM_MOUSEWHEEL:
676         if (SendMessage
677             (hwnd, WM_NCHITTEST, 0,
678              MAKELONG(GET_X_LPARAM(lParam),
679                       GET_Y_LPARAM(lParam))) == HTCLIENT) {
680             /* Pass the message to the root window */
681             SendMessage(hwndScreen, message, wParam, lParam);
682             return 0;
683         }
684         else
685             break;
686
687     case WM_SETFOCUS:
688         if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
689             break;
690
691         {
692             /* Get the parent window for transient handling */
693             HWND hParent = GetParent(hwnd);
694
695             if (hParent && IsIconic(hParent))
696                 ShowWindow(hParent, SW_RESTORE);
697         }
698
699         winRestoreModeKeyStates();
700
701         /* Add the keyboard hook if possible */
702         if (g_fKeyboardHookLL)
703             g_fKeyboardHookLL = winInstallKeyboardHookLL();
704         return 0;
705
706     case WM_KILLFOCUS:
707         /* Pop any pressed keys since we are losing keyboard focus */
708         winKeybdReleaseKeys();
709
710         /* Remove our keyboard hook if it is installed */
711         winRemoveKeyboardHookLL();
712
713         /* Revert the X focus as well, but only if the Windows focus is going to another window */
714         if (!wParam && pWin)
715             DeleteWindowFromAnyEvents(pWin, FALSE);
716
717         return 0;
718
719     case WM_SYSDEADCHAR:
720     case WM_DEADCHAR:
721         /*
722          * NOTE: We do nothing with WM_*CHAR messages,
723          * nor does the root window, so we can just toss these messages.
724          */
725         return 0;
726
727     case WM_SYSKEYDOWN:
728     case WM_KEYDOWN:
729
730         /*
731          * Don't pass Alt-F4 key combo to root window,
732          * let Windows translate to WM_CLOSE and close this top-level window.
733          *
734          * NOTE: We purposely don't check the fUseWinKillKey setting because
735          * it should only apply to the key handling for the root window,
736          * not for top-level window-manager windows.
737          *
738          * ALSO NOTE: We do pass Ctrl-Alt-Backspace to the root window
739          * because that is a key combo that no X app should be expecting to
740          * receive, since it has historically been used to shutdown the X server.
741          * Passing Ctrl-Alt-Backspace to the root window preserves that
742          * behavior, assuming that -unixkill has been passed as a parameter.
743          */
744         if (wParam == VK_F4 && (GetKeyState(VK_MENU) & 0x8000))
745             break;
746
747 #if CYGWINDOWING_DEBUG
748         if (wParam == VK_ESCAPE) {
749             /* Place for debug: put any tests and dumps here */
750             WINDOWPLACEMENT windPlace;
751             RECT rc;
752             LPRECT pRect;
753
754             windPlace.length = sizeof(WINDOWPLACEMENT);
755             GetWindowPlacement(hwnd, &windPlace);
756             pRect = &windPlace.rcNormalPosition;
757             ErrorF("\nCYGWINDOWING Dump:\n"
758                    "\tdrawable: (%hd, %hd) - %hdx%hd\n", pDraw->x,
759                    pDraw->y, pDraw->width, pDraw->height);
760             ErrorF("\twindPlace: (%ld, %ld) - %ldx%ld\n", pRect->left,
761                    pRect->top, pRect->right - pRect->left,
762                    pRect->bottom - pRect->top);
763             if (GetClientRect(hwnd, &rc)) {
764                 pRect = &rc;
765                 ErrorF("\tClientRect: (%ld, %ld) - %ldx%ld\n", pRect->left,
766                        pRect->top, pRect->right - pRect->left,
767                        pRect->bottom - pRect->top);
768             }
769             if (GetWindowRect(hwnd, &rc)) {
770                 pRect = &rc;
771                 ErrorF("\tWindowRect: (%ld, %ld) - %ldx%ld\n", pRect->left,
772                        pRect->top, pRect->right - pRect->left,
773                        pRect->bottom - pRect->top);
774             }
775             ErrorF("\n");
776         }
777 #endif
778
779         /* Pass the message to the root window */
780         return winWindowProc(hwndScreen, message, wParam, lParam);
781
782     case WM_SYSKEYUP:
783     case WM_KEYUP:
784
785         /* Pass the message to the root window */
786         return winWindowProc(hwndScreen, message, wParam, lParam);
787
788     case WM_HOTKEY:
789
790         /* Pass the message to the root window */
791         SendMessage(hwndScreen, message, wParam, lParam);
792         return 0;
793
794     case WM_ACTIVATE:
795
796         /* Pass the message to the root window */
797         SendMessage(hwndScreen, message, wParam, lParam);
798
799         if (LOWORD(wParam) != WA_INACTIVE) {
800             /* Raise the window to the top in Z order */
801             /* ago: Activate does not mean putting it to front! */
802             /*
803                wmMsg.msg = WM_WM_RAISE;
804                if (fWMMsgInitialized)
805                winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
806              */
807
808             /* Tell our Window Manager thread to activate the window */
809             wmMsg.msg = WM_WM_ACTIVATE;
810             if (fWMMsgInitialized)
811                 if (!pWin || !pWin->overrideRedirect)   /* for OOo menus */
812                     winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
813         }
814         /* Prevent the mouse wheel from stalling when another window is minimized */
815         if (HIWORD(wParam) == 0 && LOWORD(wParam) == WA_ACTIVE &&
816             (HWND) lParam != NULL && (HWND) lParam != (HWND) GetParent(hwnd))
817             SetFocus(hwnd);
818         return 0;
819
820     case WM_ACTIVATEAPP:
821         /*
822          * This message is also sent to the root window
823          * so we do nothing for individual multiwindow windows
824          */
825         break;
826
827     case WM_CLOSE:
828         /* Branch on if the window was killed in X already */
829         if (pWinPriv->fXKilled) {
830             /* Window was killed, go ahead and destroy the window */
831             DestroyWindow(hwnd);
832         }
833         else {
834             /* Tell our Window Manager thread to kill the window */
835             wmMsg.msg = WM_WM_KILL;
836             if (fWMMsgInitialized)
837                 winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
838         }
839         return 0;
840
841     case WM_DESTROY:
842
843         /* Branch on if the window was killed in X already */
844         if (pWinPriv && !pWinPriv->fXKilled) {
845             ErrorF("winTopLevelWindowProc - WM_DESTROY - WM_WM_KILL\n");
846
847             /* Tell our Window Manager thread to kill the window */
848             wmMsg.msg = WM_WM_KILL;
849             if (fWMMsgInitialized)
850                 winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
851         }
852
853         RemoveProp(hwnd, WIN_WINDOW_PROP);
854         RemoveProp(hwnd, WIN_WID_PROP);
855         RemoveProp(hwnd, WIN_NEEDMANAGE_PROP);
856
857         break;
858
859     case WM_MOVE:
860         /* Adjust the X Window to the moved Windows window */
861         winAdjustXWindow(pWin, hwnd);
862         return 0;
863
864     case WM_SHOWWINDOW:
865         /* Bail out if the window is being hidden */
866         if (!wParam)
867             return 0;
868
869         /* */
870         if (!pWin->overrideRedirect) {
871             /* Flag that this window needs to be made active when clicked */
872             SetProp(hwnd, WIN_NEEDMANAGE_PROP, (HANDLE) 1);
873
874             if (!(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_APPWINDOW)) {
875                 HWND zstyle = HWND_NOTOPMOST;
876
877                 /* Set the window extended style flags */
878                 SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
879
880                 /* Set the transient style flags */
881                 if (GetParent(hwnd))
882                     SetWindowLongPtr(hwnd, GWL_STYLE,
883                                      WS_POPUP | WS_OVERLAPPED | WS_SYSMENU |
884                                      WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
885                 /* Set the window standard style flags */
886                 else
887                     SetWindowLongPtr(hwnd, GWL_STYLE,
888                                      (WS_POPUP | WS_OVERLAPPEDWINDOW |
889                                       WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
890                                      & ~WS_CAPTION & ~WS_SIZEBOX);
891
892                 winUpdateWindowPosition(hwnd, FALSE, &zstyle);
893
894                 {
895                     WinXWMHints hints;
896
897                     if (winMultiWindowGetWMHints(pWin, &hints)) {
898                         /*
899                            Give the window focus, unless it has an InputHint
900                            which is FALSE (this is used by e.g. glean to
901                            avoid every test window grabbing the focus)
902                          */
903                         if (!((hints.flags & InputHint) && (!hints.input))) {
904                             SetForegroundWindow(hwnd);
905                         }
906                     }
907                 }
908             }
909             wmMsg.msg = WM_WM_MAP3;
910         }
911         else {                  /* It is an overridden window so make it top of Z stack */
912
913             HWND forHwnd = GetForegroundWindow();
914
915 #if CYGWINDOWING_DEBUG
916             ErrorF("overridden window is shown\n");
917 #endif
918             if (forHwnd != NULL) {
919                 if (GetWindowLongPtr(forHwnd, GWLP_USERDATA) & (LONG_PTR)
920                     XMING_SIGNATURE) {
921                     if (GetWindowLongPtr(forHwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
922                         SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
923                                      SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
924                     else
925                         SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
926                                      SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
927                 }
928             }
929             wmMsg.msg = WM_WM_MAP2;
930         }
931
932         /* Tell our Window Manager thread to map the window */
933         if (fWMMsgInitialized)
934             winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
935
936         winStartMousePolling(s_pScreenPriv);
937
938         return 0;
939
940     case WM_SIZING:
941         /* Need to legalize the size according to WM_NORMAL_HINTS */
942         /* for applications like xterm */
943         return ValidateSizing(hwnd, pWin, wParam, lParam);
944
945     case WM_WINDOWPOSCHANGED:
946     {
947         LPWINDOWPOS pWinPos = (LPWINDOWPOS) lParam;
948
949         if (!(pWinPos->flags & SWP_NOZORDER)) {
950 #if CYGWINDOWING_DEBUG
951             winDebug("\twindow z order was changed\n");
952 #endif
953             if (pWinPos->hwndInsertAfter == HWND_TOP
954                 || pWinPos->hwndInsertAfter == HWND_TOPMOST
955                 || pWinPos->hwndInsertAfter == HWND_NOTOPMOST) {
956 #if CYGWINDOWING_DEBUG
957                 winDebug("\traise to top\n");
958 #endif
959                 /* Raise the window to the top in Z order */
960                 winRaiseWindow(pWin);
961             }
962             else if (pWinPos->hwndInsertAfter == HWND_BOTTOM) {
963             }
964             else {
965                 /* Check if this window is top of X windows. */
966                 HWND hWndAbove = NULL;
967                 DWORD dwCurrentProcessID = GetCurrentProcessId();
968                 DWORD dwWindowProcessID = 0;
969
970                 for (hWndAbove = pWinPos->hwndInsertAfter;
971                      hWndAbove != NULL;
972                      hWndAbove = GetNextWindow(hWndAbove, GW_HWNDPREV)) {
973                     /* Ignore other XWin process's window */
974                     GetWindowThreadProcessId(hWndAbove, &dwWindowProcessID);
975
976                     if ((dwWindowProcessID == dwCurrentProcessID)
977                         && GetProp(hWndAbove, WIN_WINDOW_PROP)
978                         && !IsWindowVisible(hWndAbove)
979                         && !IsIconic(hWndAbove))        /* ignore minimized windows */
980                         break;
981                 }
982                 /* If this is top of X windows in Windows stack,
983                    raise it in X stack. */
984                 if (hWndAbove == NULL) {
985 #if CYGWINDOWING_DEBUG
986                     winDebug("\traise to top\n");
987 #endif
988                     winRaiseWindow(pWin);
989                 }
990             }
991         }
992     }
993         /*
994          * Pass the message to DefWindowProc to let the function
995          * break down WM_WINDOWPOSCHANGED to WM_MOVE and WM_SIZE.
996          */
997         break;
998
999     case WM_SIZE:
1000         /* see dix/window.c */
1001 #if CYGWINDOWING_DEBUG
1002     {
1003         char buf[64];
1004
1005         switch (wParam) {
1006         case SIZE_MINIMIZED:
1007             strcpy(buf, "SIZE_MINIMIZED");
1008             break;
1009         case SIZE_MAXIMIZED:
1010             strcpy(buf, "SIZE_MAXIMIZED");
1011             break;
1012         case SIZE_RESTORED:
1013             strcpy(buf, "SIZE_RESTORED");
1014             break;
1015         default:
1016             strcpy(buf, "UNKNOWN_FLAG");
1017         }
1018         ErrorF("winTopLevelWindowProc - WM_SIZE to %dx%d (%s) - %d ms\n",
1019                (int) LOWORD(lParam), (int) HIWORD(lParam), buf,
1020                (int) (GetTickCount()));
1021     }
1022 #endif
1023         /* Adjust the X Window to the moved Windows window */
1024         winAdjustXWindow(pWin, hwnd);
1025         return 0;               /* end of WM_SIZE handler */
1026
1027     case WM_STYLECHANGING:
1028         /*
1029            When the style changes, adjust the Windows window size so the client area remains the same size,
1030            and adjust the Windows window position so that the client area remains in the same place.
1031          */
1032     {
1033         RECT newWinRect;
1034         DWORD dwExStyle;
1035         DWORD dwStyle;
1036         DWORD newStyle = ((STYLESTRUCT *) lParam)->styleNew;
1037         WINDOWINFO wi;
1038
1039         dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
1040         dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
1041
1042         winDebug("winTopLevelWindowProc - WM_STYLECHANGING from %08x %08x\n",
1043                  dwStyle, dwExStyle);
1044
1045         if (wParam == GWL_EXSTYLE)
1046             dwExStyle = newStyle;
1047
1048         if (wParam == GWL_STYLE)
1049             dwStyle = newStyle;
1050
1051         winDebug("winTopLevelWindowProc - WM_STYLECHANGING to %08x %08x\n",
1052                  dwStyle, dwExStyle);
1053
1054         /* Get client rect in screen coordinates */
1055         wi.cbSize = sizeof(WINDOWINFO);
1056         GetWindowInfo(hwnd, &wi);
1057
1058         winDebug
1059             ("winTopLevelWindowProc - WM_STYLECHANGING client area {%d, %d, %d, %d}, {%d x %d}\n",
1060              wi.rcClient.left, wi.rcClient.top, wi.rcClient.right,
1061              wi.rcClient.bottom, wi.rcClient.right - wi.rcClient.left,
1062              wi.rcClient.bottom - wi.rcClient.top);
1063
1064         newWinRect = wi.rcClient;
1065         if (!AdjustWindowRectEx(&newWinRect, dwStyle, FALSE, dwExStyle))
1066             winDebug
1067                 ("winTopLevelWindowProc - WM_STYLECHANGING AdjustWindowRectEx failed\n");
1068
1069         winDebug
1070             ("winTopLevelWindowProc - WM_STYLECHANGING window area should be {%d, %d, %d, %d}, {%d x %d}\n",
1071              newWinRect.left, newWinRect.top, newWinRect.right,
1072              newWinRect.bottom, newWinRect.right - newWinRect.left,
1073              newWinRect.bottom - newWinRect.top);
1074
1075         /*
1076            Style change hasn't happened yet, so we can't adjust the window size yet, as the winAdjustXWindow()
1077            which WM_SIZE does will use the current (unchanged) style.  Instead make a note to change it when
1078            WM_STYLECHANGED is received...
1079          */
1080         pWinPriv->hDwp = BeginDeferWindowPos(1);
1081         pWinPriv->hDwp =
1082             DeferWindowPos(pWinPriv->hDwp, hwnd, NULL, newWinRect.left,
1083                            newWinRect.top, newWinRect.right - newWinRect.left,
1084                            newWinRect.bottom - newWinRect.top,
1085                            SWP_NOACTIVATE | SWP_NOZORDER);
1086     }
1087         return 0;
1088
1089     case WM_STYLECHANGED:
1090     {
1091         if (pWinPriv->hDwp) {
1092             EndDeferWindowPos(pWinPriv->hDwp);
1093             pWinPriv->hDwp = NULL;
1094         }
1095         winDebug("winTopLevelWindowProc - WM_STYLECHANGED done\n");
1096     }
1097         return 0;
1098
1099     case WM_MOUSEACTIVATE:
1100
1101         /* Check if this window needs to be made active when clicked */
1102         if (!GetProp(pWinPriv->hWnd, WIN_NEEDMANAGE_PROP)) {
1103 #if CYGMULTIWINDOW_DEBUG
1104             ErrorF("winTopLevelWindowProc - WM_MOUSEACTIVATE - "
1105                    "MA_NOACTIVATE\n");
1106 #endif
1107
1108             /* */
1109             return MA_NOACTIVATE;
1110         }
1111         break;
1112
1113     case WM_SETCURSOR:
1114         if (LOWORD(lParam) == HTCLIENT) {
1115             if (!g_fSoftwareCursor)
1116                 SetCursor(s_pScreenPriv->cursor.handle);
1117             return TRUE;
1118         }
1119         break;
1120
1121     default:
1122         break;
1123     }
1124
1125     ret = DefWindowProc(hwnd, message, wParam, lParam);
1126     /*
1127      * If the window was minized we get the stack change before the window is restored
1128      * and so it gets lost. Ensure there stacking order is correct.
1129      */
1130     if (needRestack)
1131         winReorderWindowsMultiWindow();
1132     return ret;
1133 }