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