コード例 #1
0
LRESULT CALLBACK
winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static winPrivScreenPtr s_pScreenPriv = NULL;
    static winScreenInfo *s_pScreenInfo = NULL;
    static ScreenPtr s_pScreen = NULL;
    static HWND s_hwndLastPrivates = NULL;
    static HINSTANCE s_hInstance;
    static Bool s_fTracking = FALSE;
    static unsigned long s_ulServerGeneration = 0;
    static UINT s_uTaskbarRestart = 0;
    int iScanCode;
    int i;

#if CYGDEBUG
    winDebugWin32Message("winWindowProc", hwnd, message, wParam, lParam);
#endif

    /* Watch for server regeneration */
    if (g_ulServerGeneration != s_ulServerGeneration) {
        /* Store new server generation */
        s_ulServerGeneration = g_ulServerGeneration;
    }

    /* Only retrieve new privates pointers if window handle is null or changed */
    if ((s_pScreenPriv == NULL || hwnd != s_hwndLastPrivates)
        && (s_pScreenPriv = GetProp(hwnd, WIN_SCR_PROP)) != NULL) {
#if CYGDEBUG
        winDebug("winWindowProc - Setting privates handle\n");
#endif
        s_pScreenInfo = s_pScreenPriv->pScreenInfo;
        s_pScreen = s_pScreenInfo->pScreen;
        s_hwndLastPrivates = hwnd;
    }
    else if (s_pScreenPriv == NULL) {
        /* For safety, handle case that should never happen */
        s_pScreenInfo = NULL;
        s_pScreen = NULL;
        s_hwndLastPrivates = NULL;
    }

    /* Branch on message type */
    switch (message) {
    case WM_TRAYICON:
        return winHandleIconMessage(hwnd, message, wParam, lParam,
                                    s_pScreenPriv);

    case WM_CREATE:
#if CYGDEBUG
        winDebug("winWindowProc - WM_CREATE\n");
#endif

        /*
         * Add a property to our display window that references
         * this screens' privates.
         *
         * This allows the window procedure to refer to the
         * appropriate window DC and shadow DC for the window that
         * it is processing.  We use this to repaint exposed
         * areas of our display window.
         */
        s_pScreenPriv = ((LPCREATESTRUCT) lParam)->lpCreateParams;
        s_hInstance = ((LPCREATESTRUCT) lParam)->hInstance;
        s_pScreenInfo = s_pScreenPriv->pScreenInfo;
        s_pScreen = s_pScreenInfo->pScreen;
        s_hwndLastPrivates = hwnd;
        s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
        SetProp(hwnd, WIN_SCR_PROP, s_pScreenPriv);

        /* Setup tray icon */
        if (!s_pScreenInfo->fNoTrayIcon) {
            /*
             * NOTE: The WM_CREATE message is processed before CreateWindowEx
             * returns, so s_pScreenPriv->hwndScreen is invalid at this point.
             * We go ahead and copy our hwnd parameter over top of the screen
             * privates hwndScreen so that we have a valid value for
             * that member.  Otherwise, the tray icon will disappear
             * the first time you move the mouse over top of it.
             */

            s_pScreenPriv->hwndScreen = hwnd;

            winInitNotifyIcon(s_pScreenPriv);
        }
        return 0;

    case WM_DISPLAYCHANGE:
        /*
           WM_DISPLAYCHANGE seems to be sent when the monitor layout or
           any monitor's resolution or depth changes, but it's lParam and
           wParam always indicate the resolution and bpp for the primary
           monitor (so ignore that as we could be on any monitor...)
         */

        /* We cannot handle a display mode change during initialization */
        if (s_pScreenInfo == NULL)
            FatalError("winWindowProc - WM_DISPLAYCHANGE - The display "
                       "mode changed while we were intializing.  This is "
                       "very bad and unexpected.  Exiting.\n");

        /*
         * We do not care about display changes with
         * fullscreen DirectDraw engines, because those engines set
         * their own mode when they become active.
         */
        if (s_pScreenInfo->fFullScreen
            && (s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD
                || s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL
#ifdef XWIN_PRIMARYFB
                || s_pScreenInfo->dwEngine == WIN_SERVER_PRIMARY_DD
#endif
            )) {
            break;
        }

        ErrorF("winWindowProc - WM_DISPLAYCHANGE - new width: %d "
               "new height: %d new bpp: %d\n",
               LOWORD(lParam), HIWORD(lParam), wParam);

        /* 0 bpp has no defined meaning, ignore this message */
        if (wParam == 0)
            break;

        /*
         * Check for a disruptive change in depth.
         * We can only display a message for a disruptive depth change,
         * we cannot do anything to correct the situation.
         */
        /*
           XXX: maybe we need to check if GetSystemMetrics(SM_SAMEDISPLAYFORMAT)
           has changed as well...
         */
        if (s_pScreenInfo->dwBPP !=
            GetDeviceCaps(s_pScreenPriv->hdcScreen, BITSPIXEL)) {
            if ((s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD ||
                 s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL
#ifdef XWIN_PRIMARYFB
                 || s_pScreenInfo->dwEngine == WIN_SERVER_PRIMARY_DD
#endif
                )) {
                /* Cannot display the visual until the depth is restored */
                ErrorF("winWindowProc - Disruptive change in depth\n");

                /* Display depth change dialog */
                winDisplayDepthChangeDialog(s_pScreenPriv);

                /* Flag that we have an invalid screen depth */
                s_pScreenPriv->fBadDepth = TRUE;

                /* Minimize the display window */
                ShowWindow(hwnd, SW_MINIMIZE);
            }
            else {
                /* For GDI, performance may suffer until original depth is restored */
                ErrorF
                    ("winWindowProc - Performance may be non-optimal after change in depth\n");
            }
        }
        else {
            /* Flag that we have a valid screen depth */
            s_pScreenPriv->fBadDepth = FALSE;
        }

        /*
           If we could cheaply check if this WM_DISPLAYCHANGE change
           affects the monitor(s) which this X screen is displayed on
           then we should do so here.  For the moment, assume it does.
           (this is probably usually the case so that might be an
           overoptimization)
         */
        {
            /*
               In rootless modes which are monitor or virtual desktop size
               use RandR to resize the X screen
             */
            if ((!s_pScreenInfo->fUserGaveHeightAndWidth) &&
                (s_pScreenInfo->iResizeMode == resizeWithRandr) && (FALSE
#ifdef XWIN_MULTIWINDOWEXTWM
                                                                    ||
                                                                    s_pScreenInfo->
                                                                    fMWExtWM
#endif
                                                                    ||
                                                                    s_pScreenInfo->
                                                                    fRootless
#ifdef XWIN_MULTIWINDOW
                                                                    ||
                                                                    s_pScreenInfo->
                                                                    fMultiWindow
#endif
                )) {
                DWORD dwWidth, dwHeight;

                if (s_pScreenInfo->fMultipleMonitors) {
                    /* resize to new virtual desktop size */
                    dwWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
                    dwHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
                }
                else {
                    /* resize to new size of specified monitor */
                    struct GetMonitorInfoData data;

                    if (QueryMonitor(s_pScreenInfo->iMonitor, &data)) {
                        if (data.bMonitorSpecifiedExists == TRUE) {
                            dwWidth = data.monitorWidth;
                            dwHeight = data.monitorHeight;
                            /*
                               XXX: monitor may have changed position,
                               so we might need to update xinerama data
                             */
                        }
                        else {
                            ErrorF("Monitor number %d no longer exists!\n",
                                   s_pScreenInfo->iMonitor);
                        }
                    }
                }

                /*
                   XXX: probably a small bug here: we don't compute the work area
                   and allow for task bar

                   XXX: generally, we don't allow for the task bar being moved after
                   the server is started
                 */

                /* Set screen size to match new size, if it is different to current */
                if ((s_pScreenInfo->dwWidth != dwWidth) ||
                    (s_pScreenInfo->dwHeight != dwHeight)) {
                    winDoRandRScreenSetSize(s_pScreen,
                                            dwWidth,
                                            dwHeight,
                                            (dwWidth * 25.4) /
                                            monitorResolution,
                                            (dwHeight * 25.4) /
                                            monitorResolution);
                }
            }
            else {
                /*
                 * We can simply recreate the same-sized primary surface when
                 * the display dimensions change.
                 */

                /*
                 * NOTE: The non-DirectDraw engines set the ReleasePrimarySurface
                 * and CreatePrimarySurface function pointers to point
                 * to the no operation function, NoopDDA.  This allows us
                 * to blindly call these functions, even if they are not
                 * relevant to the current engine (e.g., Shadow GDI).
                 */

                winDebug
                    ("winWindowProc - WM_DISPLAYCHANGE - Releasing and recreating primary surface\n");

                /* Release the old primary surface */
                (*s_pScreenPriv->pwinReleasePrimarySurface) (s_pScreen);

                /* Create the new primary surface */
                (*s_pScreenPriv->pwinCreatePrimarySurface) (s_pScreen);
            }
        }

        break;

    case WM_SIZE:
    {
        SCROLLINFO si;
        RECT rcWindow;
        int iWidth, iHeight;

#if CYGDEBUG
        winDebug("winWindowProc - WM_SIZE\n");
#endif

        /* Break if we do not allow resizing */
        if ((s_pScreenInfo->iResizeMode == notAllowed)
            || !s_pScreenInfo->fDecoration
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            || s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOW
            || s_pScreenInfo->fMultiWindow
#endif
            || s_pScreenInfo->fFullScreen)
            break;

        /* No need to resize if we get minimized */
        if (wParam == SIZE_MINIMIZED)
            return 0;

        ErrorF("winWindowProc - WM_SIZE - new client area w: %d h: %d\n",
               LOWORD(lParam), HIWORD(lParam));

        if (s_pScreenInfo->iResizeMode == resizeWithRandr) {
            /* Actual resizing is done on WM_EXITSIZEMOVE */
            return 0;
        }

        /* Otherwise iResizeMode == resizeWithScrollbars */

        /*
         * Get the size of the whole window, including client area,
         * scrollbars, and non-client area decorations (caption, borders).
         * We do this because we need to check if the client area
         * without scrollbars is large enough to display the whole visual.
         * The new client area size passed by lParam already subtracts
         * the size of the scrollbars if they are currently displayed.
         * So checking is LOWORD(lParam) == visual_width and
         * HIWORD(lParam) == visual_height will never tell us to hide
         * the scrollbars because the client area would always be too small.
         * GetClientRect returns the same sizes given by lParam, so we
         * cannot use GetClientRect either.
         */
        GetWindowRect(hwnd, &rcWindow);
        iWidth = rcWindow.right - rcWindow.left;
        iHeight = rcWindow.bottom - rcWindow.top;

        /* Subtract the frame size from the window size. */
        iWidth -= 2 * GetSystemMetrics(SM_CXSIZEFRAME);
        iHeight -= (2 * GetSystemMetrics(SM_CYSIZEFRAME)
                    + GetSystemMetrics(SM_CYCAPTION));

        /*
         * Update scrollbar page sizes.
         * NOTE: If page size == range, then the scrollbar is
         * automatically hidden.
         */

        /* Is the naked client area large enough to show the whole visual? */
        if (iWidth < s_pScreenInfo->dwWidth
            || iHeight < s_pScreenInfo->dwHeight) {
            /* Client area too small to display visual, use scrollbars */
            iWidth -= GetSystemMetrics(SM_CXVSCROLL);
            iHeight -= GetSystemMetrics(SM_CYHSCROLL);
        }

        /* Set the horizontal scrollbar page size */
        si.cbSize = sizeof(si);
        si.fMask = SIF_PAGE | SIF_RANGE;
        si.nMin = 0;
        si.nMax = s_pScreenInfo->dwWidth - 1;
        si.nPage = iWidth;
        SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

        /* Set the vertical scrollbar page size */
        si.cbSize = sizeof(si);
        si.fMask = SIF_PAGE | SIF_RANGE;
        si.nMin = 0;
        si.nMax = s_pScreenInfo->dwHeight - 1;
        si.nPage = iHeight;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

        /*
         * NOTE: Scrollbars may have moved if they were at the 
         * far right/bottom, so we query their current position.
         */

        /* Get the horizontal scrollbar position and set the offset */
        si.cbSize = sizeof(si);
        si.fMask = SIF_POS;
        GetScrollInfo(hwnd, SB_HORZ, &si);
        s_pScreenInfo->dwXOffset = -si.nPos;

        /* Get the vertical scrollbar position and set the offset */
        si.cbSize = sizeof(si);
        si.fMask = SIF_POS;
        GetScrollInfo(hwnd, SB_VERT, &si);
        s_pScreenInfo->dwYOffset = -si.nPos;
    }
        return 0;

    case WM_SYSCOMMAND:
        if (s_pScreenInfo->iResizeMode == resizeWithRandr &&
            ((wParam & 0xfff0) == SC_MAXIMIZE ||
             (wParam & 0xfff0) == SC_RESTORE))
            PostMessage(hwnd, WM_EXITSIZEMOVE, 0, 0);
        break;

    case WM_ENTERSIZEMOVE:
        ErrorF("winWindowProc - WM_ENTERSIZEMOVE\n");
        break;

    case WM_EXITSIZEMOVE:
        ErrorF("winWindowProc - WM_EXITSIZEMOVE\n");

        if (s_pScreenInfo->iResizeMode == resizeWithRandr) {
            /* Set screen size to match new client area, if it is different to current */
            RECT rcClient;
            DWORD dwWidth, dwHeight;

            GetClientRect(hwnd, &rcClient);
            dwWidth = rcClient.right - rcClient.left;
            dwHeight = rcClient.bottom - rcClient.top;

            if ((s_pScreenInfo->dwWidth != dwWidth) ||
                (s_pScreenInfo->dwHeight != dwHeight)) {
                /* mm = dots * (25.4 mm / inch) / (dots / inch) */
                winDoRandRScreenSetSize(s_pScreen,
                                        dwWidth,
                                        dwHeight,
                                        (dwWidth * 25.4) / monitorResolution,
                                        (dwHeight * 25.4) / monitorResolution);
            }
        }

        break;

    case WM_VSCROLL:
    {
        SCROLLINFO si;
        int iVertPos;

#if CYGDEBUG
        winDebug("winWindowProc - WM_VSCROLL\n");
#endif

        /* Get vertical scroll bar info */
        si.cbSize = sizeof(si);
        si.fMask = SIF_ALL;
        GetScrollInfo(hwnd, SB_VERT, &si);

        /* Save the vertical position for comparison later */
        iVertPos = si.nPos;

        /*
         * Don't forget:
         * moving the scrollbar to the DOWN, scroll the content UP
         */
        switch (LOWORD(wParam)) {
        case SB_TOP:
            si.nPos = si.nMin;
            break;

        case SB_BOTTOM:
            si.nPos = si.nMax - si.nPage + 1;
            break;

        case SB_LINEUP:
            si.nPos -= 1;
            break;

        case SB_LINEDOWN:
            si.nPos += 1;
            break;

        case SB_PAGEUP:
            si.nPos -= si.nPage;
            break;

        case SB_PAGEDOWN:
            si.nPos += si.nPage;
            break;

        case SB_THUMBTRACK:
            si.nPos = si.nTrackPos;
            break;

        default:
            break;
        }

        /*
         * We retrieve the position after setting it,
         * because Windows may adjust it.
         */
        si.fMask = SIF_POS;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
        GetScrollInfo(hwnd, SB_VERT, &si);

        /* Scroll the window if the position has changed */
        if (si.nPos != iVertPos) {
            /* Save the new offset for bit block transfers, etc. */
            s_pScreenInfo->dwYOffset = -si.nPos;

            /* Change displayed region in the window */
            ScrollWindowEx(hwnd,
                           0,
                           iVertPos - si.nPos,
                           NULL, NULL, NULL, NULL, SW_INVALIDATE);

            /* Redraw the window contents */
            UpdateWindow(hwnd);
        }
    }
        return 0;

    case WM_HSCROLL:
    {
        SCROLLINFO si;
        int iHorzPos;

#if CYGDEBUG
        winDebug("winWindowProc - WM_HSCROLL\n");
#endif

        /* Get horizontal scroll bar info */
        si.cbSize = sizeof(si);
        si.fMask = SIF_ALL;
        GetScrollInfo(hwnd, SB_HORZ, &si);

        /* Save the horizontal position for comparison later */
        iHorzPos = si.nPos;

        /*
         * Don't forget:
         * moving the scrollbar to the RIGHT, scroll the content LEFT
         */
        switch (LOWORD(wParam)) {
        case SB_LEFT:
            si.nPos = si.nMin;
            break;

        case SB_RIGHT:
            si.nPos = si.nMax - si.nPage + 1;
            break;

        case SB_LINELEFT:
            si.nPos -= 1;
            break;

        case SB_LINERIGHT:
            si.nPos += 1;
            break;

        case SB_PAGELEFT:
            si.nPos -= si.nPage;
            break;

        case SB_PAGERIGHT:
            si.nPos += si.nPage;
            break;

        case SB_THUMBTRACK:
            si.nPos = si.nTrackPos;
            break;

        default:
            break;
        }

        /*
         * We retrieve the position after setting it,
         * because Windows may adjust it.
         */
        si.fMask = SIF_POS;
        SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
        GetScrollInfo(hwnd, SB_HORZ, &si);

        /* Scroll the window if the position has changed */
        if (si.nPos != iHorzPos) {
            /* Save the new offset for bit block transfers, etc. */
            s_pScreenInfo->dwXOffset = -si.nPos;

            /* Change displayed region in the window */
            ScrollWindowEx(hwnd,
                           iHorzPos - si.nPos,
                           0, NULL, NULL, NULL, NULL, SW_INVALIDATE);

            /* Redraw the window contents */
            UpdateWindow(hwnd);
        }
    }
        return 0;

    case WM_GETMINMAXINFO:
    {
        MINMAXINFO *pMinMaxInfo = (MINMAXINFO *) lParam;
        int iCaptionHeight;
        int iBorderHeight, iBorderWidth;

#if CYGDEBUG
        winDebug("winWindowProc - WM_GETMINMAXINFO - pScreenInfo: %08x\n",
                 s_pScreenInfo);
#endif

        /* Can't do anything without screen info */
        if (s_pScreenInfo == NULL
            || (s_pScreenInfo->iResizeMode != resizeWithScrollbars)
            || s_pScreenInfo->fFullScreen || !s_pScreenInfo->fDecoration
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            || s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOW
            || s_pScreenInfo->fMultiWindow
#endif
            )
            break;

        /*
         * Here we can override the maximum tracking size, which
         * is the largest size that can be assigned to our window
         * via the sizing border.
         */

        /*
         * FIXME: Do we only need to do this once, since our visual size
         * does not change?  Does Windows store this value statically
         * once we have set it once?
         */

        /* Get the border and caption sizes */
        iCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
        iBorderWidth = 2 * GetSystemMetrics(SM_CXSIZEFRAME);
        iBorderHeight = 2 * GetSystemMetrics(SM_CYSIZEFRAME);

        /* Allow the full visual to be displayed */
        pMinMaxInfo->ptMaxTrackSize.x = s_pScreenInfo->dwWidth + iBorderWidth;
        pMinMaxInfo->ptMaxTrackSize.y
            = s_pScreenInfo->dwHeight + iBorderHeight + iCaptionHeight;
    }
        return 0;

    case WM_ERASEBKGND:
#if CYGDEBUG
        winDebug("winWindowProc - WM_ERASEBKGND\n");
#endif
        /*
         * Pretend that we did erase the background but we don't care,
         * the application uses the full window estate. This avoids some
         * flickering when resizing.
         */
        return TRUE;

    case WM_PAINT:
#if CYGDEBUG
        winDebug("winWindowProc - WM_PAINT\n");
#endif
        /* Only paint if we have privates and the server is enabled */
        if (s_pScreenPriv == NULL
            || !s_pScreenPriv->fEnabled
            || (s_pScreenInfo->fFullScreen && !s_pScreenPriv->fActive)
            || s_pScreenPriv->fBadDepth) {
            /* We don't want to paint */
            break;
        }

        /* Break out here if we don't have a valid paint routine */
        if (s_pScreenPriv->pwinBltExposedRegions == NULL)
            break;

        /* Call the engine dependent repainter */
        (*s_pScreenPriv->pwinBltExposedRegions) (s_pScreen);
        return 0;

    case WM_PALETTECHANGED:
    {
#if CYGDEBUG
        winDebug("winWindowProc - WM_PALETTECHANGED\n");
#endif
        /*
         * Don't process if we don't have privates or a colormap,
         * or if we have an invalid depth.
         */
        if (s_pScreenPriv == NULL
            || s_pScreenPriv->pcmapInstalled == NULL
            || s_pScreenPriv->fBadDepth)
            break;

        /* Return if we caused the palette to change */
        if ((HWND) wParam == hwnd) {
            /* Redraw the screen */
            (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen);
            return 0;
        }

        /* Reinstall the windows palette */
        (*s_pScreenPriv->pwinRealizeInstalledPalette) (s_pScreen);

        /* Redraw the screen */
        (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen);
        return 0;
    }

    case WM_MOUSEMOVE:
        /* We can't do anything without privates */
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /* We can't do anything without g_pwinPointer */
        if (g_pwinPointer == NULL)
            break;

        /* Has the mouse pointer crossed screens? */
        if (s_pScreen != miPointerGetScreen(g_pwinPointer))
            miPointerSetScreen(g_pwinPointer, s_pScreenInfo->dwScreen,
                               GET_X_LPARAM(lParam) - s_pScreenInfo->dwXOffset,
                               GET_Y_LPARAM(lParam) - s_pScreenInfo->dwYOffset);

        /* Are we tracking yet? */
        if (!s_fTracking) {
            TRACKMOUSEEVENT tme;

            /* Setup data structure */
            ZeroMemory(&tme, sizeof(tme));
            tme.cbSize = sizeof(tme);
            tme.dwFlags = TME_LEAVE;
            tme.hwndTrack = hwnd;

            /* Call the tracking function */
            if (!TrackMouseEvent(&tme))
                ErrorF("winWindowProc - TrackMouseEvent failed\n");

            /* Flag that we are tracking now */
            s_fTracking = TRUE;
        }

        /* Hide or show the Windows mouse cursor */
        if (g_fSoftwareCursor && g_fCursor &&
            (s_pScreenPriv->fActive || s_pScreenInfo->fLessPointer)) {
            /* Hide Windows cursor */
            g_fCursor = FALSE;
            ShowCursor(FALSE);
        }
        else if (g_fSoftwareCursor && !g_fCursor && !s_pScreenPriv->fActive
                 && !s_pScreenInfo->fLessPointer) {
            /* Show Windows cursor */
            g_fCursor = TRUE;
            ShowCursor(TRUE);
        }

        /* Deliver absolute cursor position to X Server */
        winEnqueueMotion(GET_X_LPARAM(lParam) - s_pScreenInfo->dwXOffset,
                         GET_Y_LPARAM(lParam) - s_pScreenInfo->dwYOffset);
        return 0;

    case WM_NCMOUSEMOVE:
        /*
         * We break instead of returning 0 since we need to call
         * DefWindowProc to get the mouse cursor changes
         * and min/max/close button highlighting in Windows XP.
         * The Platform SDK says that you should return 0 if you
         * process this message, but it fails to mention that you
         * will give up any default functionality if you do return 0.
         */

        /* We can't do anything without privates */
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /* Non-client mouse movement, show Windows cursor */
        if (g_fSoftwareCursor && !g_fCursor) {
            g_fCursor = TRUE;
            ShowCursor(TRUE);
        }
        break;

    case WM_MOUSELEAVE:
        /* Mouse has left our client area */

        /* Flag that we are no longer tracking */
        s_fTracking = FALSE;

        /* Show the mouse cursor, if necessary */
        if (g_fSoftwareCursor && !g_fCursor) {
            g_fCursor = TRUE;
            ShowCursor(TRUE);
        }
        return 0;

    case WM_LBUTTONDBLCLK:
    case WM_LBUTTONDOWN:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        if (s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            )
            SetCapture(hwnd);
        return winMouseButtonsHandle(s_pScreen, ButtonPress, Button1, wParam);

    case WM_LBUTTONUP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        if (s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            )
            ReleaseCapture();
        return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button1, wParam);

    case WM_MBUTTONDBLCLK:
    case WM_MBUTTONDOWN:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        if (s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            )
            SetCapture(hwnd);
        return winMouseButtonsHandle(s_pScreen, ButtonPress, Button2, wParam);

    case WM_MBUTTONUP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        if (s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            )
            ReleaseCapture();
        return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button2, wParam);

    case WM_RBUTTONDBLCLK:
    case WM_RBUTTONDOWN:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        if (s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            )
            SetCapture(hwnd);
        return winMouseButtonsHandle(s_pScreen, ButtonPress, Button3, wParam);

    case WM_RBUTTONUP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        if (s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            )
            ReleaseCapture();
        return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button3, wParam);

    case WM_XBUTTONDBLCLK:
    case WM_XBUTTONDOWN:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        if (s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            )
            SetCapture(hwnd);
        return winMouseButtonsHandle(s_pScreen, ButtonPress, HIWORD(wParam) + 5,
                                     wParam);
    case WM_XBUTTONUP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        if (s_pScreenInfo->fRootless
#ifdef XWIN_MULTIWINDOWEXTWM
            || s_pScreenInfo->fMWExtWM
#endif
            )
            ReleaseCapture();
        return winMouseButtonsHandle(s_pScreen, ButtonRelease,
                                     HIWORD(wParam) + 5, wParam);

    case WM_TIMER:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /* Branch on the timer id */
        switch (wParam) {
        case WIN_E3B_TIMER_ID:
            /* Send delayed button press */
            winMouseButtonsSendEvent(ButtonPress,
                                     s_pScreenPriv->iE3BCachedPress);

            /* Kill this timer */
            KillTimer(s_pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID);

            /* Clear screen privates flags */
            s_pScreenPriv->iE3BCachedPress = 0;
            break;

        case WIN_POLLING_MOUSE_TIMER_ID:
        {
            POINT point;
            WPARAM wL, wM, wR, wShift, wCtrl;
            LPARAM lPos;

            /* Get the current position of the mouse cursor */
            GetCursorPos(&point);

            /* Map from screen (-X, -Y) to root (0, 0) */
            point.x -= GetSystemMetrics(SM_XVIRTUALSCREEN);
            point.y -= GetSystemMetrics(SM_YVIRTUALSCREEN);

            /* Deliver absolute cursor position to X Server */
            winEnqueueMotion(point.x, point.y);

            /* Check if a button was released but we didn't see it */
            GetCursorPos(&point);
            wL = (GetKeyState(VK_LBUTTON) & 0x8000) ? MK_LBUTTON : 0;
            wM = (GetKeyState(VK_MBUTTON) & 0x8000) ? MK_MBUTTON : 0;
            wR = (GetKeyState(VK_RBUTTON) & 0x8000) ? MK_RBUTTON : 0;
            wShift = (GetKeyState(VK_SHIFT) & 0x8000) ? MK_SHIFT : 0;
            wCtrl = (GetKeyState(VK_CONTROL) & 0x8000) ? MK_CONTROL : 0;
            lPos = MAKELPARAM(point.x, point.y);
            if (g_fButton[0] & !wL)
                PostMessage(hwnd, WM_LBUTTONUP, wCtrl | wM | wR | wShift, lPos);
            if (g_fButton[1] & !wM)
                PostMessage(hwnd, WM_MBUTTONUP, wCtrl | wL | wR | wShift, lPos);
            if (g_fButton[2] & !wR)
                PostMessage(hwnd, WM_RBUTTONUP, wCtrl | wL | wM | wShift, lPos);
        }
        }
        return 0;

    case WM_CTLCOLORSCROLLBAR:
        FatalError("winWindowProc - WM_CTLCOLORSCROLLBAR - We are not "
                   "supposed to get this message.  Exiting.\n");
        return 0;

    case WM_MOUSEWHEEL:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
