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