From 677e7a737897e8c2a60564085821545810369e02 Mon Sep 17 00:00:00 2001
From: Sine Striker <trueful@163.com>
Date: 周一, 11 12月 2023 22:43:14 +0800
Subject: [PATCH] Widgets: Add window state handler

---
 examples/shared/widgetframe/windowbar.cpp |    9 +++-
 src/widgets/widgetwindowagent.cpp         |   37 +++++++++++++-----
 src/widgets/widgetwindowagent_p.h         |    4 +
 src/core/contexts/win32windowcontext.cpp  |   53 +++++++++++++-------------
 4 files changed, 61 insertions(+), 42 deletions(-)

diff --git a/examples/shared/widgetframe/windowbar.cpp b/examples/shared/widgetframe/windowbar.cpp
index a39ab4f..adbe0d1 100644
--- a/examples/shared/widgetframe/windowbar.cpp
+++ b/examples/shared/widgetframe/windowbar.cpp
@@ -248,23 +248,26 @@
             QLabel *label = titleLabel();
             QAbstractButton *maxBtn = maxButton();
             switch (event->type()) {
-                case QEvent::WindowIconChange:
+                case QEvent::WindowIconChange: {
                     if (d_ptr->autoIcon && iconBtn) {
                         iconBtn->setIcon(w->windowIcon());
                         iconChanged(w->windowIcon());
                     }
                     break;
-                case QEvent::WindowTitleChange:
+                }
+                case QEvent::WindowTitleChange: {
                     if (d_ptr->autoTitle && label) {
                         label->setText(w->windowTitle());
                         titleChanged(w->windowTitle());
                     }
                     break;
-                case QEvent::WindowStateChange:
+                }
+                case QEvent::WindowStateChange: {
                     if (maxBtn) {
                         maxBtn->setChecked(w->isMaximized());
                     }
                     break;
+                }
                 default:
                     break;
             }
diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp
index 56513a9..ea68c0d 100644
--- a/src/core/contexts/win32windowcontext.cpp
+++ b/src/core/contexts/win32windowcontext.cpp
@@ -749,33 +749,13 @@
             return ::DefWindowProcW(hWnd, message, wParam, lParam);
         }
 
-        switch (message) {
-            case WM_NCCALCSIZE: {
-                // Since Qt does the necessary processing of the WM_NCCALCSIZE message, we need to
-                // forward it right away and process it in our native event filter.
-                WindowsNativeEventFilter::lastMessageContext = ctx;
-                LRESULT result = ::CallWindowProcW(g_qtWindowProc, hWnd, message, wParam, lParam);
-                WindowsNativeEventFilter::lastMessageContext = nullptr;
-                return result;
-            }
-
-            case WM_WINDOWPOSCHANGING: {
-                // When toggling the "Show theme color in title bar and window border" setting in
-                // Windows Settings, or calling `DrawMenuBar()`, Windows sends a message of
-                // WM_WINDOWPOSCHANGING with flags 0x37. If we do not process this message,
-                // the client area as a whole will shift to the left, which looks very abnormal if
-                // we don't repaint it. This exception disappears if we add SWP_NOCOPYBITS flag.
-                // But I don't know what caused the problem, or why this would solve it.
-                const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam);
-                if (windowPos->flags ==
-                    (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED)) {
-                    windowPos->flags |= SWP_NOCOPYBITS;
-                }
-                return ::CallWindowProcW(g_qtWindowProc, hWnd, message, wParam, lParam);
-            }
-
-            default:
-                break;
+        // Since Qt does the necessary processing of the WM_NCCALCSIZE message, we need to
+        // forward it right away and process it in our native event filter.
+        if (message == WM_NCCALCSIZE) {
+            WindowsNativeEventFilter::lastMessageContext = ctx;
+            LRESULT result = ::CallWindowProcW(g_qtWindowProc, hWnd, message, wParam, lParam);
+            WindowsNativeEventFilter::lastMessageContext = nullptr;
+            return result;
         }
 
         // Try hooked procedure and save result
@@ -1250,6 +1230,7 @@
                 }
                 break;
             }
+
             case WM_NCHITTEST: {
                 // 鍘熺敓Win32绐楀彛鍙湁椤惰竟鏄湪绐楀彛鍐呴儴resize鐨勶紝鍏朵綑涓夎竟閮芥槸鍦ㄧ獥鍙�
                 // 澶栭儴杩涜resize鐨勶紝鍏跺師鐞嗘槸锛學S_THICKFRAME杩欎釜绐楀彛鏍峰紡浼氬湪绐�
@@ -1538,9 +1519,27 @@
                     return true;
                 }
             }
