Zhao Yuhang
2023-12-14 59690b8ab4f3e4c2cea0467f40e858080943dd62
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,10 +27,7 @@
#include <dwmapi.h>
#include <timeapi.h>
#include "nativeeventfilter.h"
#include "qwkglobal_p.h"
#include "win10borderhandler_p.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Q_DECLARE_METATYPE(QMargins)
@@ -85,7 +83,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);
        }
@@ -430,8 +428,8 @@
        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;
        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);
    }
@@ -450,6 +448,9 @@
        ::GetWindowPlacement(hwnd, &wp);
        return ((wp.showCmd == SW_NORMAL) || (wp.showCmd == SW_RESTORE));
#else
        if (isFullScreen(hwnd)) {
            return false;
        }
        const auto style = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_STYLE));
        return (!(style & (WS_MINIMIZE | WS_MAXIMIZE)));
#endif
@@ -636,7 +637,7 @@
    // DefWindowProc(). Consequently, we have to add a global native filter that forwards the result
    // of the hook function, telling Qt whether we have filtered the events before. Since Qt only
    // handles Windows window messages in the main thread, it is safe to do so.
    class WindowsNativeEventFilter : public NativeEventFilter {
    class WindowsNativeEventFilter : public AppNativeEventFilter {
    public:
        bool nativeEventFilter(const QByteArray &eventType, void *message,
                               QT_NATIVE_EVENT_RESULT_TYPE *result) override {
@@ -799,18 +800,58 @@
            case ShowSystemMenuHook: {
                const auto &pos = *static_cast<const QPoint *>(data);
                auto hWnd = reinterpret_cast<HWND>(m_windowHandle->winId());
                showSystemMenu2(hWnd, qpoint2point(pos), false,
                showSystemMenu2(hWnd, qpoint2point(QHighDpi::toNativeGlobalPosition(pos, m_windowHandle)), false,
                                m_delegate->isHostSizeFixed(m_host));
                return;
            }
            case DefaultColorsHook: {
                auto map = *reinterpret_cast<QMap<QString, QColor> *>(data);
                auto &map = *static_cast<QMap<QString, QColor> *>(data);
                map.clear();
                map.insert("activeLight", kWindowsColorSet.activeLight);
                map.insert("activeDark", kWindowsColorSet.activeDark);
                map.insert("inactiveLight", kWindowsColorSet.inactiveLight);
                map.insert("inactiveDark", kWindowsColorSet.inactiveDark);
                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 DrawWindows10BorderHook: {
                auto args = static_cast<void **>(data);
                auto &painter = *static_cast<QPainter *>(args[0]);
                const auto &rect = *static_cast<const QRect *>(args[1]);
                const auto &region = *static_cast<const QRegion *>(args[2]);
                const auto hwnd = reinterpret_cast<HWND>(m_windowHandle->winId());
                QPen pen;
                pen.setWidth(getWindowFrameBorderThickness(hwnd) * 2);
                const bool dark = isDarkThemeActive() && isDarkWindowFrameEnabled(hwnd);
                if (m_delegate->isWindowActive(m_host)) {
                    if (isWindowFrameBorderColorized()) {
                        pen.setColor(getAccentColor());
                    } else {
                        static QColor frameBorderActiveColorLight(kWindowsColorSet.activeLight);
                        static QColor frameBorderActiveColorDark(kWindowsColorSet.activeDark);
                        pen.setColor(dark ? frameBorderActiveColorDark
                                          : frameBorderActiveColorLight);
                    }
                } else {
                    static QColor frameBorderInactiveColorLight(kWindowsColorSet.inactiveLight);
                    static QColor frameBorderInactiveColorDark(kWindowsColorSet.inactiveDark);
                    pen.setColor(dark ? frameBorderInactiveColorDark
                                      : frameBorderInactiveColorLight);
                }
                painter.save();
                // We needs anti-aliasing to give us better result.
                painter.setRenderHint(QPainter::Antialiasing);
                painter.setPen(pen);
                painter.drawLine(QLine{
                    QPoint{0,                       0},
                    QPoint{m_windowHandle->width(), 0}
                });
                painter.restore();
                return;
            }
@@ -822,14 +863,12 @@
        AbstractWindowContext::virtual_hook(id, data);
    }
    bool Win32WindowContext::needWin10BorderHandler() const {
    bool Win32WindowContext::needBorderPainter() const {
        return isWin10OrGreater() && !isWin11OrGreater();
    }
    void Win32WindowContext::setWin10BorderHandler(Win10BorderHandler *handler) {
        win10BorderHandler.reset(handler);
        handler->setBorderThickness(
            int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId))));
    int Win32WindowContext::borderThickness() const {
        return getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId));
    }
    bool Win32WindowContext::setupHost() {
@@ -897,12 +936,25 @@
            return true;
        }
        // Forward to native event filter subscribers
        if (!m_nativeEventFilters.isEmpty()) {
            MSG msg;
            msg.hwnd = hWnd;
            msg.message = message;
            msg.wParam = wParam;
            msg.lParam = lParam;
            QT_NATIVE_EVENT_RESULT_TYPE res = 0;
            if (dispatch(QByteArrayLiteral("windows_generic_MSG"), &msg, &res)) {
                *result = LRESULT(res);
                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() {
@@ -1187,7 +1239,7 @@
                    // 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) {
                    if (wParam && !lParam) {
                        centered = true;
                        moveToDesktopCenter(hWnd);
                    }
@@ -1881,42 +1933,6 @@
            return true;
        }
        return false;
    }
    void Win10BorderHandler::paintBorder(QPainter &painter, const QRect &rect,
                                         const QRegion &region) {
        Q_UNUSED(rect)
        Q_UNUSED(region)
        QPen pen;
        pen.setWidth(m_borderThickness * 2);
        const bool dark = isDarkThemeActive() &&
                          isDarkWindowFrameEnabled(reinterpret_cast<HWND>(m_window->winId()));
        if (isActive()) {
            if (isWindowFrameBorderColorized()) {
                pen.setColor(getAccentColor());
            } else {
                static QColor frameBorderActiveColorLight(kWindowsColorSet.activeLight);
                static QColor frameBorderActiveColorDark(kWindowsColorSet.activeDark);
                pen.setColor(dark ? frameBorderActiveColorDark : frameBorderActiveColorLight);
            }
        } else {
            static QColor frameBorderInactiveColorLight(kWindowsColorSet.inactiveLight);
            static QColor frameBorderInactiveColorDark(kWindowsColorSet.inactiveDark);
            pen.setColor(dark ? frameBorderInactiveColorDark : frameBorderInactiveColorLight);
        }
        painter.save();
        // ### TODO: do we need to enable or disable it?
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setPen(pen);
        painter.drawLine(QLine{
            QPoint{0,                 0},
            QPoint{m_window->width(), 0}
        });
        painter.restore();
    }
}