SineStriker
2023-12-27 88b5b56b6a67d93208eae3980af2f30da09dd8ae
src/core/contexts/win32windowcontext.cpp
@@ -9,7 +9,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)
@@ -26,10 +25,6 @@
#include "qwkglobal_p.h"
#include "qwkwindowsextra_p.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Q_DECLARE_METATYPE(QMargins)
#endif
namespace QWK {
@@ -51,13 +46,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
@@ -69,55 +64,6 @@
        ::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) {
        const DynamicApis &apis = DynamicApis::instance();
        if (apis.pGetDpiForWindow) {         // Win10
            return apis.pGetDpiForWindow(hwnd);
        } else if (apis.pGetDpiForMonitor) { // Win8.1
            HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
            UINT dpiX{0};
            UINT dpiY{0};
            apis.pGetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
            return dpiX;
        } else { // Win2K
            HDC hdc = ::GetDC(nullptr);
            const int dpiX = ::GetDeviceCaps(hdc, LOGPIXELSX);
            // const int dpiY = ::GetDeviceCaps(hdc, LOGPIXELSY);
            ::ReleaseDC(nullptr, hdc);
            return quint32(dpiX);
        }
    }
    static inline quint32 getSystemMetricsForDpi(int index, quint32 dpi) {
        const DynamicApis &apis = DynamicApis::instance();
        if (apis.pGetSystemMetricsForDpi) {
            return ::GetSystemMetricsForDpi(index, dpi);
        }
        return ::GetSystemMetrics(index);
    }
    static inline quint32 getWindowFrameBorderThickness(HWND hwnd) {
        const DynamicApis &apis = DynamicApis::instance();
        if (UINT result = 0; SUCCEEDED(apis.pDwmGetWindowAttribute(
                hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &result, sizeof(result)))) {
            return result;
        }
        return getSystemMetricsForDpi(SM_CXBORDER, getDpiForWindow(hwnd));
    }
    static inline quint32 getResizeBorderThickness(HWND hwnd) {
        const quint32 dpi = getDpiForWindow(hwnd);
        return getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
    }
    static inline quint32 getTitleBarHeight(HWND hwnd) {
        const quint32 dpi = getDpiForWindow(hwnd);
        return getSystemMetricsForDpi(SM_CYCAPTION, dpi) +
               getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
    }
    static void setInternalWindowFrameMargins(QWindow *window, const QMargins &margins) {
@@ -455,8 +401,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) {
@@ -473,9 +419,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
@@ -627,6 +570,7 @@
            case RaiseWindowHook: {
                if (!windowId)
                    return;
                m_delegate->setWindowVisible(m_host, true);
                const auto hwnd = reinterpret_cast<HWND>(windowId);
                bringWindowToFront(hwnd);
                return;
@@ -659,7 +603,7 @@
            }
            case DrawWindows10BorderHook: {
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
                if (!windowId)
                    return;
@@ -699,12 +643,12 @@
                    QPoint{m_windowHandle->width(), 0}
                });
                painter.restore();
                return;
