SineStriker
2023-12-13 b49663c490141b75605eafa381f6c9e2c736147d
src/core/contexts/win32windowcontext.cpp
@@ -4,6 +4,7 @@
#include <QtCore/QHash>
#include <QtCore/QScopeGuard>
#include <QtCore/QTimer>
#include <QtGui/QGuiApplication>
#include <QtGui/QPainter>
#include <QtGui/QPalette>
@@ -26,7 +27,7 @@
#include <dwmapi.h>
#include <timeapi.h>
#include "nativeeventfilter.h"
#include "nativeeventfilter_p.h"
#include "qwkglobal_p.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@@ -83,7 +84,7 @@
    // ### FIXME: Tell the user to call in the documentation, instead of automatically
    // calling it directly.
    // ### FIXME FIXME FIXME
    static struct QWK_Hook {
    static const struct QWK_Hook {
        QWK_Hook() {
            qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
        }
@@ -357,44 +358,37 @@
        }
    }
    static inline quint32 getWindowFrameBorderThickness(HWND hwnd) {
        UINT result = 0;
    static inline quint32 getSystemMetricsForDpi(int index, quint32 dpi) {
        const DynamicApis &apis = DynamicApis::instance();
        if (SUCCEEDED(apis.pDwmGetWindowAttribute(hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
                                                  &result, sizeof(result)))) {
            return result;
        } else {
            const quint32 dpi = getDpiForWindow(hwnd);
            result = quint32(std::round(qreal(1) * qreal(dpi) / qreal(USER_DEFAULT_SCREEN_DPI)));
        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 DynamicApis &apis = DynamicApis::instance();
        if (apis.pGetSystemMetricsForDpi) {
            const quint32 dpi = getDpiForWindow(hwnd);
            return apis.pGetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
                   apis.pGetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
        } else {
            return ::GetSystemMetrics(SM_CXSIZEFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER);
        }
        const quint32 dpi = getDpiForWindow(hwnd);
        return getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
    }
    static inline quint32 getTitleBarHeight(HWND hwnd) {
        const auto captionHeight = [hwnd]() -> int {
            const DynamicApis &apis = DynamicApis::instance();
            if (apis.pGetSystemMetricsForDpi) {
                const quint32 dpi = getDpiForWindow(hwnd);
                return apis.pGetSystemMetricsForDpi(SM_CYCAPTION, dpi);
            } else {
                return ::GetSystemMetrics(SM_CYCAPTION);
            }
        }();
        return captionHeight + getResizeBorderThickness(hwnd);
        const quint32 dpi = getDpiForWindow(hwnd);
        return getSystemMetricsForDpi(SM_CYCAPTION, dpi) +
               getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
    }
    static inline void updateInternalWindowFrameMargins(HWND hwnd, QWindow *window) {
    static void updateInternalWindowFrameMargins(HWND hwnd, QWindow *window) {
        const auto margins = [hwnd]() -> QMargins {
            const auto titleBarHeight = int(getTitleBarHeight(hwnd));
            if (isWin10OrGreater()) {
@@ -460,7 +454,7 @@
#endif
    }
    static inline void syncPaintEventWithDwm() {
    static void syncPaintEventWithDwm() {
        // No need to sync with DWM if DWM composition is disabled.
        if (!isDwmCompositionEnabled()) {
            return;
@@ -505,9 +499,9 @@
        apis.ptimeEndPeriod(ms_granularity);
    }
    static inline void showSystemMenu2(HWND hWnd, const POINT &pos, const bool selectFirstEntry,
                                       const bool fixedSize) {
        const HMENU hMenu = ::GetSystemMenu(hWnd, FALSE);
    static void showSystemMenu2(HWND hWnd, const POINT &pos, const bool selectFirstEntry,
                                const bool fixedSize) {
        HMENU hMenu = ::GetSystemMenu(hWnd, FALSE);
        if (!hMenu) {
            // The corresponding window doesn't have a system menu, most likely due to the
            // lack of the "WS_SYSMENU" window style. This situation should not be treated
@@ -809,35 +803,17 @@
                return;
            }
            case NeedsDrawBordersHook: {
                auto &result = *static_cast<bool *>(data);
                result = isWin10OrGreater() && !isWin11OrGreater();
            case DefaultColorsHook: {
                auto &map = *static_cast<QMap<QString, QColor> *>(data);
                map.clear();
                map.insert(QStringLiteral("activeLight"), kWindowsColorSet.activeLight);
                map.insert(QStringLiteral("activeDark"), kWindowsColorSet.activeDark);
                map.insert(QStringLiteral("inactiveLight"), kWindowsColorSet.inactiveLight);
                map.insert(QStringLiteral("inactiveDark"), kWindowsColorSet.inactiveDark);
                return;
            }
            case BorderThicknessHook: {
                auto args = static_cast<void **>(data);
                const bool requireNative = *static_cast<const bool *>(args[0]);
                quint32 &thickness = *static_cast<quint32 *>(args[1]);
                const auto hwnd = reinterpret_cast<HWND>(m_windowHandle->winId());
                const auto nativeThickness = getWindowFrameBorderThickness(hwnd);
                thickness = requireNative
                                ? nativeThickness
                                : QHighDpi::fromNativePixels(nativeThickness, m_windowHandle);
                return;
            }
            case BorderColorsHook: {
                auto arr = *reinterpret_cast<QList<QColor> *>(data);
                arr.clear();
                arr.push_back(kWindowsColorSet.activeLight);
                arr.push_back(kWindowsColorSet.activeDark);
                arr.push_back(kWindowsColorSet.inactiveLight);
                arr.push_back(kWindowsColorSet.inactiveDark);
                return;
            }
            case DrawBordersHook: {
            case DrawWindows10BorderHook: {
                auto args = static_cast<void **>(data);
                auto &painter = *static_cast<QPainter *>(args[0]);
                const auto &rect = *static_cast<const QRect *>(args[1]);
@@ -845,13 +821,10 @@
                const auto hwnd = reinterpret_cast<HWND>(m_windowHandle->winId());
                QPen pen;
                const auto borderThickness = int(QHighDpi::fromNativePixels(
                    getWindowFrameBorderThickness(hwnd), m_windowHandle));
                pen.setWidth(borderThickness * 2);
                const bool active = m_delegate->isWindowActive(m_host);
                const bool dark = isDarkThemeActive() && isDarkWindowFrameEnabled(hwnd);
                pen.setWidth(getWindowFrameBorderThickness(hwnd) * 2);
                if (active) {
                const bool dark = isDarkThemeActive() && isDarkWindowFrameEnabled(hwnd);
                if (m_delegate->isWindowActive(m_host)) {
                    if (isWindowFrameBorderColorized()) {
                        pen.setColor(getAccentColor());
                    } else {
@@ -873,11 +846,10 @@
                painter.setPen(pen);
                painter.drawLine(QLine{
                    QPoint{0,            0},
                    QPoint{rect.width(), 0}
                    QPoint{0,                       0},
                    QPoint{m_windowHandle->width(), 0}
                });
                painter.restore();
                return;
            }
            default: {
@@ -886,6 +858,14 @@
            }
        }
        AbstractWindowContext::virtual_hook(id, data);
    }
    bool Win32WindowContext::needBorderPainter() const {
        return isWin10OrGreater() && !isWin11OrGreater();
    }
    int Win32WindowContext::borderThickness() const {
        return getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId));
    }
    bool Win32WindowContext::setupHost() {
@@ -953,12 +933,16 @@
            return true;
        }
        if (themeStuffHandler(hWnd, message, wParam, lParam, result)) {
            return true;
        }
        return false; // Not handled
    }
    QWK_USED static constexpr const struct {
        const WPARAM wParam = 0xF1C9ADD4;
        const LPARAM lParam = 0xAFB6F4C6;
        const WPARAM wParam = MAKEWPARAM(44500, 61897);
        const LPARAM lParam = MAKELPARAM(62662, 44982); // Not used. Reserve for future use.
    } kMessageTag;
    static inline quint64 getKeyState() {
@@ -1939,4 +1923,48 @@
        return false;
    }
    bool Win32WindowContext::themeStuffHandler(HWND hWnd, UINT message, WPARAM wParam,
                                               LPARAM lParam, LRESULT *resul) {
        switch (message) {
            case WM_DPICHANGED: {
                const auto dpiX = UINT(LOWORD(wParam));
                const auto dpiY = UINT(HIWORD(wParam));
                QEvent e(QEvent::ScreenChangeInternal);
                dispatch(&e);
                break;
            }
            case WM_THEMECHANGED:
            case WM_SYSCOLORCHANGE: {
                QEvent e(QEvent::UpdateLater);
                dispatch(&e);
                break;
            }
            case WM_DWMCOLORIZATIONCOLORCHANGED: {
                const QColor color = QColor::fromRgba(wParam);
                const auto blendedWithOpacity = *reinterpret_cast<LPBOOL>(lParam);
                QEvent e(QEvent::UpdateLater);
                dispatch(&e);
                break;
            }
            case WM_SETTINGCHANGE: {
                if (!wParam && lParam &&
                    std::wcscmp(reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0) {
                    const QColor color = getAccentColor();
                    QEvent e(QEvent::UpdateLater);
                    dispatch(&e);
                }
                break;
            }
            default:
                break;
        }
        return false;
    }
}