#if CYGDEBUG
        winDebug("winWindowProc - WM_MOUSEWHEEL\n");
#endif
        winMouseWheel(s_pScreen, GET_WHEEL_DELTA_WPARAM(wParam));
        break;

    case WM_SETFOCUS:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /* Restore the state of all mode keys */
        winRestoreModeKeyStates();

        /* Add the keyboard hook if possible */
        if (g_fKeyboardHookLL)
            g_fKeyboardHookLL = winInstallKeyboardHookLL();
        return 0;

    case WM_KILLFOCUS:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /* Release any pressed keys */
        winKeybdReleaseKeys();

        /* Remove our keyboard hook if it is installed */
        winRemoveKeyboardHookLL();
        return 0;

    case WM_SYSKEYDOWN:
    case WM_KEYDOWN:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /*
         * FIXME: Catching Alt-F4 like this is really terrible.  This should
         * be generalized to handle other Windows keyboard signals.  Actually,
         * the list keys to catch and the actions to perform when caught should
         * be configurable; that way user's can customize the keys that they
         * need to have passed through to their window manager or apps, or they
         * can remap certain actions to new key codes that do not conflict
         * with the X apps that they are using.  Yeah, that'll take awhile.
         */
        if ((s_pScreenInfo->fUseWinKillKey && wParam == VK_F4
             && (GetKeyState(VK_MENU) & 0x8000))
            || (s_pScreenInfo->fUseUnixKillKey && wParam == VK_BACK
                && (GetKeyState(VK_MENU) & 0x8000)
                && (GetKeyState(VK_CONTROL) & 0x8000))) {
            /*
             * Better leave this message here, just in case some unsuspecting
             * user enters Alt + F4 and is surprised when the application
             * quits.
             */
            ErrorF("winWindowProc - WM_*KEYDOWN - Closekey hit, quitting\n");

            /* Display Exit dialog */
            winDisplayExitDialog(s_pScreenPriv);
            return 0;
        }

        /*
         * Don't do anything for the Windows keys, as focus will soon
         * be returned to Windows.  We may be able to trap the Windows keys,
         * but we should determine if that is desirable before doing so.
         */
        if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL)
            break;

        /* Discard fake Ctrl_L events that precede AltGR on non-US keyboards */
        if (winIsFakeCtrl_L(message, wParam, lParam))
            return 0;

        /* 
         * Discard presses generated from Windows auto-repeat
         */
        if (lParam & (1 << 30)) {
            switch (wParam) {
                /* ago: Pressing LControl while RControl is pressed is 
                 * Indicated as repeat. Fix this!
                 */
            case VK_CONTROL:
            case VK_SHIFT:
                if (winCheckKeyPressed(wParam, lParam))
                    return 0;
                break;
            default:
                return 0;
            }
        }

        /* Translate Windows key code to X scan code */
        winTranslateKey(wParam, lParam, &iScanCode);

        /* Ignore repeats for CapsLock */
        if (wParam == VK_CAPITAL)
            lParam = 1;

        /* Send the key event(s) */
        for (i = 0; i < LOWORD(lParam); ++i)
            winSendKeyEvent(iScanCode, TRUE);
        return 0;

    case WM_SYSKEYUP:
    case WM_KEYUP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /*
         * Don't do anything for the Windows keys, as focus will soon
         * be returned to Windows.  We may be able to trap the Windows keys,
         * but we should determine if that is desirable before doing so.
         */
        if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL)
            break;

        /* Ignore the fake Ctrl_L that follows an AltGr release */
        if (winIsFakeCtrl_L(message, wParam, lParam))
            return 0;

        /* Enqueue a keyup event */
        winTranslateKey(wParam, lParam, &iScanCode);
        winSendKeyEvent(iScanCode, FALSE);

        /* Release all pressed shift keys */
        if (wParam == VK_SHIFT)
            winFixShiftKeys(iScanCode);
        return 0;

    case WM_HOTKEY:
        if (s_pScreenPriv == NULL)
            break;

        /* Call the engine-specific hot key handler */
        (*s_pScreenPriv->pwinHotKeyAltTab) (s_pScreen);
        return 0;

    case WM_ACTIVATE:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /* TODO: Override display of window when we have a bad depth */
        if (LOWORD(wParam) != WA_INACTIVE && s_pScreenPriv->fBadDepth) {
            ErrorF("winWindowProc - WM_ACTIVATE - Bad depth, trying "
                   "to override window activation\n");

            /* Minimize the window */
            ShowWindow(hwnd, SW_MINIMIZE);

            /* Display dialog box */
            if (g_hDlgDepthChange != NULL) {
                /* Make the existing dialog box active */
                SetActiveWindow(g_hDlgDepthChange);
            }
            else {
                /* TODO: Recreate the dialog box and bring to the top */
                ShowWindow(g_hDlgDepthChange, SW_SHOWDEFAULT);
            }

            /* Don't do any other processing of this message */
            return 0;
        }