+
+            case WM_WINDOWPOSCHANGING: {
+                // ### FIXME: How does this problem happen and why is it solved?
+                // When toggling the "Show theme color in title bar and window border" setting in
+                // Windows Settings, or calling `DrawMenuBar()`, Windows sends a message of
+                // WM_WINDOWPOSCHANGING with flags 0x37. If we do not process this message,
+                // the client area as a whole will shift to the left, which looks very abnormal if
+                // we don't repaint it. This exception disappears if we add SWP_NOCOPYBITS flag.
+                // But I don't know what caused the problem, or why this would solve it.
+                const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam);
+                if (windowPos->flags ==
+                    (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED)) {
+                    windowPos->flags |= SWP_NOCOPYBITS;
+                }
+                break;
+            }
+
             default:
                 break;
         }
+
         if (!isWin10OrGreater()) {
             switch (message) {
                 case WM_NCUAHDRAWCAPTION:
diff --git a/src/widgets/widgetwindowagent.cpp b/src/widgets/widgetwindowagent.cpp
index e859fbd..578ab83 100644
--- a/src/widgets/widgetwindowagent.cpp
+++ b/src/widgets/widgetwindowagent.cpp
@@ -3,25 +3,38 @@
 
 #include <QtGui/QtEvents>
 #include <QtGui/QPainter>
+#include <QtCore/QDebug>
 
 #include "widgetitemdelegate_p.h"
 
 namespace QWK {
 
-    class WidgetPaintFilter : public QObject {
+    class WidgetBorderHandler : public QObject {
     public:
-        WidgetPaintFilter(QWidget *widget, AbstractWindowContext *ctx) : widget(widget), ctx(ctx) {
+        WidgetBorderHandler(QWidget *widget, AbstractWindowContext *ctx)
+            : widget(widget), ctx(ctx) {
             widget->installEventFilter(this);
+        }
+
+        void updateMargins() {
+            if (widget->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) {
+                widget->setContentsMargins({});
+            } else {
+                widget->setContentsMargins({0, 1, 0, 0});
+            }
         }
 
     protected:
         bool eventFilter(QObject *obj, QEvent *event) override {
             switch (event->type()) {
                 case QEvent::Paint: {
-                    auto pe = static_cast<QPaintEvent *>(event);
+                    if (widget->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen))
+                        break;
+
+                    auto paintEvent = static_cast<QPaintEvent *>(event);
                     QPainter painter(widget);
-                    QRect rect = pe->rect();
-                    QRegion region = pe->region();
+                    QRect rect = paintEvent->rect();
+                    QRegion region = paintEvent->region();
                     void *args[] = {
                         &painter,
                         &rect,
@@ -29,6 +42,11 @@
                     };
                     ctx->virtual_hook(AbstractWindowContext::DrawBordersHook, args);
                     return true;
+                }
+
+                case QEvent::WindowStateChange: {
+                    updateMargins();
+                    break;
                 }
                 default:
                     break;
@@ -79,13 +97,10 @@
         if (bool needPaintBorder = false;
             d->context->virtual_hook(AbstractWindowContext::NeedsDrawBordersHook, &needPaintBorder),
             needPaintBorder) {
-            d->paintFilter = std::make_unique<WidgetPaintFilter>(w, d->context.get());
+            auto borderHandler = std::make_unique<WidgetBorderHandler>(w, d->context.get());
+            borderHandler->updateMargins();
+            d->borderHandler = std::move(borderHandler);
         }
-
-        if (d->context->key() == "win32") {
-            w->setContentsMargins(0, 1, 0, 0);
-        }
-
         return true;
     }
 
diff --git a/src/widgets/widgetwindowagent_p.h b/src/widgets/widgetwindowagent_p.h
index 758250e..cd1e5c1 100644
--- a/src/widgets/widgetwindowagent_p.h
+++ b/src/widgets/widgetwindowagent_p.h
@@ -6,6 +6,8 @@
 
 namespace QWK {
 
+    class WidgetBorderHandler;
+
     class WidgetWindowAgentPrivate : public WindowAgentBasePrivate {
         Q_DECLARE_PUBLIC(WidgetWindowAgent)
     public:
@@ -17,7 +19,7 @@
         // Host
         QWidget *hostWidget{};
 
-        std::unique_ptr<QObject> paintFilter;
+        std::unique_ptr<WidgetBorderHandler> borderHandler;
     };
 
 }

--
Gitblit v1.9.1