Sine Striker
2024-02-20 2d2fc799bc698ebf7e7c8bcc394366d0d7bf071b
src/core/contexts/win32windowcontext.cpp
@@ -1,3 +1,7 @@
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
// SPDX-License-Identifier: Apache-2.0
#include "win32windowcontext_p.h"
#include <optional>
@@ -9,7 +13,6 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QPainter>
#include <QtGui/QPalette>
#include <QtGui/QStyleHints>
#include <QtGui/private/qhighdpiscaling_p.h>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
@@ -47,13 +50,13 @@
    static WNDPROC g_qtWindowProc = nullptr;
    static inline bool
#if !QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
#if !QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
        constexpr
#endif
        isSystemBorderEnabled() {
        return
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
            isWin10OrGreater()
#else
            false
@@ -93,18 +96,6 @@
        monitorInfo.cbSize = sizeof(monitorInfo);
        ::GetMonitorInfoW(monitor, &monitorInfo);
        return monitorInfo;
    }
    static inline void moveWindowToDesktopCenter(HWND hwnd) {
        MONITORINFOEXW monitorInfo = getMonitorForWindow(hwnd);
        RECT windowRect{};
        ::GetWindowRect(hwnd, &windowRect);
        const auto newX = monitorInfo.rcMonitor.left +
                          (RECT_WIDTH(monitorInfo.rcMonitor) - RECT_WIDTH(windowRect)) / 2;
        const auto newY = monitorInfo.rcMonitor.top +
                          (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 void moveWindowToMonitor(HWND hwnd, const MONITORINFOEXW &activeMonitor) {
@@ -402,8 +393,8 @@
            return false;
        }
        static WindowsNativeEventFilter *instance;
        static Win32WindowContext *lastMessageContext;
        static inline WindowsNativeEventFilter *instance = nullptr;
        static inline Win32WindowContext *lastMessageContext = nullptr;
        static inline void install() {
            if (instance) {
@@ -420,9 +411,6 @@
            instance = nullptr;
        }
    };
    WindowsNativeEventFilter *WindowsNativeEventFilter::instance = nullptr;
    Win32WindowContext *WindowsNativeEventFilter::lastMessageContext = nullptr;
    // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025
    // We can see from the source code that Qt will filter out some messages first and then send the
@@ -563,17 +551,10 @@
    void Win32WindowContext::virtual_hook(int id, void *data) {
        switch (id) {
            case CentralizeHook: {
                if (!windowId)
                    return;
                const auto hwnd = reinterpret_cast<HWND>(windowId);
                moveWindowToDesktopCenter(hwnd);
                return;
            }
            case RaiseWindowHook: {
                if (!windowId)
                    return;
                m_delegate->setWindowVisible(m_host, true);
                const auto hwnd = reinterpret_cast<HWND>(windowId);
                bringWindowToFront(hwnd);
                return;
@@ -605,8 +586,8 @@
                return;
            }
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
            case DrawWindows10BorderHook: {
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
                if (!windowId)
                    return;
@@ -646,12 +627,10 @@
                    QPoint{m_windowHandle->width(), 0}
                });
                painter.restore();
#endif
                return;
            }
            case DrawWindows10BorderHook2: {
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
                if (!m_windowHandle)
                    return;
@@ -672,9 +651,9 @@
                ::FillRect(hdc, &rcTopBorder,
                           reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH)));
                ::ReleaseDC(hWnd, hdc);
#endif
                return;
            }
#endif
            default:
                break;
@@ -683,14 +662,22 @@
    }
    QVariant Win32WindowContext::windowAttribute(const QString &key) const {
        if (key == QStringLiteral("title-bar-rect")) {
        if (key == QStringLiteral("window-rect")) {
            if (!m_windowHandle)
                return {};
            auto hwnd = reinterpret_cast<HWND>(windowId);
            RECT frame{};
            ::AdjustWindowRectExForDpi(&frame, ::GetWindowLongPtrW(hwnd, GWL_STYLE), FALSE, 0,
                                       getDpiForWindow(hwnd));
            auto hwnd = reinterpret_cast<HWND>(windowId);
            // According to MSDN, WS_OVERLAPPED is not allowed for AdjustWindowRect.
            auto style = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_STYLE) & ~WS_OVERLAPPED);
            auto exStyle = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_EXSTYLE));
            const DynamicApis &apis = DynamicApis::instance();
            if (apis.pAdjustWindowRectExForDpi) {
                apis.pAdjustWindowRectExForDpi(&frame, style, FALSE, exStyle,
                                               getDpiForWindow(hwnd));
            } else {
                ::AdjustWindowRectEx(&frame, style, FALSE, exStyle);
            }
            return QVariant::fromValue(rect2qrect(frame));
        }
@@ -724,17 +711,23 @@
        if (!isSystemBorderEnabled()) {
            static auto margins = QVariant::fromValue(QMargins(1, 1, 1, 1));
            // If we remove the system border, the window will lose its shadow. If dwm is enabled,
            // then we need to set at least 1px margins, otherwise the following operation will
            // fail with no effect.
            setWindowAttribute(QStringLiteral("extra-margins"), margins);
        }
        // We should disable WS_SYSMENU, otherwise the system button icons will be visible if mica
        // is enabled and the title bar is transparent.
        {
            auto style = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
            ::SetWindowLongPtrW(hWnd, GWL_STYLE, style & (~WS_SYSMENU));
#else
            ::SetWindowLongPtrW(hWnd, GWL_STYLE,
                                (style | WS_THICKFRAME | WS_CAPTION) & (~WS_SYSMENU));
#endif
            if (isSystemBorderEnabled()) {
                ::SetWindowLongPtrW(hWnd, GWL_STYLE, style & (~WS_SYSMENU));
            } else {
                ::SetWindowLongPtrW(hWnd, GWL_STYLE,
                                    (style | WS_THICKFRAME | WS_CAPTION) & (~WS_SYSMENU));
            }
        }
        // Add managed window
@@ -812,8 +805,7 @@
        if (key == QStringLiteral("extra-margins")) {
            auto margins = qmargins2margins(attribute.value<QMargins>());
            DynamicApis::instance().pDwmExtendFrameIntoClientArea(hwnd, &margins);
            return true;
            return apis.pDwmExtendFrameIntoClientArea(hwnd, &margins) == S_OK;
        }
        if (key == QStringLiteral("dark-mode")) {
@@ -943,12 +935,9 @@
        }
        if (key == QStringLiteral("dwm-blur")) {
            // TODO: Optimize
            // Currently not available!!!
            if (attribute.toBool()) {
                // We need to extend the window frame into the whole client area to be able
                // to see the blurred window background.
                apis.pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
                // We can't extend the window frame for this effect.
                restoreMargins();
                if (isWin8OrGreater()) {
                    ACCENT_POLICY policy{};
                    policy.dwAccentState = ACCENT_ENABLE_BLURBEHIND;
@@ -980,7 +969,6 @@
                    bb.dwFlags = DWM_BB_ENABLE;
                    apis.pDwmEnableBlurBehindWindow(hwnd, &bb);
                }
                restoreMargins();
            }
            return true;
        }
@@ -1318,19 +1306,6 @@
    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) {
                        centered = true;
                        moveWindowToDesktopCenter(hWnd);
                    }
                }
                break;
            }
            case WM_NCHITTEST: {
                // 原生Win32窗口只有顶边是在窗口内部resize的,其余三边都是在窗口
                // 外部进行resize的,其原理是,WS_THICKFRAME这个窗口样式会在窗