#if CYGDEBUG
        winDebug("winWindowProc - WM_ACTIVATE\n");
#endif

        /*
         * Focus is being changed to another window.
         * The other window may or may not belong to
         * our process.
         */

        /* Clear any lingering wheel delta */
        s_pScreenPriv->iDeltaZ = 0;

        /* Reshow the Windows mouse cursor if we are being deactivated */
        if (g_fSoftwareCursor && LOWORD(wParam) == WA_INACTIVE && !g_fCursor) {
            /* Show Windows cursor */
            g_fCursor = TRUE;
            ShowCursor(TRUE);
        }
        return 0;

    case WM_ACTIVATEAPP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

#if CYGDEBUG || TRUE
        winDebug("winWindowProc - WM_ACTIVATEAPP\n");
#endif

        /* Activate or deactivate */
        s_pScreenPriv->fActive = wParam;

        /* Reshow the Windows mouse cursor if we are being deactivated */
        if (g_fSoftwareCursor && !s_pScreenPriv->fActive && !g_fCursor) {
            /* Show Windows cursor */
            g_fCursor = TRUE;
            ShowCursor(TRUE);
        }

#ifdef XWIN_CLIPBOARD
        /* Make sure the clipboard chain is ok. */
        winFixClipboardChain();
#endif

        /* Call engine specific screen activation/deactivation function */
        (*s_pScreenPriv->pwinActivateApp) (s_pScreen);

#ifdef XWIN_MULTIWINDOWEXTWM
        if (s_pScreenPriv->fActive) {
            /* Restack all window unless using built-in wm. */
            if (s_pScreenInfo->fInternalWM && s_pScreenInfo->fAnotherWMRunning)
                winMWExtWMRestackWindows(s_pScreen);
        }
#endif

        return 0;

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case ID_APP_EXIT:
            /* Display Exit dialog */
            winDisplayExitDialog(s_pScreenPriv);
            return 0;

#ifdef XWIN_MULTIWINDOW
        case ID_APP_HIDE_ROOT:
            if (s_pScreenPriv->fRootWindowShown)
                ShowWindow(s_pScreenPriv->hwndScreen, SW_HIDE);
            else
                ShowWindow(s_pScreenPriv->hwndScreen, SW_SHOW);
            s_pScreenPriv->fRootWindowShown = !s_pScreenPriv->fRootWindowShown;
            return 0;
#endif

        case ID_APP_ABOUT:
            /* Display the About box */
            winDisplayAboutDialog(s_pScreenPriv);
            return 0;

        default:
            /* It's probably one of the custom menus... */
            if (HandleCustomWM_COMMAND(0, LOWORD(wParam)))
                return 0;
        }
        break;

    case WM_ENDSESSION:
    case WM_GIVEUP:
        /* Tell X that we are giving up */
#ifdef XWIN_MULTIWINDOW
        if (s_pScreenInfo->fMultiWindow)
            winDeinitMultiWindowWM();
