1 /*
2  *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3  *
4  *Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  *"Software"), to deal in the Software without restriction, including
7  *without limitation the rights to use, copy, modify, merge, publish,
8  *distribute, sublicense, and/or sell copies of the Software, and to
9  *permit persons to whom the Software is furnished to do so, subject to
10  *the following conditions:
11  *
12  *The above copyright notice and this permission notice shall be
13  *included in all copies or substantial portions of the Software.
14  *
15  *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
19  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  *Except as contained in this notice, the name of the XFree86 Project
24  *shall not be used in advertising or otherwise to promote the sale, use
25  *or other dealings in this Software without prior written authorization
26  *from the XFree86 Project.
27  *
28  * Authors:	Kensuke Matsuzaki
29  *		Earle F. Philhower, III
30  *		Harold L Hunt II
31  */
32 #ifdef HAVE_XWIN_CONFIG_H
33 #include <xwin-config.h>
34 #endif
35 #include "win.h"
36 #include <winuser.h>
37 #define _WINDOWSWM_SERVER_
38 #include <X11/extensions/windowswmstr.h>
39 #include "dixevents.h"
40 #include "propertyst.h"
41 #include <X11/Xatom.h>
42 #include "winmultiwindowclass.h"
43 #include "winmsg.h"
44 #include "inputstr.h"
45 
46 /*
47  * Constant defines
48  */
49 
50 #define MOUSE_ACTIVATE_DEFAULT		TRUE
51 #define RAISE_ON_CLICK_DEFAULT		FALSE
52 
53 /*
54  * Local globals
55  */
56 
57 static UINT_PTR g_uipMousePollingTimerID = 0;
58 
59 /*
60  * Local function
61  */
62 
DEFINE_ATOM_HELPER(AtmWindowsWMMouseActivate,WINDOWSWM_MOUSE_ACTIVATE)63 DEFINE_ATOM_HELPER(AtmWindowsWMMouseActivate, WINDOWSWM_MOUSE_ACTIVATE)
64 /* DEFINE_ATOM_HELPER(AtmWindowsWMClientWindow, WINDOWSWM_CLIENT_WINDOW) */
65 
66 /*
67  * ConstrainSize - Taken from TWM sources - Respects hints for sizing
68  */
69 #define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
70 static void
71 ConstrainSize(WinXSizeHints hints, int *widthp, int *heightp)
72 {
73     int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
74     int baseWidth, baseHeight;
75     int dwidth = *widthp, dheight = *heightp;
76 
77     if (hints.flags & PMinSize) {
78         minWidth = hints.min_width;
79         minHeight = hints.min_height;
80     }
81     else if (hints.flags & PBaseSize) {
82         minWidth = hints.base_width;
83         minHeight = hints.base_height;
84     }
85     else
86         minWidth = minHeight = 1;
87 
88     if (hints.flags & PBaseSize) {
89         baseWidth = hints.base_width;
90         baseHeight = hints.base_height;
91     }
92     else if (hints.flags & PMinSize) {
93         baseWidth = hints.min_width;
94         baseHeight = hints.min_height;
95     }
96     else
97         baseWidth = baseHeight = 0;
98 
99     if (hints.flags & PMaxSize) {
100         maxWidth = hints.max_width;
101         maxHeight = hints.max_height;
102     }
103     else {
104         maxWidth = MAXINT;
105         maxHeight = MAXINT;
106     }
107 
108     if (hints.flags & PResizeInc) {
109         xinc = hints.width_inc;
110         yinc = hints.height_inc;
111     }
112     else
113         xinc = yinc = 1;
114 
115     /*
116      * First, clamp to min and max values
117      */
118     if (dwidth < minWidth)
119         dwidth = minWidth;
120     if (dheight < minHeight)
121         dheight = minHeight;
122 
123     if (dwidth > maxWidth)
124         dwidth = maxWidth;
125     if (dheight > maxHeight)
126         dheight = maxHeight;
127 
128     /*
129      * Second, fit to base + N * inc
130      */
131     dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
132     dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
133 
134     /*
135      * Third, adjust for aspect ratio
136      */
137 
138     /*
139      * The math looks like this:
140      *
141      * minAspectX    dwidth     maxAspectX
142      * ---------- <= ------- <= ----------
143      * minAspectY    dheight    maxAspectY
144      *
145      * If that is multiplied out, then the width and height are
146      * invalid in the following situations:
147      *
148      * minAspectX * dheight > minAspectY * dwidth
149      * maxAspectX * dheight < maxAspectY * dwidth
150      *
151      */
152 
153     if (hints.flags & PAspect) {
154         if (hints.min_aspect.x * dheight > hints.min_aspect.y * dwidth) {
155             delta =
156                 makemult(hints.min_aspect.x * dheight / hints.min_aspect.y -
157                          dwidth, xinc);
158             if (dwidth + delta <= maxWidth)
159                 dwidth += delta;
160             else {
161                 delta =
162                     makemult(dheight -
163                              dwidth * hints.min_aspect.y / hints.min_aspect.x,
164                              yinc);
165                 if (dheight - delta >= minHeight)
166                     dheight -= delta;
167             }
168         }
169 
170         if (hints.max_aspect.x * dheight < hints.max_aspect.y * dwidth) {
171             delta =
172                 makemult(dwidth * hints.max_aspect.y / hints.max_aspect.x -
173                          dheight, yinc);
174             if (dheight + delta <= maxHeight)
175                 dheight += delta;
176             else {
177                 delta =
178                     makemult(dwidth -
179                              hints.max_aspect.x * dheight / hints.max_aspect.y,
180                              xinc);
181                 if (dwidth - delta >= minWidth)
182                     dwidth -= delta;
183             }
184         }
185     }
186 
187     /* Return computed values */
188     *widthp = dwidth;
189     *heightp = dheight;
190 }
191 
192 #undef makemult
193 
194 /*
195  * ValidateSizing - Ensures size request respects hints
196  */
197 static int
ValidateSizing(HWND hwnd,WindowPtr pWin,WPARAM wParam,LPARAM lParam)198 ValidateSizing(HWND hwnd, WindowPtr pWin, WPARAM wParam, LPARAM lParam)
199 {
200     WinXSizeHints sizeHints;
201     RECT *rect;
202     int iWidth, iHeight, iTopBorder;
203     POINT pt;
204 
205     /* Invalid input checking */
206     if (pWin == NULL || lParam == 0) {
207         ErrorF("Invalid input checking\n");
208         return FALSE;
209     }
210 
211     /* No size hints, no checking */
212     if (!winMultiWindowGetWMNormalHints(pWin, &sizeHints)) {
213         ErrorF("No size hints, no checking\n");
214         return FALSE;
215     }
216 
217     /* Avoid divide-by-zero */
218     if (sizeHints.flags & PResizeInc) {
219         if (sizeHints.width_inc == 0)
220             sizeHints.width_inc = 1;
221         if (sizeHints.height_inc == 0)
222             sizeHints.height_inc = 1;
223     }
224 
225     rect = (RECT *) lParam;
226 
227     iWidth = rect->right - rect->left;
228     iHeight = rect->bottom - rect->top;
229 
230     /* Get title bar height, there must be an easier way?! */
231     pt.x = pt.y = 0;
232     ClientToScreen(hwnd, &pt);
233     iTopBorder = pt.y - rect->top;
234 
235     /* Now remove size of any borders */
236     iWidth -= 2 * GetSystemMetrics(SM_CXSIZEFRAME);
237     iHeight -= GetSystemMetrics(SM_CYSIZEFRAME) + iTopBorder;
238 
239     /* Constrain the size to legal values */
240     ConstrainSize(sizeHints, &iWidth, &iHeight);
241 
242     /* Add back the borders */
243     iWidth += 2 * GetSystemMetrics(SM_CXSIZEFRAME);
244     iHeight += GetSystemMetrics(SM_CYSIZEFRAME) + iTopBorder;
245 
246     /* Adjust size according to where we're dragging from */
247     switch (wParam) {
248     case WMSZ_TOP:
249     case WMSZ_TOPRIGHT:
250     case WMSZ_BOTTOM:
251     case WMSZ_BOTTOMRIGHT:
252     case WMSZ_RIGHT:
253         rect->right = rect->left + iWidth;
254         break;
255     default:
256         rect->left = rect->right - iWidth;
257         break;
258     }
259     switch (wParam) {
260     case WMSZ_BOTTOM:
261     case WMSZ_BOTTOMRIGHT:
262     case WMSZ_BOTTOMLEFT:
263     case WMSZ_RIGHT:
264     case WMSZ_LEFT:
265         rect->bottom = rect->top + iHeight;
266         break;
267     default:
268         rect->top = rect->bottom - iHeight;
269         break;
270     }
271     return TRUE;
272 }
273 
274 /*
275  * IsMouseActive
276  */
277 
278 static Bool
IsMouseActive(WindowPtr pWin)279 IsMouseActive(WindowPtr pWin)
280 {
281 
282     struct _Window *pwin;
283     struct _Property *prop;
284 
285     /* XXX We're getting inputInfo.poniter here, but this might be really wrong.
286      * Which pointer's current window do we want? */
287     WindowPtr pRoot = GetCurrentRootWindow(inputInfo.pointer);
288 
289     if (!pWin) {
290         ErrorF("IsMouseActive - pWin was NULL use default value:%d\n",
291                MOUSE_ACTIVATE_DEFAULT);
292         return MOUSE_ACTIVATE_DEFAULT;
293     }
294 
295     pwin = (struct _Window *) pWin;
296 
297     if (pwin->optional)
298         prop = (struct _Property *) pwin->optional->userProps;
299     else
300         prop = NULL;
301 
302     while (prop) {
303         if (prop->propertyName == AtmWindowsWMMouseActivate()
304             && prop->type == XA_INTEGER && prop->format == 32) {
305             return *(int *) prop->data;
306         }
307         else
308             prop = prop->next;
309     }
310 
311     if (pWin != pRoot) {
312         return IsMouseActive(pRoot);
313     }
314     else {
315 #if CYGMULTIWINDOW_DEBUG
316         winDebug("IsMouseActive - no prop use default value:%d\n",
317                  MOUSE_ACTIVATE_DEFAULT);
318 #endif
319         return MOUSE_ACTIVATE_DEFAULT;
320     }
321 }
322 
323 /*
324  * winMWExtWMWindowProc - Window procedure
325  */
326 
327 LRESULT CALLBACK
winMWExtWMWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)328 winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
329 {
330     WindowPtr pWin = NULL;
331     win32RootlessWindowPtr pRLWinPriv = NULL;
332     ScreenPtr pScreen = NULL;
333     winPrivScreenPtr pScreenPriv = NULL;
334     winScreenInfo *pScreenInfo = NULL;
335     HWND hwndScreen = NULL;
336     POINT ptMouse;
337     static Bool s_fTracking = FALSE;
338     HDC hdcUpdate;
339     PAINTSTRUCT ps;
340     LPWINDOWPOS pWinPos = NULL;
341     RECT rcClient;
342 
343     /* Check if the Windows window property for our X window pointer is valid */
344     if ((pRLWinPriv =
345          (win32RootlessWindowPtr) GetProp(hwnd, WIN_WINDOW_PROP)) != NULL) {
346         pWin = pRLWinPriv->pFrame->win;
347         pScreen = pWin->drawable.pScreen;
348         if (pScreen)
349             pScreenPriv = winGetScreenPriv(pScreen);
350         if (pScreenPriv)
351             pScreenInfo = pScreenPriv->pScreenInfo;
352         if (pScreenPriv)
353             hwndScreen = pScreenPriv->hwndScreen;
354 
355 #if CYGDEBUG
356         winDebugWin32Message("winMWExtWMWindowProc", hwnd, message, wParam,
357                              lParam);
358 
359         winDebug("\thWnd %p\n", hwnd);
360         winDebug("\tpScreenPriv %p\n", pScreenPriv);
361         winDebug("\tpScreenInfo %p\n", pScreenInfo);
362         winDebug("\thwndScreen %p\n", hwndScreen);
363         winDebug("winMWExtWMWindowProc (%p) %08x %08x %08x\n",
364                  pRLWinPriv, message, (int)wParam, (int)lParam);
365 #endif
366     }
367     /* Branch on message type */
368     switch (message) {
369     case WM_CREATE:
370 #if CYGMULTIWINDOW_DEBUG
371         winDebug("winMWExtWMWindowProc - WM_CREATE\n");
372 #endif
373         /* */
374         SetProp(hwnd,
375                 WIN_WINDOW_PROP,
376                 (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams);
377         return 0;
378 
379     case WM_CLOSE:
380 #if CYGMULTIWINDOW_DEBUG
381         winDebug("winMWExtWMWindowProc - WM_CLOSE %d\n", pRLWinPriv->fClose);
382 #endif
383         /* Tell window-manager to close window */
384         if (pRLWinPriv->fClose) {
385             DestroyWindow(hwnd);
386         }
387         else {
388             winWindowsWMSendEvent(WindowsWMControllerNotify,
389                                   WindowsWMControllerNotifyMask,
390                                   1,
391                                   WindowsWMCloseWindow,
392                                   pWin->drawable.id, 0, 0, 0, 0);
393         }
394         return 0;
395 
396     case WM_DESTROY:
397 #if CYGMULTIWINDOW_DEBUG
398         winDebug("winMWExtWMWindowProc - WM_DESTROY\n");
399 #endif
400         /* Free the shaodw DC; which allows the bitmap to be freed */
401         DeleteDC(pRLWinPriv->hdcShadow);
402         pRLWinPriv->hdcShadow = NULL;
403 
404         /* Free the shadow bitmap */
405         DeleteObject(pRLWinPriv->hbmpShadow);
406         pRLWinPriv->hbmpShadow = NULL;
407 
408         /* Free the screen DC */
409         ReleaseDC(pRLWinPriv->hWnd, pRLWinPriv->hdcScreen);
410         pRLWinPriv->hdcScreen = NULL;
411 
412         /* Free shadow buffer info header */
413         free(pRLWinPriv->pbmihShadow);
414         pRLWinPriv->pbmihShadow = NULL;
415 
416         pRLWinPriv->fResized = FALSE;
417         pRLWinPriv->pfb = NULL;
418         free(pRLWinPriv);
419         RemoveProp(hwnd, WIN_WINDOW_PROP);
420         break;
421 
422     case WM_MOUSEMOVE:
423 #if CYGMULTIWINDOW_DEBUG && 0
424         winDebug("winMWExtWMWindowProc - WM_MOUSEMOVE\n");
425 #endif
426         /* Unpack the client area mouse coordinates */
427         ptMouse.x = GET_X_LPARAM(lParam);
428         ptMouse.y = GET_Y_LPARAM(lParam);
429 
430         /* Translate the client area mouse coordinates to screen coordinates */
431         ClientToScreen(hwnd, &ptMouse);
432 
433         /* Screen Coords from (-X, -Y) -> Root Window (0, 0) */
434         ptMouse.x -= GetSystemMetrics(SM_XVIRTUALSCREEN);
435         ptMouse.y -= GetSystemMetrics(SM_YVIRTUALSCREEN);
436 
437         /* We can't do anything without privates */
438         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
439             break;
440 
441         /* Has the mouse pointer crossed screens? */
442         if (pScreen != miPointerGetScreen(inputInfo.pointer))
443              miPointerSetScreen(inputInfo.pointer, pScreenInfo->dwScreen,
444                                 ptMouse.x - pScreenInfo->dwXOffset,
445                                 ptMouse.y - pScreenInfo->dwYOffset);
446 
447         /* Are we tracking yet? */
448         if (!s_fTracking) {
449             TRACKMOUSEEVENT tme;
450 
451             /* Setup data structure */
452             ZeroMemory(&tme, sizeof(tme));
453             tme.cbSize = sizeof(tme);
454             tme.dwFlags = TME_LEAVE;
455             tme.hwndTrack = hwnd;
456 
457             /* Call the tracking function */
458             if (!TrackMouseEvent(&tme))
459                 ErrorF("winMWExtWMWindowProc - TrackMouseEvent failed\n");
460 
461             /* Flag that we are tracking now */
462             s_fTracking = TRUE;
463         }
464 
465         /* Kill the timer used to poll mouse events */
466         if (g_uipMousePollingTimerID != 0) {
467             KillTimer(pScreenPriv->hwndScreen, WIN_POLLING_MOUSE_TIMER_ID);
468             g_uipMousePollingTimerID = 0;
469         }
470 
471         /* Deliver absolute cursor position to X Server */
472         winEnqueueMotion(ptMouse.x - pScreenInfo->dwXOffset,
473                          ptMouse.y - pScreenInfo->dwYOffset);
474 
475         return 0;
476 
477     case WM_NCMOUSEMOVE:
478 #if CYGMULTIWINDOW_DEBUG && 0
479         winDebug("winMWExtWMWindowProc - WM_NCMOUSEMOVE\n");
480 #endif
481         /*
482          * We break instead of returning 0 since we need to call
483          * DefWindowProc to get the mouse cursor changes
484          * and min/max/close button highlighting in Windows XP.
485          * The Platform SDK says that you should return 0 if you
486          * process this message, but it fails to mention that you
487          * will give up any default functionality if you do return 0.
488          */
489 
490         /* We can't do anything without privates */
491         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
492             break;
493 
494         /*
495          * Timer to poll mouse events.  This is needed to make
496          * programs like xeyes follow the mouse properly.
497          */
498         if (g_uipMousePollingTimerID == 0)
499             g_uipMousePollingTimerID = SetTimer(pScreenPriv->hwndScreen,
500                                                 WIN_POLLING_MOUSE_TIMER_ID,
501                                                 MOUSE_POLLING_INTERVAL, NULL);
502         break;
503 
504     case WM_MOUSELEAVE:
505 #if CYGMULTIWINDOW_DEBUG
506         winDebug("winMWExtWMWindowProc - WM_MOUSELEAVE\n");
507 #endif
508         /* Mouse has left our client area */
509 
510         /* Flag that we are no longer tracking */
511         s_fTracking = FALSE;
512 
513         /*
514          * Timer to poll mouse events.  This is needed to make
515          * programs like xeyes follow the mouse properly.
516          */
517         if (g_uipMousePollingTimerID == 0)
518             g_uipMousePollingTimerID = SetTimer(pScreenPriv->hwndScreen,
519                                                 WIN_POLLING_MOUSE_TIMER_ID,
520                                                 MOUSE_POLLING_INTERVAL, NULL);
521         return 0;
522 
523     case WM_LBUTTONDBLCLK:
524     case WM_LBUTTONDOWN:
525 #if CYGMULTIWINDOW_DEBUG
526         winDebug("winMWExtWMWindowProc - WM_LBUTTONDBLCLK\n");
527 #endif
528         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
529             break;
530         SetCapture(hwnd);
531         return winMouseButtonsHandle(pScreen, ButtonPress, Button1, wParam);
532 
533     case WM_LBUTTONUP:
534 #if CYGMULTIWINDOW_DEBUG
535         winDebug("winMWExtWMWindowProc - WM_LBUTTONUP\n");
536 #endif
537         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
538             break;
539         ReleaseCapture();
540         return winMouseButtonsHandle(pScreen, ButtonRelease, Button1, wParam);
541 
542     case WM_MBUTTONDBLCLK:
543     case WM_MBUTTONDOWN:
544 #if CYGMULTIWINDOW_DEBUG
545         winDebug("winMWExtWMWindowProc - WM_MBUTTONDBLCLK\n");
546 #endif
547         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
548             break;
549         SetCapture(hwnd);
550         return winMouseButtonsHandle(pScreen, ButtonPress, Button2, wParam);
551 
552     case WM_MBUTTONUP:
553 #if CYGMULTIWINDOW_DEBUG
554         winDebug("winMWExtWMWindowProc - WM_MBUTTONUP\n");
555 #endif
556         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
557             break;
558         ReleaseCapture();
559         return winMouseButtonsHandle(pScreen, ButtonRelease, Button2, wParam);
560 
561     case WM_RBUTTONDBLCLK:
562     case WM_RBUTTONDOWN:
563 #if CYGMULTIWINDOW_DEBUG
564         winDebug("winMWExtWMWindowProc - WM_RBUTTONDBLCLK\n");
565 #endif
566         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
567             break;
568         SetCapture(hwnd);
569         return winMouseButtonsHandle(pScreen, ButtonPress, Button3, wParam);
570 
571     case WM_RBUTTONUP:
572 #if CYGMULTIWINDOW_DEBUG
573         winDebug("winMWExtWMWindowProc - WM_RBUTTONUP\n");
574 #endif
575         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
576             break;
577         ReleaseCapture();
578         return winMouseButtonsHandle(pScreen, ButtonRelease, Button3, wParam);
579 
580     case WM_XBUTTONDBLCLK:
581     case WM_XBUTTONDOWN:
582         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
583             break;
584         SetCapture(hwnd);
585         return winMouseButtonsHandle(pScreen, ButtonPress, HIWORD(wParam) + 7,
586                                      wParam);
587     case WM_XBUTTONUP:
588         if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
589             break;
590         ReleaseCapture();
591         return winMouseButtonsHandle(pScreen, ButtonRelease, HIWORD(wParam) + 7,
592                                      wParam);
593 
594     case WM_MOUSEWHEEL:
595 #if CYGMULTIWINDOW_DEBUG
596         winDebug("winMWExtWMWindowProc - WM_MOUSEWHEEL\n");
597 #endif
598 
599         /* Pass the message to the root window */
600         SendMessage(hwndScreen, message, wParam, lParam);
601         return 0;
602 
603     case WM_MOUSEHWHEEL:
604 #if CYGMULTIWINDOW_DEBUG
605         winDebug("winMWExtWMWindowProc - WM_MOUSEHWHEEL\n");
606 #endif
607 
608         /* Pass the message to the root window */
609         SendMessage(hwndScreen, message, wParam, lParam);
610         return 0;
611 
612     case WM_MOUSEACTIVATE:
613 #if CYGMULTIWINDOW_DEBUG
614         winDebug("winMWExtWMWindowProc - WM_MOUSEACTIVATE\n");
615 #endif
616         if (!IsMouseActive(pWin))
617             return MA_NOACTIVATE;
618 
619         break;
620 
621     case WM_KILLFOCUS:
622         /* Pop any pressed keys since we are losing keyboard focus */
623         winKeybdReleaseKeys();
624         return 0;
625 
626     case WM_SYSDEADCHAR:
627     case WM_DEADCHAR:
628         /*
629          * NOTE: We do nothing with WM_*CHAR messages,
630          * nor does the root window, so we can just toss these messages.
631          */
632         return 0;
633 
634     case WM_SYSKEYDOWN:
635     case WM_KEYDOWN:
636 #if CYGMULTIWINDOW_DEBUG
637         winDebug("winMWExtWMWindowProc - WM_*KEYDOWN\n");
638 #endif
639 
640         /*
641          * Don't pass Alt-F4 key combo to root window,
642          * let Windows translate to WM_CLOSE and close this top-level window.
643          *
644          * NOTE: We purposely don't check the fUseWinKillKey setting because
645          * it should only apply to the key handling for the root window,
646          * not for top-level window-manager windows.
647          *
648          * ALSO NOTE: We do pass Ctrl-Alt-Backspace to the root window
649          * because that is a key combo that no X app should be expecting to
650          * receive, since it has historically been used to shutdown the X server.
651          * Passing Ctrl-Alt-Backspace to the root window preserves that
652          * behavior, assuming that -unixkill has been passed as a parameter.
653          */
654         if (wParam == VK_F4 && (GetKeyState(VK_MENU) & 0x8000))
655             break;
656 
657         /* Pass the message to the root window */
658         SendMessage(hwndScreen, message, wParam, lParam);
659         return 0;
660 
661     case WM_SYSKEYUP:
662     case WM_KEYUP:
663 
664 #if CYGMULTIWINDOW_DEBUG
665         winDebug("winMWExtWMWindowProc - WM_*KEYUP\n");
666 #endif
667 
668         /* Pass the message to the root window */
669         SendMessage(hwndScreen, message, wParam, lParam);
670         return 0;
671 
672     case WM_HOTKEY:
673 #if CYGMULTIWINDOW_DEBUG
674         winDebug("winMWExtWMWindowProc - WM_HOTKEY\n");
675 #endif
676 
677         /* Pass the message to the root window */
678         SendMessage(hwndScreen, message, wParam, lParam);
679         return 0;
680 
681     case WM_ERASEBKGND:
682 #if CYGDEBUG
683         winDebug("winMWExtWMWindowProc - WM_ERASEBKGND\n");
684 #endif
685         /*
686          * Pretend that we did erase the background but we don't care,
687          * since we repaint the entire region anyhow
688          * This avoids some flickering when resizing.
689          */
690         return TRUE;
691 
692     case WM_PAINT:
693 
694         /* BeginPaint gives us an hdc that clips to the invalidated region */
695         hdcUpdate = BeginPaint(hwnd, &ps);
696 
697         /* Try to copy from the shadow buffer */
698         if (!BitBlt(hdcUpdate,
699                     ps.rcPaint.left, ps.rcPaint.top,
700                     ps.rcPaint.right - ps.rcPaint.left,
701                     ps.rcPaint.bottom - ps.rcPaint.top,
702                     pRLWinPriv->hdcShadow,
703                     ps.rcPaint.left, ps.rcPaint.top, SRCCOPY)) {
704             LPVOID lpMsgBuf;
705 
706             /* Display a fancy error message */
707             FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
708                           FORMAT_MESSAGE_FROM_SYSTEM |
709                           FORMAT_MESSAGE_IGNORE_INSERTS,
710                           NULL,
711                           GetLastError(),
712                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
713                           (LPTSTR) &lpMsgBuf, 0, NULL);
714 
715             ErrorF("winMWExtWMWindowProc - BitBlt failed: %s\n",
716                    (LPSTR) lpMsgBuf);
717             LocalFree(lpMsgBuf);
718         }
719 
720         /* EndPaint frees the DC */
721         EndPaint(hwnd, &ps);
722         break;
723 
724     case WM_ACTIVATE:
725 #if CYGMULTIWINDOW_DEBUG
726         winDebug("winMWExtWMWindowProc - WM_ACTIVATE\n");
727 #endif
728         if (LOWORD(wParam) != WA_INACTIVE) {
729             winWindowsWMSendEvent(WindowsWMControllerNotify,
730                                   WindowsWMControllerNotifyMask,
731                                   1,
732                                   WindowsWMActivateWindow,
733                                   pWin->drawable.id, 0, 0, 0, 0);
734         }
735         return 0;
736 
737 #if 1
738     case WM_WINDOWPOSCHANGING:
739         pWinPos = (LPWINDOWPOS) lParam;
740         if (!(pWinPos->flags & SWP_NOZORDER)) {
741             if (pRLWinPriv->fRestackingNow || pScreenPriv->fRestacking) {
742 #if CYGMULTIWINDOW_DEBUG
743                 winDebug("Win %p is now restacking.\n",
744                          pRLWinPriv);
745 #endif
746                 break;
747             }
748 
749 #if CYGMULTIWINDOW_DEBUG
750             winDebug("Win %p forbid to change z order (%p).\n",
751                      pRLWinPriv,
752                      pWinPos->hwndInsertAfter);
753 #endif
754             pWinPos->flags |= SWP_NOZORDER;
755         }
756         break;
757 #endif
758 
759     case WM_MOVE:
760 #if CYGMULTIWINDOW_DEBUG
761         winDebug("winMWExtWMWindowProc - WM_MOVE\n");
762 #endif
763         if (g_fNoConfigureWindow)
764             break;
765 #if 0
766         /* Bail if Windows window is not actually moving */
767         if (pRLWinPriv->dwX == (short) LOWORD(lParam)
768             && pRLWinPriv->dwY == (short) HIWORD(lParam))
769             break;
770 
771         /* Also bail if we're maximizing, we'll do the whole thing in WM_SIZE */
772         {
773             WINDOWPLACEMENT windPlace;
774 
775             windPlace.length = sizeof(WINDOWPLACEMENT);
776 
777             /* Get current window placement */
778             GetWindowPlacement(hwnd, &windPlace);
779 
780             /* Bail if maximizing */
781             if (windPlace.showCmd == SW_MAXIMIZE
782                 || windPlace.showCmd == SW_SHOWMAXIMIZED)
783                 break;
784         }
785 #endif
786 
787 #if CYGMULTIWINDOW_DEBUG
788         winDebug("\t(%d, %d)\n", (short) LOWORD(lParam),
789                  (short) HIWORD(lParam));
790 #endif
791         if (!pRLWinPriv->fMovingOrSizing) {
792             winMWExtWMMoveXWindow(pWin, (LOWORD(lParam) - wBorderWidth(pWin)
793                                          - GetSystemMetrics(SM_XVIRTUALSCREEN)),
794                                   (HIWORD(lParam) - wBorderWidth(pWin)
795                                    - GetSystemMetrics(SM_YVIRTUALSCREEN)));
796         }
797         return 0;
798 
799     case WM_SHOWWINDOW:
800 #if CYGMULTIWINDOW_DEBUG || TRUE
801         winDebug("winMWExtWMWindowProc - WM_SHOWWINDOW\n");
802 #endif
803         /* Bail out if the window is being hidden */
804         if (!wParam)
805             return 0;
806 
807         winMWExtWMUpdateWindowDecoration(pRLWinPriv, pScreenInfo);
808 
809         break;
810 
811     case WM_SIZING:
812         /* Need to legalize the size according to WM_NORMAL_HINTS */
813         /* for applications like xterm */
814         return ValidateSizing(hwnd, pWin, wParam, lParam);
815 
816     case WM_WINDOWPOSCHANGED:
817     {
818         pWinPos = (LPWINDOWPOS) lParam;
819 #if CYGMULTIWINDOW_DEBUG
820         winDebug("winMWExtWMWindowProc - WM_WINDOWPOSCHANGED\n");
821         winDebug("\tflags: %s%s%s%s%s%s%s%s%s%s%s%s\n",
822                  (pWinPos->flags & SWP_DRAWFRAME) ? "SWP_DRAWFRAME " : "",
823                  (pWinPos->flags & SWP_FRAMECHANGED) ? "SWP_FRAMECHANGED " : "",
824                  (pWinPos->flags & SWP_HIDEWINDOW) ? "SWP_HIDEWINDOW " : "",
825                  (pWinPos->flags & SWP_NOACTIVATE) ? "SWP_NOACTIVATE " : "",
826                  (pWinPos->flags & SWP_NOCOPYBITS) ? "SWP_NOCOPYBITS " : "",
827                  (pWinPos->flags & SWP_NOMOVE) ? "SWP_NOMOVE " : "",
828                  (pWinPos->
829                   flags & SWP_NOOWNERZORDER) ? "SWP_NOOWNERZORDER " : "",
830                  (pWinPos->flags & SWP_NOSIZE) ? "SWP_NOSIZE " : "",
831                  (pWinPos->flags & SWP_NOREDRAW) ? "SWP_NOREDRAW " : "",
832                  (pWinPos->
833                   flags & SWP_NOSENDCHANGING) ? "SWP_NOSENDCHANGING " : "",
834                  (pWinPos->flags & SWP_NOZORDER) ? "SWP_NOZORDER " : "",
835                  (pWinPos->flags & SWP_SHOWWINDOW) ? "SWP_SHOWWINDOW " : "");
836         winDebug("\tno_configure: %s\n", (g_fNoConfigureWindow ? "Yes" : "No"));
837         winDebug("\textend: (%d, %d, %d, %d)\n",
838                  pWinPos->x, pWinPos->y, pWinPos->cx, pWinPos->cy);
839 
840 #endif
841         if (pWinPos->flags & SWP_HIDEWINDOW)
842             break;
843 
844         if (!(pWinPos->flags & SWP_NOSIZE)) {
845             if (IsIconic(hwnd)) {
846 #if CYGMULTIWINDOW_DEBUG
847                 winDebug("\tIconic -> MINIMIZED\n");
848 #endif
849 
850                 winWindowsWMSendEvent(WindowsWMControllerNotify,
851                                       WindowsWMControllerNotifyMask,
852                                       1,
853                                       WindowsWMMinimizeWindow,
854                                       pWin->drawable.id, 0, 0, 0, 0);
855             }
856             else if (IsZoomed(hwnd)) {
857 #if CYGMULTIWINDOW_DEBUG
858                 winDebug("\tZoomed -> MAXIMIZED\n");
859 #endif
860                 winWindowsWMSendEvent(WindowsWMControllerNotify,
861                                       WindowsWMControllerNotifyMask,
862                                       1,
863                                       WindowsWMMaximizeWindow,
864                                       pWin->drawable.id, 0, 0, 0, 0);
865             }
866             else {
867 #if CYGMULTIWINDOW_DEBUG
868                 winDebug("\tnone -> RESTORED\n");
869 #endif
870                 winWindowsWMSendEvent(WindowsWMControllerNotify,
871                                       WindowsWMControllerNotifyMask,
872                                       1,
873                                       WindowsWMRestoreWindow,
874                                       pWin->drawable.id, 0, 0, 0, 0);
875             }
876         }
877         if (!g_fNoConfigureWindow) {
878 
879             if (!pRLWinPriv->fMovingOrSizing
880                 /*&& (pWinPos->flags & SWP_SHOWWINDOW) */ ) {
881                 GetClientRect(hwnd, &rcClient);
882                 MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT) &rcClient, 2);
883 
884                 if (!(pWinPos->flags & SWP_NOMOVE)
885                     && !(pWinPos->flags & SWP_NOSIZE)) {
886 #if CYGMULTIWINDOW_DEBUG
887                     winDebug("\tmove & resize\n");
888 #endif
889 
890                     winMWExtWMMoveResizeXWindow(pWin,
891                                                 rcClient.left -
892                                                 wBorderWidth(pWin)
893                                                 -
894                                                 GetSystemMetrics
895                                                 (SM_XVIRTUALSCREEN),
896                                                 rcClient.top -
897                                                 wBorderWidth(pWin)
898                                                 -
899                                                 GetSystemMetrics
900                                                 (SM_YVIRTUALSCREEN),
901                                                 rcClient.right - rcClient.left -
902                                                 wBorderWidth(pWin) * 2,
903                                                 rcClient.bottom - rcClient.top -
904                                                 wBorderWidth(pWin) * 2);
905                 }
906                 else if (!(pWinPos->flags & SWP_NOMOVE)) {
907 #if CYGMULTIWINDOW_DEBUG
908                     winDebug("\tmove\n");
909 #endif
910 
911                     winMWExtWMMoveResizeXWindow(pWin,
912                                                 rcClient.left -
913                                                 wBorderWidth(pWin)
914                                                 -
915                                                 GetSystemMetrics
916                                                 (SM_XVIRTUALSCREEN),
917                                                 rcClient.top -
918                                                 wBorderWidth(pWin)
919                                                 -
920                                                 GetSystemMetrics
921                                                 (SM_YVIRTUALSCREEN),
922                                                 rcClient.right - rcClient.left -
923                                                 wBorderWidth(pWin) * 2,
924                                                 rcClient.bottom - rcClient.top -
925                                                 wBorderWidth(pWin) * 2);
926                 }
927                 else if (!(pWinPos->flags & SWP_NOMOVE)) {
928 #if CYGMULTIWINDOW_DEBUG
929                     winDebug("\tmove\n");
930 #endif
931 
932                     winMWExtWMMoveXWindow(pWin,
933                                           rcClient.left - wBorderWidth(pWin)
934                                           - GetSystemMetrics(SM_XVIRTUALSCREEN),
935                                           rcClient.top - wBorderWidth(pWin)
936                                           -
937                                           GetSystemMetrics(SM_YVIRTUALSCREEN));
938                 }
939                 else if (!(pWinPos->flags & SWP_NOSIZE)) {
940 #if CYGMULTIWINDOW_DEBUG
941                     winDebug("\tresize\n");
942 #endif
943 
944                     winMWExtWMResizeXWindow(pWin,
945                                             rcClient.right - rcClient.left
946                                             - wBorderWidth(pWin) * 2,
947                                             rcClient.bottom - rcClient.top
948                                             - wBorderWidth(pWin) * 2);
949                 }
950             }
951         }
952     }
953 #if CYGMULTIWINDOW_DEBUG
954         winDebug("winMWExtWMWindowProc - WM_WINDOWPOSCHANGED - done.\n");
955 #endif
956         return 0;
957 
958     case WM_SIZE:
959         /* see dix/window.c */
960         /* FIXME: Maximize/Restore? */
961 #if CYGMULTIWINDOW_DEBUG
962         winDebug("winMWExtWMWindowProc - WM_SIZE\n");
963 #endif
964 #if CYGMULTIWINDOW_DEBUG
965         winDebug("\t(%d, %d) %d\n", (short) LOWORD(lParam),
966                  (short) HIWORD(lParam), g_fNoConfigureWindow);
967 #endif
968         if (g_fNoConfigureWindow)
969             break;
970 
971         /* Branch on type of resizing occurring */
972         switch (wParam) {
973         case SIZE_MINIMIZED:
974 #if CYGMULTIWINDOW_DEBUG
975             winDebug("\tSIZE_MINIMIZED\n");
976 #endif
977 
978             winWindowsWMSendEvent(WindowsWMControllerNotify,
979                                   WindowsWMControllerNotifyMask,
980                                   1,
981                                   WindowsWMMinimizeWindow,
982                                   pWin->drawable.id,
983                                   0, 0, LOWORD(lParam), HIWORD(lParam));
984             break;
985 
986         case SIZE_RESTORED:
987 #if CYGMULTIWINDOW_DEBUG
988             winDebug("\tSIZE_RESTORED\n");
989 #endif
990             winWindowsWMSendEvent(WindowsWMControllerNotify,
991                                   WindowsWMControllerNotifyMask,
992                                   1,
993                                   WindowsWMRestoreWindow,
994                                   pWin->drawable.id,
995                                   0, 0, LOWORD(lParam), HIWORD(lParam));
996             break;
997 
998         case SIZE_MAXIMIZED:
999 #if CYGMULTIWINDOW_DEBUG
1000             winDebug("\tSIZE_MAXIMIZED\n");
1001 #endif
1002             winWindowsWMSendEvent(WindowsWMControllerNotify,
1003                                   WindowsWMControllerNotifyMask,
1004                                   1,
1005                                   WindowsWMMaximizeWindow,
1006                                   pWin->drawable.id,
1007                                   0, 0, LOWORD(lParam), HIWORD(lParam));
1008             break;
1009         }
1010 
1011         /* Perform the resize and notify the X client */
1012         if (!pRLWinPriv->fMovingOrSizing) {
1013             winMWExtWMResizeXWindow(pWin, (short) LOWORD(lParam)
1014                                     - wBorderWidth(pWin) * 2,
1015                                     (short) HIWORD(lParam)
1016                                     - wBorderWidth(pWin) * 2);
1017         }
1018         break;
1019 
1020     case WM_ACTIVATEAPP:
1021 #if CYGMULTIWINDOW_DEBUG
1022         winDebug("winMWExtWMWindowProc - WM_ACTIVATEAPP\n");
1023 #endif
1024         if (wParam) {
1025             winWindowsWMSendEvent(WindowsWMActivationNotify,
1026                                   WindowsWMActivationNotifyMask,
1027                                   1,
1028                                   WindowsWMIsActive,
1029                                   pWin->drawable.id, 0, 0, 0, 0);
1030         }
1031         else {
1032             winWindowsWMSendEvent(WindowsWMActivationNotify,
1033                                   WindowsWMActivationNotifyMask,
1034                                   1,
1035                                   WindowsWMIsInactive,
1036                                   pWin->drawable.id, 0, 0, 0, 0);
1037         }
1038         break;
1039 
1040     case WM_SETCURSOR:
1041         if (LOWORD(lParam) == HTCLIENT) {
1042             if (!g_fSoftwareCursor)
1043                 SetCursor(pScreenPriv->cursor.handle);
1044             return TRUE;
1045         }
1046         break;
1047 
1048     case WM_ENTERSIZEMOVE:
1049 #if CYGMULTIWINDOW_DEBUG
1050         winDebug("winMWExtWMWindowProc - WM_ENTERSIZEMOVE\n");
1051 #endif
1052         pRLWinPriv->fMovingOrSizing = TRUE;
1053         break;
1054 
1055     case WM_EXITSIZEMOVE:
1056 #if CYGMULTIWINDOW_DEBUG
1057         winDebug("winMWExtWMWindowProc - WM_EXITSIZEMOVE\n");
1058 #endif
1059         pRLWinPriv->fMovingOrSizing = FALSE;
1060 
1061         GetClientRect(hwnd, &rcClient);
1062 
1063         MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT) &rcClient, 2);
1064 
1065         winMWExtWMMoveResizeXWindow(pWin, rcClient.left - wBorderWidth(pWin)
1066                                     - GetSystemMetrics(SM_XVIRTUALSCREEN),
1067                                     rcClient.top - wBorderWidth(pWin)
1068                                     - GetSystemMetrics(SM_YVIRTUALSCREEN),
1069                                     rcClient.right - rcClient.left
1070                                     - wBorderWidth(pWin) * 2,
1071                                     rcClient.bottom - rcClient.top
1072                                     - wBorderWidth(pWin) * 2);
1073         break;
1074 
1075     default:
1076         break;
1077     }
1078 
1079     return DefWindowProc(hwnd, message, wParam, lParam);
1080 }
1081