#endif
                return;
            }
            case DrawWindows10BorderHook2: {
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
                if (!m_windowHandle)
                    return;
@@ -729,49 +673,35 @@
                return;
            }
                //            case AbstractWindowContext::DrawWindows10BackgroundHook: {
                // #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
                //                if (!m_windowHandle)
                //                    return;
                //
                //                auto hWnd = reinterpret_cast<HWND>(windowId);
                //                HDC hdc = ::GetDC(hWnd);
                //                RECT windowRect{};
                //                ::GetClientRect(hWnd, &windowRect);
                //                RECT rcRest = {
                //                    0,
                //                    int(getWindowFrameBorderThickness(hWnd)),
                //                    RECT_WIDTH(windowRect),
                //                    RECT_HEIGHT(windowRect),
                //                };
                //                HBRUSH blueBrush = ::CreateSolidBrush(RGB(0, 0, 255));
                //
                //                // To hide the original title bar, we have to paint on top of it
                //                with
                //                // the alpha component set to 255. This is a hack to do it with
                //                GDI.
                //                // See NonClientIslandWindow::_UpdateFrameMargins for more
                //                information. HDC opaqueDc; BP_PAINTPARAMS params =
                //                {sizeof(params), BPPF_NOCLIP | BPPF_ERASE}; auto buf =
                //                BeginBufferedPaint(hdc, &rcRest, BPBF_TOPDOWNDIB, &params,
                //                &opaqueDc); if (!buf || !opaqueDc) {
                //                    return;
                //                }
                //
                //                ::FillRect(opaqueDc, &rcRest, blueBrush);
                //                ::BufferedPaintSetAlpha(buf, nullptr, 255);
                //                ::EndBufferedPaint(buf, TRUE);
                //
                //                ::DeleteObject(blueBrush);
                //                ::ReleaseDC(hWnd, hdc);
                // #endif
                //                return;
                //            }
            default:
                break;
        }
        AbstractWindowContext::virtual_hook(id, data);
    }
    QVariant Win32WindowContext::windowAttribute(const QString &key) const {
        if (key == QStringLiteral("title-bar-rect")) {
            if (!m_windowHandle)
                return {};
            auto hwnd = reinterpret_cast<HWND>(windowId);
            RECT frame{};
            ::AdjustWindowRectExForDpi(&frame, ::GetWindowLongPtrW(hwnd, GWL_STYLE), FALSE, 0,
                                       getDpiForWindow(hwnd));
            return QVariant::fromValue(rect2qrect(frame));
        }
        if (key == QStringLiteral("win10-border-needed")) {
            return isSystemBorderEnabled() && !isWin11OrGreater();
        }
        if (key == QStringLiteral("border-thickness")) {
            return m_windowHandle
                       ? int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)))
                       : 0;
        }
        return AbstractWindowContext::windowAttribute(key);
    }
    void Win32WindowContext::winIdChanged() {
@@ -790,12 +720,13 @@
        auto hWnd = reinterpret_cast<HWND>(winId);
        if (!isSystemBorderEnabled()) {
            setWindowAttribute("extra-margins", true);
            static auto margins = QVariant::fromValue(QMargins(1, 1, 1, 1));
            setWindowAttribute(QStringLiteral("extra-margins"), margins);
        }
        {
            auto style = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
            ::SetWindowLongPtrW(hWnd, GWL_STYLE, style & (~WS_SYSMENU));
#else
            ::SetWindowLongPtrW(hWnd, GWL_STYLE,
@@ -865,17 +796,20 @@
    bool Win32WindowContext::windowAttributeChanged(const QString &key, const QVariant &attribute,
                                                    const QVariant &oldAttribute) {
        Q_UNUSED(oldAttribute)
        const auto hwnd = reinterpret_cast<HWND>(m_windowHandle->winId());
        const DynamicApis &apis = DynamicApis::instance();
        static constexpr const MARGINS defaultEmptyMargins = {0, 0, 0, 0};
        static constexpr const MARGINS defaultExtraMargins = {1, 1, 1, 1};
        static constexpr const MARGINS extendedMargins = {-1, -1, -1, -1};
        const auto &restoreMargins = [this, &apis, hwnd]() {
            auto margins = qmargins2margins(
                m_windowAttributes.value(QStringLiteral("extra-margins")).value<QMargins>());
            apis.pDwmExtendFrameIntoClientArea(hwnd, &margins);
        };
        if (key == QStringLiteral("extra-margins")) {
            if (isWin11OrGreater())
                return false;
            hasExtraMargins = attribute.toBool();
            DynamicApis::instance().pDwmExtendFrameIntoClientArea(
                hwnd, hasExtraMargins ? &defaultExtraMargins : &defaultEmptyMargins);
            auto margins = qmargins2margins(attribute.value<QMargins>());
            DynamicApis::instance().pDwmExtendFrameIntoClientArea(hwnd, &margins);
            return true;
        }
@@ -902,8 +836,6 @@
        }
        // For Win11 or later
        static const auto &defaultMargins =
            isSystemBorderEnabled() ? defaultExtraMargins : defaultEmptyMargins;
        if (key == QStringLiteral("mica")) {
            if (!isWin11OrGreater()) {
                return false;
@@ -933,7 +865,7 @@
                    const BOOL enable = FALSE;
                    apis.pDwmSetWindowAttribute(hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable));
                }
                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
                restoreMargins();
            }
            return true;
        }
@@ -955,7 +887,7 @@
                const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_AUTO;
                apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType,
                                            sizeof(backdropType));
                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
                restoreMargins();
            }
            return true;
        }
@@ -1002,7 +934,7 @@
                //     wcad.cbData = sizeof(policy);
                //     apis.pSetWindowCompositionAttribute(hwnd, &wcad);
                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
                restoreMargins();
            }
            return true;
        }
@@ -1045,7 +977,7 @@
                    bb.dwFlags = DWM_BB_ENABLE;
                    apis.pDwmEnableBlurBehindWindow(hwnd, &bb);
                }
                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
                restoreMargins();
            }
            return true;
        }
@@ -1384,12 +1316,12 @@
                                                 LPARAM lParam, LRESULT *result) {
        switch (message) {
            case WM_SHOWWINDOW: {
                if (!centered) {
                if (!initialCentered) {
                    // 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;
                        initialCentered = true;
                        moveWindowToDesktopCenter(hWnd);
                    }
                }
@@ -2080,15 +2012,6 @@
            return true;
        }
        return false;
    }
    bool Win32WindowContext::needBorderPainter() const {
        Q_UNUSED(this)
        return isSystemBorderEnabled() && !isWin11OrGreater();
    }
    int Win32WindowContext::borderThickness() const {
        return int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)));
    }
}