#endif
        GiveUp(0);
        return 0;

    case WM_CLOSE:
        /* Display Exit dialog */
        winDisplayExitDialog(s_pScreenPriv);
        return 0;

    case WM_SETCURSOR:
        if (LOWORD(lParam) == HTCLIENT) {
            if (!g_fSoftwareCursor)
                SetCursor(s_pScreenPriv->cursor.handle);
            return TRUE;
        }
        break;

#ifdef XWIN_MULTIWINDOWEXTWM
    case WM_MANAGE:
        ErrorF("winWindowProc - WM_MANAGE\n");
        s_pScreenInfo->fAnotherWMRunning = FALSE;

        if (s_pScreenInfo->fInternalWM) {
            EnumThreadWindows(g_dwCurrentThreadID, winMWExtWMDecorateWindow, 0);
            //RootlessRepositionWindows (s_pScreen);
        }
        break;

    case WM_UNMANAGE:
        ErrorF("winWindowProc - WM_UNMANAGE\n");
        s_pScreenInfo->fAnotherWMRunning = TRUE;

        if (s_pScreenInfo->fInternalWM) {
            EnumThreadWindows(g_dwCurrentThreadID, winMWExtWMDecorateWindow, 0);
            winMWExtWMRestackWindows(s_pScreen);
        }
        break;
#endif

    default:
        if (message == s_uTaskbarRestart) {
            winInitNotifyIcon(s_pScreenPriv);
        }
        break;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}
コード例 #2
0
LRESULT CALLBACK
winMWExtWMWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    WindowPtr pWin = NULL;
    win32RootlessWindowPtr pRLWinPriv = NULL;
    ScreenPtr pScreen = NULL;
    winPrivScreenPtr pScreenPriv = NULL;
    winScreenInfo *pScreenInfo = NULL;
    HWND hwndScreen = NULL;
    POINT ptMouse;
    static Bool s_fTracking = FALSE;
    HDC hdcUpdate;
    PAINTSTRUCT ps;
    LPWINDOWPOS pWinPos = NULL;
    RECT rcClient;
    winWMMessageRec wmMsg;
    Bool fWMMsgInitialized = FALSE;

    /* Check if the Windows window property for our X window pointer is valid */
    if ((pRLWinPriv =
         (win32RootlessWindowPtr) GetProp(hwnd, WIN_WINDOW_PROP)) != NULL) {
        pWin = pRLWinPriv->pFrame->win;
        pScreen = pWin->drawable.pScreen;
        if (pScreen)
            pScreenPriv = winGetScreenPriv(pScreen);
        if (pScreenPriv)
            pScreenInfo = pScreenPriv->pScreenInfo;
        if (pScreenPriv)
            hwndScreen = pScreenPriv->hwndScreen;

        wmMsg.msg = 0;
        wmMsg.hwndWindow = hwnd;
        wmMsg.iWindow = (Window) pWin->drawable.id;

        wmMsg.iX = pRLWinPriv->pFrame->x;
        wmMsg.iY = pRLWinPriv->pFrame->y;
        wmMsg.iWidth = pRLWinPriv->pFrame->width;
        wmMsg.iHeight = pRLWinPriv->pFrame->height;

        fWMMsgInitialized = TRUE;
#if CYGDEBUG
        winDebugWin32Message("winMWExtWMWindowProc", hwnd, message, wParam,
                             lParam);

        winDebug("\thWnd %08X\n", hwnd);
        winDebug("\tpScreenPriv %08X\n", pScreenPriv);
        winDebug("\tpScreenInfo %08X\n", pScreenInfo);
        winDebug("\thwndScreen %08X\n", hwndScreen);
        winDebug("winMWExtWMWindowProc (%08x) %08x %08x %08x\n",
                 pRLWinPriv, message, wParam, lParam);
#endif
    }
    /* Branch on message type */
    switch (message) {
    case WM_CREATE:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_CREATE\n");
#endif
        /* */
        SetProp(hwnd,
                WIN_WINDOW_PROP,
                (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams);
        return 0;

    case WM_CLOSE:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_CLOSE %d\n", pRLWinPriv->fClose);
#endif
        /* Tell window-manager to close window */
        if (pRLWinPriv->fClose) {
            DestroyWindow(hwnd);
        }
        else {
            if (winIsInternalWMRunning(pScreenInfo)) {
                /* Tell our Window Manager thread to kill the window */
                wmMsg.msg = WM_WM_KILL;
                if (fWMMsgInitialized)
                    winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg);
            }
            winWindowsWMSendEvent(WindowsWMControllerNotify,
                                  WindowsWMControllerNotifyMask,
                                  1,
                                  WindowsWMCloseWindow,
                                  pWin->drawable.id, 0, 0, 0, 0);
        }
        return 0;

    case WM_DESTROY:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_DESTROY\n");
#endif
        /* Free the shaodw DC; which allows the bitmap to be freed */
        DeleteDC(pRLWinPriv->hdcShadow);
        pRLWinPriv->hdcShadow = NULL;

        /* Free the shadow bitmap */
        DeleteObject(pRLWinPriv->hbmpShadow);
        pRLWinPriv->hbmpShadow = NULL;

        /* Free the screen DC */
        ReleaseDC(pRLWinPriv->hWnd, pRLWinPriv->hdcScreen);
        pRLWinPriv->hdcScreen = NULL;

        /* Free shadow buffer info header */
        free(pRLWinPriv->pbmihShadow);
        pRLWinPriv->pbmihShadow = NULL;

        pRLWinPriv->fResized = FALSE;
        pRLWinPriv->pfb = NULL;
        free(pRLWinPriv);
        RemoveProp(hwnd, WIN_WINDOW_PROP);
        break;

    case WM_MOUSEMOVE:
#if CYGMULTIWINDOW_DEBUG && 0
        winDebug("winMWExtWMWindowProc - WM_MOUSEMOVE\n");
#endif
        /* Unpack the client area mouse coordinates */
        ptMouse.x = GET_X_LPARAM(lParam);
        ptMouse.y = GET_Y_LPARAM(lParam);

        /* Translate the client area mouse coordinates to screen coordinates */
        ClientToScreen(hwnd, &ptMouse);

        /* Screen Coords from (-X, -Y) -> Root Window (0, 0) */
        ptMouse.x -= GetSystemMetrics(SM_XVIRTUALSCREEN);
        ptMouse.y -= GetSystemMetrics(SM_YVIRTUALSCREEN);

        /* We can't do anything without privates */
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;

        /* Has the mouse pointer crossed screens? */
        if (pScreen != miPointerGetScreen(inputInfo.pointer))
             miPointerSetScreen(inputInfo.pointer, pScreenInfo->dwScreen,
                                ptMouse.x - pScreenInfo->dwXOffset,
                                ptMouse.y - pScreenInfo->dwYOffset);

        /* Are we tracking yet? */
        if (!s_fTracking) {
            TRACKMOUSEEVENT tme;

            /* Setup data structure */
            ZeroMemory(&tme, sizeof(tme));
            tme.cbSize = sizeof(tme);
            tme.dwFlags = TME_LEAVE;
            tme.hwndTrack = hwnd;

            /* Call the tracking function */
            if (!TrackMouseEvent(&tme))
                ErrorF("winMWExtWMWindowProc - TrackMouseEvent failed\n");

            /* Flag that we are tracking now */
            s_fTracking = TRUE;
        }

        /* Kill the timer used to poll mouse events */
        if (g_uipMousePollingTimerID != 0) {
            KillTimer(pScreenPriv->hwndScreen, WIN_POLLING_MOUSE_TIMER_ID);
            g_uipMousePollingTimerID = 0;
        }

        /* Deliver absolute cursor position to X Server */
        winEnqueueMotion(ptMouse.x - pScreenInfo->dwXOffset,
                         ptMouse.y - pScreenInfo->dwYOffset);

        return 0;

    case WM_NCMOUSEMOVE:
#if CYGMULTIWINDOW_DEBUG && 0
        winDebug("winMWExtWMWindowProc - WM_NCMOUSEMOVE\n");
#endif
        /*
         * We break instead of returning 0 since we need to call
         * DefWindowProc to get the mouse cursor changes
         * and min/max/close button highlighting in Windows XP.
         * The Platform SDK says that you should return 0 if you
         * process this message, but it fails to mention that you
         * will give up any default functionality if you do return 0.
         */

        /* We can't do anything without privates */
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;

        /*
         * Timer to poll mouse events.  This is needed to make
         * programs like xeyes follow the mouse properly.
         */
        if (g_uipMousePollingTimerID == 0)
            g_uipMousePollingTimerID = SetTimer(pScreenPriv->hwndScreen,
                                                WIN_POLLING_MOUSE_TIMER_ID,
                                                MOUSE_POLLING_INTERVAL, NULL);
        break;

    case WM_MOUSELEAVE:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_MOUSELEAVE\n");
#endif
        /* Mouse has left our client area */

        /* Flag that we are no longer tracking */
        s_fTracking = FALSE;

        /*
         * Timer to poll mouse events.  This is needed to make
         * programs like xeyes follow the mouse properly.
         */
        if (g_uipMousePollingTimerID == 0)
            g_uipMousePollingTimerID = SetTimer(pScreenPriv->hwndScreen,
                                                WIN_POLLING_MOUSE_TIMER_ID,
                                                MOUSE_POLLING_INTERVAL, NULL);
        return 0;

    case WM_LBUTTONDBLCLK:
    case WM_LBUTTONDOWN:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_LBUTTONDBLCLK\n");
#endif
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;
        SetCapture(hwnd);
        return winMouseButtonsHandle(pScreen, ButtonPress, Button1, wParam);

    case WM_LBUTTONUP:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_LBUTTONUP\n");
#endif
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;
        ReleaseCapture();
        return winMouseButtonsHandle(pScreen, ButtonRelease, Button1, wParam);

    case WM_MBUTTONDBLCLK:
    case WM_MBUTTONDOWN:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_MBUTTONDBLCLK\n");
#endif
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;
        SetCapture(hwnd);
        return winMouseButtonsHandle(pScreen, ButtonPress, Button2, wParam);

    case WM_MBUTTONUP:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_MBUTTONUP\n");
#endif
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;
        ReleaseCapture();
        return winMouseButtonsHandle(pScreen, ButtonRelease, Button2, wParam);

    case WM_RBUTTONDBLCLK:
    case WM_RBUTTONDOWN:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_RBUTTONDBLCLK\n");
#endif
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;
        SetCapture(hwnd);
        return winMouseButtonsHandle(pScreen, ButtonPress, Button3, wParam);

    case WM_RBUTTONUP:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_RBUTTONUP\n");
#endif
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;
        ReleaseCapture();
        return winMouseButtonsHandle(pScreen, ButtonRelease, Button3, wParam);

    case WM_XBUTTONDBLCLK:
    case WM_XBUTTONDOWN:
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;
        SetCapture(hwnd);
        return winMouseButtonsHandle(pScreen, ButtonPress, HIWORD(wParam) + 5,
                                     wParam);
    case WM_XBUTTONUP:
        if (pScreenPriv == NULL || pScreenInfo->fIgnoreInput)
            break;
        ReleaseCapture();
        return winMouseButtonsHandle(pScreen, ButtonRelease, HIWORD(wParam) + 5,
                                     wParam);

    case WM_MOUSEWHEEL:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_MOUSEWHEEL\n");
#endif

        /* Pass the message to the root window */
        SendMessage(hwndScreen, message, wParam, lParam);
        return 0;

    case WM_MOUSEACTIVATE:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_MOUSEACTIVATE\n");
#endif
#if 1
        /* Check if this window needs to be made active when clicked */
        if (winIsInternalWMRunning(pScreenInfo) && pWin->overrideRedirect) {
#if CYGMULTIWINDOW_DEBUG
            winDebug("winMWExtWMWindowProc - WM_MOUSEACTIVATE - "
                     "MA_NOACTIVATE\n");
#endif

            /* */
            return MA_NOACTIVATE;
        }
#endif
        if (!winIsInternalWMRunning(pScreenInfo) && !IsMouseActive(pWin))
            return MA_NOACTIVATE;

        break;

    case WM_KILLFOCUS:
        /* Pop any pressed keys since we are losing keyboard focus */
        winKeybdReleaseKeys();
        return 0;

    case WM_SYSDEADCHAR:
    case WM_DEADCHAR:
        /*
         * NOTE: We do nothing with WM_*CHAR messages,
         * nor does the root window, so we can just toss these messages.
         */
        return 0;

    case WM_SYSKEYDOWN:
    case WM_KEYDOWN:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_*KEYDOWN\n");
#endif

        /*
         * Don't pass Alt-F4 key combo to root window,
         * let Windows translate to WM_CLOSE and close this top-level window.
         *
         * NOTE: We purposely don't check the fUseWinKillKey setting because
         * it should only apply to the key handling for the root window,
         * not for top-level window-manager windows.
         *
         * ALSO NOTE: We do pass Ctrl-Alt-Backspace to the root window
         * because that is a key combo that no X app should be expecting to
         * receive, since it has historically been used to shutdown the X server.
         * Passing Ctrl-Alt-Backspace to the root window preserves that
         * behavior, assuming that -unixkill has been passed as a parameter.
         */
        if (wParam == VK_F4 && (GetKeyState(VK_MENU) & 0x8000))
            break;

        /* Pass the message to the root window */
        SendMessage(hwndScreen, message, wParam, lParam);
        return 0;

    case WM_SYSKEYUP:
    case WM_KEYUP:

#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_*KEYUP\n");
#endif

        /* Pass the message to the root window */
        SendMessage(hwndScreen, message, wParam, lParam);
        return 0;

    case WM_HOTKEY:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_HOTKEY\n");
#endif

        /* Pass the message to the root window */
        SendMessage(hwndScreen, message, wParam, lParam);
        return 0;

    case WM_ERASEBKGND:
#if CYGDEBUG
        winDebug("winMWExtWMWindowProc - WM_ERASEBKGND\n");
#endif
        /*
         * Pretend that we did erase the background but we don't care,
         * since we repaint the entire region anyhow
         * This avoids some flickering when resizing.
         */
        return TRUE;

    case WM_PAINT:

        /* BeginPaint gives us an hdc that clips to the invalidated region */
        hdcUpdate = BeginPaint(hwnd, &ps);

        /* Try to copy from the shadow buffer */
        if (!BitBlt(hdcUpdate,
                    ps.rcPaint.left, ps.rcPaint.top,
                    ps.rcPaint.right - ps.rcPaint.left,
                    ps.rcPaint.bottom - ps.rcPaint.top,
                    pRLWinPriv->hdcShadow,
                    ps.rcPaint.left, ps.rcPaint.top, SRCCOPY)) {
            LPVOID lpMsgBuf;

            /* Display a fancy error message */
            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                          FORMAT_MESSAGE_FROM_SYSTEM |
                          FORMAT_MESSAGE_IGNORE_INSERTS,
                          NULL,
                          GetLastError(),
                          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                          (LPTSTR) &lpMsgBuf, 0, NULL);

            ErrorF("winMWExtWMWindowProc - BitBlt failed: %s\n",
                   (LPSTR) lpMsgBuf);
            LocalFree(lpMsgBuf);
        }

        /* EndPaint frees the DC */
        EndPaint(hwnd, &ps);
        break;

    case WM_ACTIVATE:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_ACTIVATE\n");
