Sine Striker
2023-12-07 1a1f26d9e4ab6a4fe51baa78e40c4cdf3f402bcf
src/core/contexts/win32windowcontext.cpp
@@ -7,7 +7,6 @@
#include <QtCore/QAbstractNativeEventFilter>
#include <QtCore/QOperatingSystemVersion>
#include <QtCore/QScopeGuard>
#include <QtCore/QTimer>
#include <QtGui/QGuiApplication>
#include <QtCore/private/qsystemlibrary_p.h>
@@ -189,20 +188,12 @@
    }
    static inline void triggerFrameChange(HWND hwnd) {
        Q_ASSERT(hwnd);
        if (!hwnd) {
            return;
        }
        ::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
                       SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER |
                           SWP_FRAMECHANGED);
    }
    static inline quint32 getDpiForWindow(HWND hwnd) {
        Q_ASSERT(hwnd);
        if (!hwnd) {
            return 0;
        }
        const DynamicApis &apis = DynamicApis::instance();
        if (apis.pGetDpiForWindow) {         // Win10
            return apis.pGetDpiForWindow(hwnd);
@@ -222,10 +213,6 @@
    }
    static inline quint32 getResizeBorderThickness(HWND hwnd) {
        Q_ASSERT(hwnd);
        if (!hwnd) {
            return 0;
        }
        const DynamicApis &apis = DynamicApis::instance();
        if (apis.pGetSystemMetricsForDpi) {
            const quint32 dpi = getDpiForWindow(hwnd);
@@ -237,10 +224,6 @@
    }
    static inline quint32 getTitleBarHeight(HWND hwnd) {
        Q_ASSERT(hwnd);
        if (!hwnd) {
            return 0;
        }
        const auto captionHeight = [hwnd]() -> int {
            const DynamicApis &apis = DynamicApis::instance();
            if (apis.pGetSystemMetricsForDpi) {
@@ -254,11 +237,6 @@
    }
    static inline void updateInternalWindowFrameMargins(HWND hwnd, QWindow *window) {
        Q_ASSERT(hwnd);
        Q_ASSERT(window);
        if (!hwnd || !window) {
            return;
        }
        const auto margins = [hwnd]() -> QMargins {
            const int titleBarHeight = getTitleBarHeight(hwnd);
            if (isWin10OrGreater()) {
@@ -285,11 +263,7 @@
#endif
    }
    static inline std::optional<MONITORINFOEXW> getMonitorForWindow(HWND hwnd) {
        Q_ASSERT(hwnd);
        if (!hwnd) {
            return std::nullopt;
        }
    static inline MONITORINFOEXW getMonitorForWindow(HWND hwnd) {
        // Use "MONITOR_DEFAULTTONEAREST" here so that we can still get the correct
        // monitor even if the window is minimized.
        HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
@@ -299,6 +273,16 @@
        return monitorInfo;
    };
    static inline void moveToDesktopCenter(HWND hwnd) {
        const auto monitorInfo = getMonitorForWindow(hwnd);
        RECT windowRect{};
        ::GetWindowRect(hwnd, &windowRect);
        const auto newX = (RECT_WIDTH(monitorInfo.rcMonitor) - RECT_WIDTH(windowRect)) / 2;
        const auto newY = (RECT_HEIGHT(monitorInfo.rcMonitor) - RECT_HEIGHT(windowRect)) / 2;
        ::SetWindowPos(hwnd, nullptr, newX, newY, 0, 0,
                       SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
    }
    static inline bool isFullScreen(HWND hwnd) {
        Q_ASSERT(hwnd);
        if (!hwnd) {
@@ -306,9 +290,8 @@
        }
        RECT windowRect{};
        ::GetWindowRect(hwnd, &windowRect);
        const std::optional<MONITORINFOEXW> mi = getMonitorForWindow(hwnd);
        // Compare to the full area of the screen, not the work area.
        return (windowRect == mi.value_or(MONITORINFOEXW{}).rcMonitor);
        return (windowRect == getMonitorForWindow(hwnd).rcMonitor);
    }
    static inline bool isWindowNoState(HWND hwnd) {
@@ -369,7 +352,7 @@
    }
    static bool isValidWindow(HWND hWnd, bool checkVisible, bool checkTopLevel) {
        if (::IsWindow(hWnd) == FALSE) {
        if (!::IsWindow(hWnd)) {
            return false;
        }
        const LONG_PTR styles = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
@@ -380,15 +363,15 @@
        if (exStyles & WS_EX_TOOLWINDOW) {
            return false;
        }
        RECT rect = {0, 0, 0, 0};
        if (::GetWindowRect(hWnd, &rect) == FALSE) {
        RECT rect{};
        if (!::GetWindowRect(hWnd, &rect)) {
            return false;
        }
        if ((rect.left >= rect.right) || (rect.top >= rect.bottom)) {
            return false;
        }
        if (checkVisible) {
            if (::IsWindowVisible(hWnd) == FALSE) {
            if (!::IsWindowVisible(hWnd)) {
                return false;
            }
        }
@@ -521,14 +504,13 @@
        // Since Qt does the necessary processing of the WM_NCCALCSIZE afterward, we still need to
        // continue dispatching it.
        if (message != WM_NCCALCSIZE && handled) {
        if (handled && message != WM_NCCALCSIZE) {
            return result;
        }
        return ::CallWindowProcW(g_qtWindowProc, hWnd, message, wParam, lParam);
    }
    Win32WindowContext::Win32WindowContext(QObject *host, WindowItemDelegate *delegate)
        : AbstractWindowContext(host, delegate) {
    Win32WindowContext::Win32WindowContext() : AbstractWindowContext() {
    }
    Win32WindowContext::~Win32WindowContext() {
@@ -543,8 +525,8 @@
        }
    }
    bool Win32WindowContext::setup() {
        if (!m_windowHandle) {
    bool Win32WindowContext::setup(QObject *host, WindowItemDelegate *delegate) {
        if (!AbstractWindowContext::setup(host, delegate)) {
            return false;
        }
@@ -573,8 +555,6 @@
        // Save window handle mapping
        g_wndProcHash->insert(hWnd, this);
        QTimer::singleShot(0, m_windowHandle, [hWnd]() { triggerFrameChange(hWnd); });
        return true;
    }
@@ -625,7 +605,7 @@
        const auto &get = [](const int virtualKey) -> bool {
            return (::GetAsyncKeyState(virtualKey) < 0);
        };
        const bool buttonSwapped = (::GetSystemMetrics(SM_SWAPBUTTON) != FALSE);
        const bool buttonSwapped = ::GetSystemMetrics(SM_SWAPBUTTON);
        if (get(VK_LBUTTON)) {
            result |= (buttonSwapped ? MK_RBUTTON : MK_LBUTTON);
        }
@@ -896,6 +876,18 @@
    bool Win32WindowContext::customWindowHandler(HWND hWnd, UINT message, WPARAM wParam,
                                                 LPARAM lParam, LRESULT *result) {
        switch (message) {
            case WM_SHOWWINDOW: {
                if (!centered) {
                    // If wParam is TRUE, the window is being shown.
                    // If lParam is zero, the message was sent because of a call to the ShowWindow
                    // function.
                    if (wParam && lParam == 0) {
                        centered = true;
                        moveToDesktopCenter(hWnd);
                    }
                }
                break;
            }
            case WM_NCCALCSIZE: {
                // Windows是根据这个消息的返回值来设置窗口的客户区(窗口中真正显示的内容)
                // 和非客户区(标题栏、窗口边框、菜单栏和状态栏等Windows系统自行提供的部分
@@ -983,8 +975,8 @@
                // simply return 0, which means "preserve the entire old client area
                // and align it with the upper-left corner of our new client area".
                const auto clientRect =
                    ((wParam == FALSE) ? reinterpret_cast<LPRECT>(lParam)
                                       : &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam))->rgrc[0]);
                    wParam ? &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam))->rgrc[0]
                           : reinterpret_cast<LPRECT>(lParam);
                if (isWin10OrGreater()) {
                    // Store the original top margin before the default window procedure applies the
                    // default frame.
@@ -1050,9 +1042,7 @@
                        // we have to use another way to judge this if we are running
                        // on Windows 7 or Windows 8.
                        if (isWin8Point1OrGreater()) {
                            const std::optional<MONITORINFOEXW> monitorInfo =
                                getMonitorForWindow(hWnd);
                            const RECT monitorRect = monitorInfo.value().rcMonitor;
                            const RECT monitorRect = getMonitorForWindow(hWnd).rcMonitor;
                            // This helper can be used to determine if there's an
                            // auto-hide taskbar on the given edge of the monitor
                            // we're currently on.
@@ -1120,7 +1110,7 @@
                // of the upper-left non-client area. It's confirmed that this issue exists
                // from Windows 7 to Windows 10. Not tested on Windows 11 yet. Don't know
                // whether it exists on Windows XP to Windows Vista or not.
                *result = wParam == FALSE ? FALSE : WVR_REDRAW;
                *result = wParam ? WVR_REDRAW : FALSE;
                return true;
            }
            case WM_NCHITTEST: {
@@ -1274,8 +1264,6 @@
                                break;
                            case CoreWindowAgent::Close:
                                *result = HTCLOSE;
                                break;
                            case CoreWindowAgent::Unknown:
                                break;
                            default:
                                break; // unreachable
@@ -1438,10 +1426,10 @@
                        // window activation state change.
                        *result = ::DefWindowProcW(hWnd, WM_NCACTIVATE, wParam, -1);
                    } else {
                        if (wParam == FALSE) {
                            *result = TRUE;
                        } else {
                        if (wParam) {
                            *result = FALSE;
                        } else {
                            *result = TRUE;
                        }
                    }
                    return true;