Sine Striker
2023-12-16 1fab480dc53e910a614d5d836993adb743d59352
src/core/contexts/win32windowcontext.cpp
@@ -27,7 +27,6 @@
#include <dwmapi.h>
#include <timeapi.h>
#include "nativeeventfilter_p.h"
#include "qwkglobal_p.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@@ -84,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);
        }
@@ -115,6 +114,7 @@
        DYNAMIC_API_DECLARE(DwmIsCompositionEnabled);
        DYNAMIC_API_DECLARE(DwmGetCompositionTimingInfo);
        DYNAMIC_API_DECLARE(DwmGetWindowAttribute);
        DYNAMIC_API_DECLARE(DwmSetWindowAttribute);
        DYNAMIC_API_DECLARE(GetDpiForWindow);
        DYNAMIC_API_DECLARE(GetSystemMetricsForDpi);
        DYNAMIC_API_DECLARE(GetDpiForMonitor);
@@ -141,6 +141,7 @@
            DYNAMIC_API_RESOLVE(dwmapi, DwmIsCompositionEnabled);
            DYNAMIC_API_RESOLVE(dwmapi, DwmGetCompositionTimingInfo);
            DYNAMIC_API_RESOLVE(dwmapi, DwmGetWindowAttribute);
            DYNAMIC_API_RESOLVE(dwmapi, DwmSetWindowAttribute);
            QSystemLibrary winmm(QStringLiteral("winmm"));
            DYNAMIC_API_RESOLVE(winmm, timeGetDevCaps);
@@ -429,8 +430,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);
    }
@@ -449,6 +450,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
@@ -635,7 +639,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 {
@@ -798,7 +802,12 @@
            case ShowSystemMenuHook: {
                const auto &pos = *static_cast<const QPoint *>(data);
                auto hWnd = reinterpret_cast<HWND>(m_windowHandle->winId());
                showSystemMenu2(hWnd, qpoint2point(pos), false,
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
                const QPoint nativeGlobalPos = QHighDpi::toNativeGlobalPosition(pos, m_windowHandle);
#else
                const QPoint nativeGlobalPos = QHighDpi::toNativePixels(pos, m_windowHandle);
#endif
                showSystemMenu2(hWnd, qpoint2point(nativeGlobalPos), false,
                                m_delegate->isHostSizeFixed(m_host));
                return;
            }
@@ -841,7 +850,7 @@
                }
                painter.save();
                // ### TODO: do we need to enable or disable it?
                // We needs anti-aliasing to give us better result.
                painter.setRenderHint(QPainter::Antialiasing);
                painter.setPen(pen);
@@ -850,6 +859,7 @@
                    QPoint{m_windowHandle->width(), 0}
                });
                painter.restore();
                return;
            }
            default: {
@@ -872,6 +882,13 @@
        // Install window hook
        auto winId = m_windowHandle->winId();
        auto hWnd = reinterpret_cast<HWND>(winId);
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
        for (const auto attr : { _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, _DWMWA_USE_IMMERSIVE_DARK_MODE }) {
            const BOOL enable = TRUE;
            DynamicApis::instance().pDwmSetWindowAttribute(hWnd, attr, &enable, sizeof(enable));
        }
#endif
        // Inform Qt we want and have set custom margins
        updateInternalWindowFrameMargins(hWnd, m_windowHandle);
@@ -933,10 +950,19 @@
            return true;
        }
        if (themeStuffHandler(hWnd, message, wParam, lParam, result)) {
            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
    }
@@ -1145,7 +1171,7 @@
                const WindowPart currentWindowPart = lastHitTestResult;
                if (message == WM_NCMOUSEMOVE) {
                    if (currentWindowPart != WindowPart::ChromeButton) {
                        m_delegate->resetQtGrabbedControl();
                        m_delegate->resetQtGrabbedControl(m_host);
                        if (mouseLeaveBlocked) {
                            emulateClientAreaMessage(hWnd, message, wParam, lParam,
                                                     WM_NCMOUSELEAVE);
@@ -1207,7 +1233,7 @@
                        // window from client area, which means we will get previous window part as
                        // HTCLIENT if the mouse leaves window from client area and enters window
                        // from non-client area, but it has no bad effect.
                        m_delegate->resetQtGrabbedControl();
                        m_delegate->resetQtGrabbedControl(m_host);
                    }
                }
                break;
@@ -1227,7 +1253,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);
                    }
@@ -1919,85 +1945,6 @@
            // entering Qt's own handling logic.
            *result = FALSE;
            return true;
        }
        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::UpdateRequest);
                dispatch(&e);
                break;
            }
            case WM_DWMCOLORIZATIONCOLORCHANGED: {
                const QColor color = QColor::fromRgba(wParam);
                const auto blendWithOpacity = *reinterpret_cast<LPBOOL>(lParam);
                QEvent e(QEvent::UpdateRequest);
                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::UpdateRequest);
                dispatch(&e);
                break;
            }
            case WM_SIZE: {
                const bool max = wParam == SIZE_MAXIMIZED;
                const bool min = wParam == SIZE_MINIMIZED;
                const bool full = isFullScreen(hWnd);
                Qt::WindowStates states{};
                if (max) {
                    states |= Qt::WindowMaximized;
                }
                if (min) {
                    states |= Qt::WindowMinimized;
                }
                if (full) {
                    states |= Qt::WindowFullScreen;
                }
                QTimer::singleShot(0, this, [this, states] {
                    QWindowStateChangeEvent e(states);
                    dispatch(&e);
                });
                break;
            }
            case WM_ACTIVATE: {
                const auto state = LOWORD(wParam);
                const bool active = state == WA_ACTIVE || state == WA_CLICKACTIVE;
                Q_UNUSED(state)
                QTimer::singleShot(0, this, [this, active] {
                    QEvent e(active ? QEvent::WindowActivate : QEvent::WindowDeactivate);
                    dispatch(&e);
                });
                break;
            }
            default:
                break;
        }
        return false;
    }