#endif
        if (LOWORD(wParam) != WA_INACTIVE) {
            if (winIsInternalWMRunning(pScreenInfo)) {
#if 0
                /* Raise the window to the top in Z order */
                wmMsg.msg = WM_WM_RAISE;
                if (fWMMsgInitialized)
                    winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg);
#endif
                /* Tell our Window Manager thread to activate the window */
                wmMsg.msg = WM_WM_ACTIVATE;
                if (fWMMsgInitialized)
                    if (!pWin || !pWin->overrideRedirect)       /* for OOo menus */
                        winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg);
            }
            winWindowsWMSendEvent(WindowsWMControllerNotify,
                                  WindowsWMControllerNotifyMask,
                                  1,
                                  WindowsWMActivateWindow,
                                  pWin->drawable.id, 0, 0, 0, 0);
        }
        return 0;

#if 1
    case WM_WINDOWPOSCHANGING:
        pWinPos = (LPWINDOWPOS) lParam;
        if (!(pWinPos->flags & SWP_NOZORDER)) {
            if (pRLWinPriv->fRestackingNow || pScreenPriv->fRestacking) {
#if CYGMULTIWINDOW_DEBUG
                winDebug("Win %08x is now restacking.\n",
                         (unsigned int) pRLWinPriv);
#endif
                break;
            }

            if (winIsInternalWMRunning(pScreenInfo) || IsRaiseOnClick(pWin)) {
#if CYGMULTIWINDOW_DEBUG
                winDebug("Win %08x has WINDOWSWM_RAISE_ON_CLICK.\n",
                         (unsigned int) pRLWinPriv);
#endif
                break;
            }

#if CYGMULTIWINDOW_DEBUG
            winDebug("Win %08x forbid to change z order (%08x).\n",
                     (unsigned int) pRLWinPriv,
                     (unsigned int) pWinPos->hwndInsertAfter);
#endif
            pWinPos->flags |= SWP_NOZORDER;
        }
        break;
#endif

    case WM_MOVE:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_MOVE - %d ms\n",
                 (unsigned int) GetTickCount());
#endif
        if (g_fNoConfigureWindow)
            break;
#if 0
        /* Bail if Windows window is not actually moving */
        if (pRLWinPriv->dwX == (short) LOWORD(lParam)
            && pRLWinPriv->dwY == (short) HIWORD(lParam))
            break;

        /* Also bail if we're maximizing, we'll do the whole thing in WM_SIZE */
        {
            WINDOWPLACEMENT windPlace;

            windPlace.length = sizeof(WINDOWPLACEMENT);

            /* Get current window placement */
            GetWindowPlacement(hwnd, &windPlace);

            /* Bail if maximizing */
            if (windPlace.showCmd == SW_MAXIMIZE
                || windPlace.showCmd == SW_SHOWMAXIMIZED)
                break;
        }
#endif

#if CYGMULTIWINDOW_DEBUG
        winDebug("\t(%d, %d)\n", (short) LOWORD(lParam),
                 (short) HIWORD(lParam));
#endif
        if (!pRLWinPriv->fMovingOrSizing) {
            if (winIsInternalWMRunning(pScreenInfo))
                winAdjustXWindow(pWin, hwnd);

            winMWExtWMMoveXWindow(pWin, (LOWORD(lParam) - wBorderWidth(pWin)
                                         - GetSystemMetrics(SM_XVIRTUALSCREEN)),
                                  (HIWORD(lParam) - wBorderWidth(pWin)
                                   - GetSystemMetrics(SM_YVIRTUALSCREEN)));
        }
        return 0;

    case WM_SHOWWINDOW:
#if CYGMULTIWINDOW_DEBUG || TRUE
        winDebug("winMWExtWMWindowProc - WM_SHOWWINDOW - %d ms\n",
                 (unsigned int) GetTickCount());
#endif
        /* Bail out if the window is being hidden */
        if (!wParam)
            return 0;

        if (!pScreenInfo->fInternalWM)  //XXXX
            return 0;

        winMWExtWMUpdateWindowDecoration(pRLWinPriv, pScreenInfo);

        if (winIsInternalWMRunning(pScreenInfo)) {
#if CYGMULTIWINDOW_DEBUG || TRUE
            winDebug("\tMapWindow\n");
#endif
            /* Tell X to map the window */
            MapWindow(pWin, wClient(pWin));

            if (!pRLWinPriv->pFrame->win->overrideRedirect)
                /* Bring the Windows window to the foreground */
                SetForegroundWindow(hwnd);

            /* Setup the Window Manager message */
            wmMsg.msg = WM_WM_MAP;
            wmMsg.iWidth = pRLWinPriv->pFrame->width;
            wmMsg.iHeight = pRLWinPriv->pFrame->height;

            /* Tell our Window Manager thread to map the window */
            if (fWMMsgInitialized)
                winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg);
        }
        break;

    case WM_SIZING:
        /* Need to legalize the size according to WM_NORMAL_HINTS */
        /* for applications like xterm */
        return ValidateSizing(hwnd, pWin, wParam, lParam);

    case WM_WINDOWPOSCHANGED:
    {
        pWinPos = (LPWINDOWPOS) lParam;
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_WINDOWPOSCHANGED\n");
        winDebug("\tflags: %s%s%s%s%s%s%s%s%s%s%s%s\n",
                 (pWinPos->flags & SWP_DRAWFRAME) ? "SWP_DRAWFRAME " : "",
                 (pWinPos->flags & SWP_FRAMECHANGED) ? "SWP_FRAMECHANGED " : "",
                 (pWinPos->flags & SWP_HIDEWINDOW) ? "SWP_HIDEWINDOW " : "",
                 (pWinPos->flags & SWP_NOACTIVATE) ? "SWP_NOACTIVATE " : "",
                 (pWinPos->flags & SWP_NOCOPYBITS) ? "SWP_NOCOPYBITS " : "",
                 (pWinPos->flags & SWP_NOMOVE) ? "SWP_NOMOVE " : "",
                 (pWinPos->
                  flags & SWP_NOOWNERZORDER) ? "SWP_NOOWNERZORDER " : "",
                 (pWinPos->flags & SWP_NOSIZE) ? "SWP_NOSIZE " : "",
                 (pWinPos->flags & SWP_NOREDRAW) ? "SWP_NOREDRAW " : "",
                 (pWinPos->
                  flags & SWP_NOSENDCHANGING) ? "SWP_NOSENDCHANGING " : "",
                 (pWinPos->flags & SWP_NOZORDER) ? "SWP_NOZORDER " : "",
                 (pWinPos->flags & SWP_SHOWWINDOW) ? "SWP_SHOWWINDOW " : "");
        winDebug("\tno_configure: %s\n", (g_fNoConfigureWindow ? "Yes" : "No"));
        winDebug("\textend: (%d, %d, %d, %d)\n",
                 pWinPos->x, pWinPos->y, pWinPos->cx, pWinPos->cy);

#endif
        if (pWinPos->flags & SWP_HIDEWINDOW)
            break;

        /* Reorder if window z order was changed */
        if ((pScreenPriv != NULL)
            && !(pWinPos->flags & SWP_NOZORDER)
            && !(pWinPos->flags & SWP_SHOWWINDOW)
            && winIsInternalWMRunning(pScreenInfo)) {
#if CYGMULTIWINDOW_DEBUG
            winDebug("\twindow z order was changed\n");
#endif
            if (pWinPos->hwndInsertAfter == HWND_TOP
                || pWinPos->hwndInsertAfter == HWND_TOPMOST
                || pWinPos->hwndInsertAfter == HWND_NOTOPMOST) {
#if CYGMULTIWINDOW_DEBUG
                winDebug("\traise to top\n");
#endif
                /* Raise the window to the top in Z order */
                wmMsg.msg = WM_WM_RAISE;
                if (fWMMsgInitialized)
                    winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg);
            }
#if 1
            else if (pWinPos->hwndInsertAfter == HWND_BOTTOM) {
            }
            else {
                /* Check if this window is top of X windows. */
                HWND hWndAbove = NULL;
                DWORD dwCurrentProcessID = GetCurrentProcessId();
                DWORD dwWindowProcessID = 0;

                for (hWndAbove = pWinPos->hwndInsertAfter;
                     hWndAbove != NULL;
                     hWndAbove = GetNextWindow(hWndAbove, GW_HWNDPREV)) {
                    /* Ignore other XWin process's window */
                    GetWindowThreadProcessId(hWndAbove, &dwWindowProcessID);

                    if ((dwWindowProcessID == dwCurrentProcessID)
                        && GetProp(hWndAbove, WIN_WINDOW_PROP)
                        && !IsWindowVisible(hWndAbove)
                        && !IsIconic(hWndAbove))        /* ignore minimized windows */
                        break;
                }
                /* If this is top of X windows in Windows stack,
                   raise it in X stack. */
                if (hWndAbove == NULL) {
#if CYGMULTIWINDOW_DEBUG
                    winDebug("\traise to top\n");
#endif
                    /* Raise the window to the top in Z order */
                    wmMsg.msg = WM_WM_RAISE;
                    if (fWMMsgInitialized)
                        winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg);
                }
            }
#endif
        }

        if (!(pWinPos->flags & SWP_NOSIZE)) {
            if (IsIconic(hwnd)) {
#if CYGMULTIWINDOW_DEBUG
                winDebug("\tIconic -> MINIMIZED\n");
#endif
                if (winIsInternalWMRunning(pScreenInfo)) {
                    /* Raise the window to the top in Z order */
                    wmMsg.msg = WM_WM_LOWER;
                    if (fWMMsgInitialized)
                        winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg);
                }
                winWindowsWMSendEvent(WindowsWMControllerNotify,
                                      WindowsWMControllerNotifyMask,
                                      1,
                                      WindowsWMMinimizeWindow,
                                      pWin->drawable.id, 0, 0, 0, 0);
            }
            else if (IsZoomed(hwnd)) {
#if CYGMULTIWINDOW_DEBUG
                winDebug("\tZoomed -> MAXIMIZED\n");
#endif
                winWindowsWMSendEvent(WindowsWMControllerNotify,
                                      WindowsWMControllerNotifyMask,
                                      1,
                                      WindowsWMMaximizeWindow,
                                      pWin->drawable.id, 0, 0, 0, 0);
            }
            else {
#if CYGMULTIWINDOW_DEBUG
                winDebug("\tnone -> RESTORED\n");
#endif
                winWindowsWMSendEvent(WindowsWMControllerNotify,
                                      WindowsWMControllerNotifyMask,
                                      1,
                                      WindowsWMRestoreWindow,
                                      pWin->drawable.id, 0, 0, 0, 0);
            }
        }
        if (!g_fNoConfigureWindow) {

            if (!pRLWinPriv->fMovingOrSizing
                /*&& (pWinPos->flags & SWP_SHOWWINDOW) */ ) {
                GetClientRect(hwnd, &rcClient);
                MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT) &rcClient, 2);

                if (!(pWinPos->flags & SWP_NOMOVE)
                    && !(pWinPos->flags & SWP_NOSIZE)) {
#if CYGMULTIWINDOW_DEBUG
                    winDebug("\tmove & resize\n");
#endif
                    if (winIsInternalWMRunning(pScreenInfo))
                        winAdjustXWindow(pWin, hwnd);

                    winMWExtWMMoveResizeXWindow(pWin,
                                                rcClient.left -
                                                wBorderWidth(pWin)
                                                -
                                                GetSystemMetrics
                                                (SM_XVIRTUALSCREEN),
                                                rcClient.top -
                                                wBorderWidth(pWin)
                                                -
                                                GetSystemMetrics
                                                (SM_YVIRTUALSCREEN),
                                                rcClient.right - rcClient.left -
                                                wBorderWidth(pWin) * 2,
                                                rcClient.bottom - rcClient.top -
                                                wBorderWidth(pWin) * 2);
                }
                else if (!(pWinPos->flags & SWP_NOMOVE)) {
#if CYGMULTIWINDOW_DEBUG
                    winDebug("\tmove\n");
#endif
                    if (winIsInternalWMRunning(pScreenInfo))
                        winAdjustXWindow(pWin, hwnd);

                    winMWExtWMMoveResizeXWindow(pWin,
                                                rcClient.left -
                                                wBorderWidth(pWin)
                                                -
                                                GetSystemMetrics
                                                (SM_XVIRTUALSCREEN),
                                                rcClient.top -
                                                wBorderWidth(pWin)
                                                -
                                                GetSystemMetrics
                                                (SM_YVIRTUALSCREEN),
                                                rcClient.right - rcClient.left -
                                                wBorderWidth(pWin) * 2,
                                                rcClient.bottom - rcClient.top -
                                                wBorderWidth(pWin) * 2);
                }
                else if (!(pWinPos->flags & SWP_NOMOVE)) {
#if CYGMULTIWINDOW_DEBUG
                    winDebug("\tmove\n");
#endif
                    if (winIsInternalWMRunning(pScreenInfo))
                        winAdjustXWindow(pWin, hwnd);

                    winMWExtWMMoveXWindow(pWin,
                                          rcClient.left - wBorderWidth(pWin)
                                          - GetSystemMetrics(SM_XVIRTUALSCREEN),
                                          rcClient.top - wBorderWidth(pWin)
                                          -
                                          GetSystemMetrics(SM_YVIRTUALSCREEN));
                }
                else if (!(pWinPos->flags & SWP_NOSIZE)) {
#if CYGMULTIWINDOW_DEBUG
                    winDebug("\tresize\n");
#endif
                    if (winIsInternalWMRunning(pScreenInfo))
                        winAdjustXWindow(pWin, hwnd);

                    winMWExtWMResizeXWindow(pWin,
                                            rcClient.right - rcClient.left
                                            - wBorderWidth(pWin) * 2,
                                            rcClient.bottom - rcClient.top
                                            - wBorderWidth(pWin) * 2);
                }
            }
        }
    }
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_WINDOWPOSCHANGED - done.\n");
#endif
        return 0;

    case WM_SIZE:
        /* see dix/window.c */
        /* FIXME: Maximize/Restore? */
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_SIZE - %d ms\n",
                 (unsigned int) GetTickCount());
#endif
#if CYGMULTIWINDOW_DEBUG
        winDebug("\t(%d, %d) %d\n", (short) LOWORD(lParam),
                 (short) HIWORD(lParam), g_fNoConfigureWindow);
#endif
        if (g_fNoConfigureWindow)
            break;

        /* Branch on type of resizing occurring */
        switch (wParam) {
        case SIZE_MINIMIZED:
#if CYGMULTIWINDOW_DEBUG
            winDebug("\tSIZE_MINIMIZED\n");
#endif
            if (winIsInternalWMRunning(pScreenInfo)) {
                /* Raise the window to the top in Z order */
                wmMsg.msg = WM_WM_LOWER;
                if (fWMMsgInitialized)
                    winSendMessageToWM(pScreenPriv->pWMInfo, &wmMsg);
            }
            winWindowsWMSendEvent(WindowsWMControllerNotify,
                                  WindowsWMControllerNotifyMask,
                                  1,
                                  WindowsWMMinimizeWindow,
                                  pWin->drawable.id,
                                  0, 0, LOWORD(lParam), HIWORD(lParam));
            break;

        case SIZE_RESTORED:
#if CYGMULTIWINDOW_DEBUG
            winDebug("\tSIZE_RESTORED\n");
#endif
            winWindowsWMSendEvent(WindowsWMControllerNotify,
                                  WindowsWMControllerNotifyMask,
                                  1,
                                  WindowsWMRestoreWindow,
                                  pWin->drawable.id,
                                  0, 0, LOWORD(lParam), HIWORD(lParam));
            break;

        case SIZE_MAXIMIZED:
#if CYGMULTIWINDOW_DEBUG
            winDebug("\tSIZE_MAXIMIZED\n");
#endif
            winWindowsWMSendEvent(WindowsWMControllerNotify,
                                  WindowsWMControllerNotifyMask,
                                  1,
                                  WindowsWMMaximizeWindow,
                                  pWin->drawable.id,
                                  0, 0, LOWORD(lParam), HIWORD(lParam));
            break;
        }

        /* Perform the resize and notify the X client */
        if (!pRLWinPriv->fMovingOrSizing) {
            if (winIsInternalWMRunning(pScreenInfo))
                winAdjustXWindow(pWin, hwnd);

            winMWExtWMResizeXWindow(pWin, (short) LOWORD(lParam)
                                    - wBorderWidth(pWin) * 2,
                                    (short) HIWORD(lParam)
                                    - wBorderWidth(pWin) * 2);
        }
        break;

    case WM_ACTIVATEAPP:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_ACTIVATEAPP - %d ms\n",
                 (unsigned int) GetTickCount());
#endif
        if (wParam) {
            if (winIsInternalWMRunning(pScreenInfo)) {
            }
            else {
            }
            winWindowsWMSendEvent(WindowsWMActivationNotify,
                                  WindowsWMActivationNotifyMask,
                                  1,
                                  WindowsWMIsActive,
                                  pWin->drawable.id, 0, 0, 0, 0);
        }
        else {
            winWindowsWMSendEvent(WindowsWMActivationNotify,
                                  WindowsWMActivationNotifyMask,
                                  1,
                                  WindowsWMIsInactive,
                                  pWin->drawable.id, 0, 0, 0, 0);
        }
        break;

    case WM_SETCURSOR:
        if (LOWORD(lParam) == HTCLIENT) {
            if (!g_fSoftwareCursor)
                SetCursor(pScreenPriv->cursor.handle);
            return TRUE;
        }
        break;

    case WM_ENTERSIZEMOVE:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_ENTERSIZEMOVE - %d ms\n",
                 (unsigned int) GetTickCount());
#endif
        pRLWinPriv->fMovingOrSizing = TRUE;
        break;

    case WM_EXITSIZEMOVE:
#if CYGMULTIWINDOW_DEBUG
        winDebug("winMWExtWMWindowProc - WM_EXITSIZEMOVE - %d ms\n",
                 (unsigned int) GetTickCount());
#endif
        pRLWinPriv->fMovingOrSizing = FALSE;

        GetClientRect(hwnd, &rcClient);

        MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT) &rcClient, 2);

        if (winIsInternalWMRunning(pScreenInfo))
            winAdjustXWindow(pWin, hwnd);

        winMWExtWMMoveResizeXWindow(pWin, rcClient.left - wBorderWidth(pWin)
                                    - GetSystemMetrics(SM_XVIRTUALSCREEN),
                                    rcClient.top - wBorderWidth(pWin)
                                    - GetSystemMetrics(SM_YVIRTUALSCREEN),
                                    rcClient.right - rcClient.left
                                    - wBorderWidth(pWin) * 2,
                                    rcClient.bottom - rcClient.top
                                    - wBorderWidth(pWin) * 2);
        break;

    case WM_MANAGE:
        ErrorF("winMWExtWMWindowProc - WM_MANAGE\n");
        break;

    case WM_UNMANAGE:
        ErrorF("winMWExtWMWindowProc - WM_UNMANAGE\n");
        break;

    default:
        break;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}
コード例 #3
0
LRESULT CALLBACK
winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    POINT ptMouse;
    HDC hdcUpdate;
    PAINTSTRUCT ps;
    WindowPtr pWin = NULL;
    winPrivWinPtr pWinPriv = NULL;
    ScreenPtr s_pScreen = NULL;
    winPrivScreenPtr s_pScreenPriv = NULL;
    winScreenInfo *s_pScreenInfo = NULL;
    HWND hwndScreen = NULL;
    DrawablePtr pDraw = NULL;
    winWMMessageRec wmMsg;
    Bool fWMMsgInitialized = FALSE;
    static Bool s_fTracking = FALSE;
    Bool needRestack = FALSE;
    LRESULT ret;
    static Bool	hasEnteredSizeMove = FALSE;

    winDebugWin32Message("winTopLevelWindowProc", hwnd, message, wParam,
                         lParam);

    /* Check if the Windows window property for our X window pointer is valid */
    if ((pWin = GetProp(hwnd, WIN_WINDOW_PROP)) != NULL) {
        /* Our X window pointer is valid */

        /* Get pointers to the drawable and the screen */
        pDraw = &pWin->drawable;
        s_pScreen = pWin->drawable.pScreen;

        /* Get a pointer to our window privates */
        pWinPriv = winGetWindowPriv(pWin);

        /* Get pointers to our screen privates and screen info */
        s_pScreenPriv = pWinPriv->pScreenPriv;
        s_pScreenInfo = s_pScreenPriv->pScreenInfo;

        /* Get the handle for our screen-sized window */
        hwndScreen = s_pScreenPriv->hwndScreen;

        /* */
        wmMsg.msg = 0;
        wmMsg.hwndWindow = hwnd;
        wmMsg.iWindow = (Window) GetProp(hwnd, WIN_WID_PROP);

        wmMsg.iX = pDraw->x;
        wmMsg.iY = pDraw->y;
        wmMsg.iWidth = pDraw->width;
        wmMsg.iHeight = pDraw->height;

        fWMMsgInitialized = TRUE;

    }
#ifdef _DEBUG
    else if (message!=WM_CREATE)
    {
        winDebug("Warning: message 0x%x received when WIN_WINDOW_PROP NULL\n",message);
    }
#endif

    /* Branch on message type */
    switch (message) {
    case WM_CREATE:

        /* */
        SetProp(hwnd,
                WIN_WINDOW_PROP,
                (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams);

        /* */
        SetProp(hwnd,
                WIN_WID_PROP,
                (HANDLE) winGetWindowID(((LPCREATESTRUCT) lParam)->
                                        lpCreateParams));

        /*
         * Make X windows' Z orders sync with Windows windows because
         * there can be AlwaysOnTop windows overlapped on the window
         * currently being created.
         */
        winReorderWindowsMultiWindow();

        /* Fix a 'round title bar corner background should be transparent not black' problem when first painted */
        {
            RECT rWindow;
            HRGN hRgnWindow;

            GetWindowRect(hwnd, &rWindow);
            hRgnWindow = CreateRectRgnIndirect(&rWindow);
            SetWindowRgn(hwnd, hRgnWindow, TRUE);
        }

        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)VCXSRV_SIGNATURE);

        return 0;

    case WM_INIT_SYS_MENU:
        /*
         * Add whatever the setup file wants to for this window
         */
        SetupSysMenu((unsigned long) hwnd);
        return 0;

    case WM_SYSCOMMAND:
        /*
         * Any window menu items go through here
         */
        if (HandleCustomWM_COMMAND((unsigned long) hwnd, LOWORD(wParam))) {
            /* Don't pass customized menus to DefWindowProc */
            return 0;
        }
        if (wParam == SC_RESTORE || wParam == SC_MAXIMIZE) {
            WINDOWPLACEMENT wndpl;

            wndpl.length = sizeof(wndpl);
            if (GetWindowPlacement(hwnd, &wndpl) &&
                    wndpl.showCmd == SW_SHOWMINIMIZED)
                needRestack = TRUE;
        }
        break;

    case WM_INITMENU:
        /* Checks/Unchecks any menu items before they are displayed */
        HandleCustomWM_INITMENU((unsigned long) hwnd, wParam);
        break;

    case WM_ERASEBKGND:
        /*
         * Pretend that we did erase the background but we don't care,
         * since we repaint the entire region anyhow
         * This avoids some flickering when resizing.
         */
        return TRUE;

    case WM_PAINT:
        /* Only paint if our window handle is valid */
        if (hwndScreen == NULL)
            break;

        /* BeginPaint gives us an hdc that clips to the invalidated region */
        hdcUpdate = BeginPaint(hwnd, &ps);
        /* Avoid the BitBlt's if the PAINTSTRUCT is bogus */
        if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 &&
                ps.rcPaint.left == 0 && ps.rcPaint.top == 0) {
            EndPaint(hwnd, &ps);
            return 0;
        }

#ifdef XWIN_GLX_WINDOWS
        if (pWinPriv->fWglUsed) {
            /*
               For regions which are being drawn by GL, the shadow framebuffer doesn't have the
               correct bits, so don't bitblt from the shadow framebuffer

               XXX: For now, just leave it alone, but ideally we want to send an expose event to
               the window so it really redraws the affected region...
             */
            ValidateRect(hwnd, &(ps.rcPaint));
        }
        else
#endif
            /* Try to copy from the shadow buffer */
            if (!BitBlt(hdcUpdate,
                        ps.rcPaint.left, ps.rcPaint.top,
                        ps.rcPaint.right - ps.rcPaint.left,
                        ps.rcPaint.bottom - ps.rcPaint.top,
                        s_pScreenPriv->hdcShadow,
                        ps.rcPaint.left + pWin->drawable.x,
                        ps.rcPaint.top + pWin->drawable.y, SRCCOPY)) {
                LPVOID lpMsgBuf;

                /* Display a fancy error message */
                FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                              FORMAT_MESSAGE_FROM_SYSTEM |
                              FORMAT_MESSAGE_IGNORE_INSERTS,
                              NULL,
                              GetLastError(),
                              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                              (LPTSTR) &lpMsgBuf, 0, NULL);

                ErrorF("winTopLevelWindowProc - BitBlt failed: %s\n",
                       (LPSTR) lpMsgBuf);
                LocalFree(lpMsgBuf);
            }

        /* EndPaint frees the DC */
        EndPaint(hwnd, &ps);
        return 0;

    case WM_MOUSEMOVE:
        /* Unpack the client area mouse coordinates */
        ptMouse.x = GET_X_LPARAM(lParam);
        ptMouse.y = GET_Y_LPARAM(lParam);

        /* Translate the client area mouse coordinates to screen coordinates */
        ClientToScreen(hwnd, &ptMouse);

        /* Screen Coords from (-X, -Y) -> Root Window (0, 0) */
        ptMouse.x -= GetSystemMetrics(SM_XVIRTUALSCREEN);
        ptMouse.y -= GetSystemMetrics(SM_YVIRTUALSCREEN);

        /* We can't do anything without privates */
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /* Has the mouse pointer crossed screens? */
        if (s_pScreen != miPointerGetScreen(g_pwinPointer))
            miPointerSetScreen(g_pwinPointer, s_pScreenInfo->dwScreen,
                               ptMouse.x - s_pScreenInfo->dwXOffset,
                               ptMouse.y - s_pScreenInfo->dwYOffset);

        /* Are we tracking yet? */
        if (!s_fTracking) {
            TRACKMOUSEEVENT tme;

            /* Setup data structure */
            ZeroMemory(&tme, sizeof(tme));
            tme.cbSize = sizeof(tme);
            tme.dwFlags = TME_LEAVE;
            tme.hwndTrack = hwnd;

            /* Call the tracking function */
            if (!TrackMouseEvent(&tme))
                ErrorF("winTopLevelWindowProc - TrackMouseEvent failed\n");

            /* Flag that we are tracking now */
            s_fTracking = TRUE;
        }

        /* Hide or show the Windows mouse cursor */
        if (g_fSoftwareCursor && g_fCursor) {
            /* Hide Windows cursor */
            g_fCursor = FALSE;
            ShowCursor(FALSE);
        }

        /* Kill the timer used to poll mouse events */
        if (g_uipMousePollingTimerID != 0) {
            KillTimer(s_pScreenPriv->hwndScreen, WIN_POLLING_MOUSE_TIMER_ID);
            g_uipMousePollingTimerID = 0;
        }

        /* Deliver absolute cursor position to X Server */
        winEnqueueMotion(ptMouse.x - s_pScreenInfo->dwXOffset,
                         ptMouse.y - s_pScreenInfo->dwYOffset);

        return 0;

    case WM_NCMOUSEMOVE:
        /*
         * We break instead of returning 0 since we need to call
         * DefWindowProc to get the mouse cursor changes
         * and min/max/close button highlighting in Windows XP.
         * The Platform SDK says that you should return 0 if you
         * process this message, but it fails to mention that you
         * will give up any default functionality if you do return 0.
         */

        /* We can't do anything without privates */
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        /* Non-client mouse movement, show Windows cursor */
        if (g_fSoftwareCursor && !g_fCursor) {
            g_fCursor = TRUE;
            ShowCursor(TRUE);
        }

        winStartMousePolling(s_pScreenPriv);

        break;

    case WM_MOUSELEAVE:
        /* We can't do anything without privates */
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        /* Mouse has left our client area */

        /* Flag that we are no longer tracking */
        s_fTracking = FALSE;

        /* Show the mouse cursor, if necessary */
        if (g_fSoftwareCursor && !g_fCursor) {
            g_fCursor = TRUE;
            ShowCursor(TRUE);
        }

        winStartMousePolling(s_pScreenPriv);

        return 0;

    case WM_LBUTTONDBLCLK:
    case WM_LBUTTONDOWN:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        g_fButton[0] = TRUE;
        SetCapture(hwnd);
        return winMouseButtonsHandle(s_pScreen, ButtonPress, Button1, wParam);

    case WM_LBUTTONUP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        g_fButton[0] = FALSE;
        ReleaseCapture();
        winStartMousePolling(s_pScreenPriv);
        return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button1, wParam);

    case WM_MBUTTONDBLCLK:
    case WM_MBUTTONDOWN:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        g_fButton[1] = TRUE;
        SetCapture(hwnd);
        return winMouseButtonsHandle(s_pScreen, ButtonPress, Button2, wParam);

    case WM_MBUTTONUP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        g_fButton[1] = FALSE;
        ReleaseCapture();
        winStartMousePolling(s_pScreenPriv);
        return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button2, wParam);

    case WM_RBUTTONDBLCLK:
    case WM_RBUTTONDOWN:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        g_fButton[2] = TRUE;
        SetCapture(hwnd);
        return winMouseButtonsHandle(s_pScreen, ButtonPress, Button3, wParam);

    case WM_RBUTTONUP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        g_fButton[2] = FALSE;
        ReleaseCapture();
        winStartMousePolling(s_pScreenPriv);
        return winMouseButtonsHandle(s_pScreen, ButtonRelease, Button3, wParam);

    case WM_XBUTTONDBLCLK:
    case WM_XBUTTONDOWN:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        SetCapture(hwnd);
        return winMouseButtonsHandle(s_pScreen, ButtonPress, HIWORD(wParam) + 5,
                                     wParam);

    case WM_XBUTTONUP:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;
        ReleaseCapture();
        winStartMousePolling(s_pScreenPriv);
        return winMouseButtonsHandle(s_pScreen, ButtonRelease,
                                     HIWORD(wParam) + 5, wParam);

    case WM_MOUSEWHEEL:
        if (SendMessage
                (hwnd, WM_NCHITTEST, 0,
                 MAKELONG(GET_X_LPARAM(lParam),
                          GET_Y_LPARAM(lParam))) == HTCLIENT) {
            /* Pass the message to the root window */
            SendMessage(hwndScreen, message, wParam, lParam);
            return 0;
        }
        else
            break;

    case WM_SETFOCUS:
        if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput)
            break;

        {
            /* Get the parent window for transient handling */
            HWND hParent = GetParent(hwnd);

            if (hParent && IsIconic(hParent))
                ShowWindow(hParent, SW_RESTORE);
        }

        winRestoreModeKeyStates();

        /* Add the keyboard hook if possible */
        if (g_fKeyboardHookLL)
            g_fKeyboardHookLL = winInstallKeyboardHookLL();
        return 0;

    case WM_KILLFOCUS:
        /* Pop any pressed keys since we are losing keyboard focus */
        winKeybdReleaseKeys();

        /* Remove our keyboard hook if it is installed */
        winRemoveKeyboardHookLL();

        /* Revert the X focus as well, but only if the Windows focus is going to another window */
        if (!wParam && pWin)
            DeleteWindowFromAnyEvents(pWin, FALSE);

        return 0;

    case WM_SYSDEADCHAR:
    case WM_DEADCHAR:
        /*
         * NOTE: We do nothing with WM_*CHAR messages,
         * nor does the root window, so we can just toss these messages.
         */
        return 0;

    case WM_SYSKEYDOWN:
    case WM_KEYDOWN:

        /*
         * Don't pass Alt-F4 key combo to root window,
         * let Windows translate to WM_CLOSE and close this top-level window.
         *
         * NOTE: We purposely don't check the fUseWinKillKey setting because
         * it should only apply to the key handling for the root window,
         * not for top-level window-manager windows.
         *
         * ALSO NOTE: We do pass Ctrl-Alt-Backspace to the root window
         * because that is a key combo that no X app should be expecting to
         * receive, since it has historically been used to shutdown the X server.
         * Passing Ctrl-Alt-Backspace to the root window preserves that
         * behavior, assuming that -unixkill has been passed as a parameter.
         */
        if (wParam == VK_F4 && (GetKeyState(VK_MENU) & 0x8000))
            break;

#ifdef WINDBG
        if (wParam == VK_ESCAPE) {
            /* Place for debug: put any tests and dumps here */
            WINDOWPLACEMENT windPlace;
            RECT rc;
            LPRECT pRect;

            windPlace.length = sizeof(WINDOWPLACEMENT);
            GetWindowPlacement(hwnd, &windPlace);
            pRect = &windPlace.rcNormalPosition;
            winDebug ("\nCYGWINDOWING Dump:\n"
                      "\tdrawable: (%hd, %hd) - %hdx%hd\n", pDraw->x,
                      pDraw->y, pDraw->width, pDraw->height);
            winDebug ("\twindPlace: (%ld, %ld) - %ldx%ld\n", pRect->left,
                      pRect->top, pRect->right - pRect->left,
                      pRect->bottom - pRect->top);
            if (GetClientRect(hwnd, &rc)) {
                pRect = &rc;
                winDebug ("\tClientRect: (%ld, %ld) - %ldx%ld\n", pRect->left,
                          pRect->top, pRect->right - pRect->left,
                          pRect->bottom - pRect->top);
            }
            if (GetWindowRect(hwnd, &rc)) {
                pRect = &rc;
                winDebug ("\tWindowRect: (%ld, %ld) - %ldx%ld\n", pRect->left,
                          pRect->top, pRect->right - pRect->left,
                          pRect->bottom - pRect->top);
            }
            winDebug ("\n");
        }
#endif

        /* Pass the message to the root window */
        return winWindowProc(hwndScreen, message, wParam, lParam);

    case WM_SYSKEYUP:
    case WM_KEYUP:

        /* Pass the message to the root window */
        return winWindowProc(hwndScreen, message, wParam, lParam);

    case WM_HOTKEY:

        /* Pass the message to the root window */
        SendMessage(hwndScreen, message, wParam, lParam);
        return 0;

    case WM_ACTIVATE:

        /* Pass the message to the root window */
        SendMessage(hwndScreen, message, wParam, lParam);

        if (LOWORD(wParam) != WA_INACTIVE) {
            /* Raise the window to the top in Z order */
            /* ago: Activate does not mean putting it to front! */
            /*
               wmMsg.msg = WM_WM_RAISE;
               if (fWMMsgInitialized)
               winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
             */

            /* Tell our Window Manager thread to activate the window */
            wmMsg.msg = WM_WM_ACTIVATE;
            if (fWMMsgInitialized && pWin->realized && !pWin->overrideRedirect /* for OOo menus */)
                winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg);
        }
        /* Prevent the mouse wheel from stalling when another window is minimized */
        if (HIWORD(wParam) == 0 && LOWORD(wParam) == WA_ACTIVE &&
                (HWND) lParam != NULL && (HWND) lParam != (HWND) GetParent(hwnd))
            SetFocus(hwnd);
        return 0;

    case WM_ACTIVATEAPP:
        /*
         * This message is also sent to the root window
         * so we do nothing for individual multiwindow windows
         */
        break;

    case WM_CLOSE:
        /* Removep AppUserModelID property */
        winSetAppUserModelID(hwnd, NULL);
        /* Branch on if the window was killed in X already */
        if (pWinPriv->fXKilled) {
            /* Window was killed, go ahead and destroy the window */
            DestroyWindow(hwnd);
        }
        else {
            /* Tell our Window Manager thread to kill the window */
            wmMsg.msg = WM_WM_KILL;
            if (fWMMsgInitialized)
                winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
        }
        return 0;

    case WM_DESTROY:

        /* Branch on if the window was killed in X already */
        if (pWinPriv && !pWinPriv->fXKilled) {
            winDebug ("winTopLevelWindowProc - WM_DESTROY - WM_WM_KILL\n");

            /* Tell our Window Manager thread to kill the window */
            wmMsg.msg = WM_WM_KILL;
            if (fWMMsgInitialized)
                winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
        }

        RemoveProp(hwnd, WIN_WINDOW_PROP);
        RemoveProp(hwnd, WIN_WID_PROP);
        RemoveProp(hwnd, WIN_NEEDMANAGE_PROP);

        break;

    case WM_MOVE:
        /* Adjust the X Window to the moved Windows window */
        if (!hasEnteredSizeMove) winAdjustXWindow (pWin, hwnd);
        /* else: Wait for WM_EXITSIZEMOVE */
        return 0;

    case WM_SHOWWINDOW:
        /* Bail out if the window is being hidden */
        if (!wParam)
            return 0;

        /* */
        if (!pWin->overrideRedirect) {
            HWND zstyle = HWND_NOTOPMOST;

            /* Flag that this window needs to be made active when clicked */
            SetProp(hwnd, WIN_NEEDMANAGE_PROP, (HANDLE) 1);

            /* Set the transient style flags */
            if (GetParent(hwnd))
                SetWindowLongPtr(hwnd, GWL_STYLE,
                                 WS_POPUP | WS_OVERLAPPED | WS_SYSMENU |
                                 WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
            /* Set the window standard style flags */
            else
                SetWindowLongPtr(hwnd, GWL_STYLE,
                                 (WS_POPUP | WS_OVERLAPPEDWINDOW |
                                  WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
                                 & ~WS_CAPTION & ~WS_SIZEBOX);

            winUpdateWindowPosition(hwnd, &zstyle);

            {
                WinXWMHints hints;

                if (winMultiWindowGetWMHints(pWin, &hints)) {
                    /*
                       Give the window focus, unless it has an InputHint
                       which is FALSE (this is used by e.g. glean to
                       avoid every test window grabbing the focus)
                     */
                    if (!((hints.flags & InputHint) && (!hints.input))) {
                        SetForegroundWindow(hwnd);
                    }
                }
            }
            wmMsg.msg = WM_WM_MAP3;
        }
        else {                  /* It is an overridden window so make it top of Z stack */

            HWND forHwnd = GetForegroundWindow();
            winDebug ("overridden window is shown\n");
            if (forHwnd != NULL) {
                if (GetWindowLongPtr(forHwnd, GWLP_USERDATA) & (LONG_PTR)
                        VCXSRV_SIGNATURE) {
                    if (GetWindowLongPtr(forHwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
                        SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
                                     SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
                    else
                        SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
                                     SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
                }
            }
            wmMsg.msg = WM_WM_MAP2;
        }

        /* Tell our Window Manager thread to map the window */
        if (fWMMsgInitialized)
            winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);

        winStartMousePolling(s_pScreenPriv);

        return 0;

    case WM_SIZING:
        /* Need to legalize the size according to WM_NORMAL_HINTS */
        /* for applications like xterm */
        return ValidateSizing(hwnd, pWin, wParam, lParam);

    case WM_WINDOWPOSCHANGING:
    {
        /*
          When window is moved or resized, force it to be redrawn, so that
          any OpenGL content is re-drawn correctly, rather than copying bits
          (which seem to be wrong, either because we are copying the wrong
          window in the window heirarchy, or because we don't have the bits
          drawn by OpenGL at all)

          XXX: really this should check if any child has fWglUsed set, but
          that might be expensive to check....
         */
        if (g_fNativeGl)
        {
            LPWINDOWPOS pWinPos = (LPWINDOWPOS)lParam;
            pWinPos->flags |= SWP_NOCOPYBITS;
        }
    }
    break;

    case WM_WINDOWPOSCHANGED:
    {
        LPWINDOWPOS pWinPos = (LPWINDOWPOS) lParam;

        if (!(pWinPos->flags & SWP_NOZORDER)) {
#if CYGWINDOWING_DEBUG
            winDebug("\twindow z order was changed\n");
#endif
            if (pWinPos->hwndInsertAfter == HWND_TOP
                    || pWinPos->hwndInsertAfter == HWND_TOPMOST
                    || pWinPos->hwndInsertAfter == HWND_NOTOPMOST) {
#if CYGWINDOWING_DEBUG
                winDebug("\traise to top\n");
#endif
                /* Raise the window to the top in Z order */
                winRaiseWindow(pWin);
            }
            else if (pWinPos->hwndInsertAfter == HWND_BOTTOM) {
            }
            else {
                /* Check if this window is top of X windows. */
                HWND hWndAbove = NULL;
                DWORD dwCurrentProcessID = GetCurrentProcessId();
                DWORD dwWindowProcessID = 0;

                for (hWndAbove = pWinPos->hwndInsertAfter;
                        hWndAbove != NULL;
                        hWndAbove = GetNextWindow(hWndAbove, GW_HWNDPREV)) {
                    /* Ignore other XWin process's window */
                    GetWindowThreadProcessId(hWndAbove, &dwWindowProcessID);

                    if ((dwWindowProcessID == dwCurrentProcessID)
                            && GetProp(hWndAbove, WIN_WINDOW_PROP)
                            && !IsWindowVisible(hWndAbove)
                            && !IsIconic(hWndAbove))        /* ignore minimized windows */
                        break;
                }
                /* If this is top of X windows in Windows stack,
                   raise it in X stack. */
                if (hWndAbove == NULL) {
#if CYGWINDOWING_DEBUG
                    winDebug("\traise to top\n");
#endif
                    winRaiseWindow(pWin);
                }
            }
        }
    }
        /*
         * Pass the message to DefWindowProc to let the function
         * break down WM_WINDOWPOSCHANGED to WM_MOVE and WM_SIZE.
         */
    break;

    case WM_ENTERSIZEMOVE:
        hasEnteredSizeMove = TRUE;
        return 0;

    case WM_EXITSIZEMOVE:
        /* Adjust the X Window to the moved Windows window */
        hasEnteredSizeMove = FALSE;
        winAdjustXWindow (pWin, hwnd);
        return 0;

    case WM_SIZE:
        /* see dix/window.c */
#ifdef WINDBG
    {
        char buf[64];

        switch (wParam) {
        case SIZE_MINIMIZED:
            strcpy(buf, "SIZE_MINIMIZED");
            break;
        case SIZE_MAXIMIZED:
            strcpy(buf, "SIZE_MAXIMIZED");
            break;
        case SIZE_RESTORED:
            strcpy(buf, "SIZE_RESTORED");
            break;
        default:
            strcpy(buf, "UNKNOWN_FLAG");
        }
        winDebug ("winTopLevelWindowProc - WM_SIZE to %dx%d (%s) - %d ms\n",
                  (int) LOWORD(lParam), (int) HIWORD(lParam), buf,
                  (int) (GetTickCount()));
    }
#endif
    if (!hasEnteredSizeMove)
    {
        /* Adjust the X Window to the moved Windows window */
        winAdjustXWindow (pWin, hwnd);
        if (wParam == SIZE_MINIMIZED) winReorderWindowsMultiWindow();
    }
        /* else: wait for WM_EXITSIZEMOVE */
        return 0; /* end of WM_SIZE handler */

    case WM_STYLECHANGED:
        /* when the style changes, adjust the window size so the client area remains the same */
    {
        LONG x,y;
        DrawablePtr pDraw = &pWin->drawable;
        x =  pDraw->x - wBorderWidth(pWin);
        y = pDraw->y - wBorderWidth(pWin);
        winPositionWindowMultiWindow(pWin, x, y);
    }
    return 0;

    case WM_MOUSEACTIVATE:

        /* Check if this window needs to be made active when clicked */
        if (!GetProp(pWinPriv->hWnd, WIN_NEEDMANAGE_PROP)) {
            winDebug ("winTopLevelWindowProc - WM_MOUSEACTIVATE - "
                      "MA_NOACTIVATE\n");

            /* */
            return MA_NOACTIVATE;
        }
        break;

    case WM_SETCURSOR:
        if (LOWORD(lParam) == HTCLIENT) {
            if (!g_fSoftwareCursor)
                SetCursor(s_pScreenPriv->cursor.handle);
            return TRUE;
        }
        break;

    default:
        break;
    }

    ret = DefWindowProc(hwnd, message, wParam, lParam);
    /*
     * If the window was minized we get the stack change before the window is restored
     * and so it gets lost. Ensure there stacking order is correct.
     */
    if (needRestack)
        winReorderWindowsMultiWindow();
    return ret;
}