From 85a3fe1b2f718ff94f83833241c202ee9ef9908a Mon Sep 17 00:00:00 2001 From: Zhao Yuhang <2546789017@qq.com> Date: Fri, 3 Nov 2023 21:25:24 +0800 Subject: [PATCH] win: fix some minor bugs --- examples/quick/qml/ApplicationWindow.qml | 2 +- examples/quick/qml/Window.qml | 2 +- examples/widget/widget.cpp | 3 +- src/core/framelesshelper_win.cpp | 84 +++++++++++++++--------- src/quick/framelessquickhelper.cpp | 5 +- src/widgets/framelesswidgetshelper.cpp | 3 + 6 files changed, 65 insertions(+), 34 deletions(-) diff --git a/examples/quick/qml/ApplicationWindow.qml b/examples/quick/qml/ApplicationWindow.qml index 3009fa3f..df4142cc 100644 --- a/examples/quick/qml/ApplicationWindow.qml +++ b/examples/quick/qml/ApplicationWindow.qml @@ -35,7 +35,7 @@ FramelessApplicationWindow { height: 600 title: qsTr("FramelessHelper demo application - Qt Quick [") + objectName + ']' color: { - if (FramelessHelper.blurBehindWindowEnabled) { + if (FramelessHelper.blurBehindWindowEnabled && FramelessUtils.blurBehindWindowSupported) { return "transparent"; } if (FramelessUtils.systemTheme === FramelessHelperConstants.Dark) { diff --git a/examples/quick/qml/Window.qml b/examples/quick/qml/Window.qml index 558b1a3c..457a4434 100644 --- a/examples/quick/qml/Window.qml +++ b/examples/quick/qml/Window.qml @@ -35,7 +35,7 @@ FramelessWindow { height: 600 title: qsTr("FramelessHelper demo application - Qt Quick [") + objectName +']' color: { - if (FramelessHelper.blurBehindWindowEnabled) { + if (FramelessHelper.blurBehindWindowEnabled && FramelessUtils.blurBehindWindowSupported) { return "transparent"; } if (FramelessUtils.systemTheme === FramelessHelperConstants.Dark) { diff --git a/examples/widget/widget.cpp b/examples/widget/widget.cpp index 41dd9a7d..81b7609a 100644 --- a/examples/widget/widget.cpp +++ b/examples/widget/widget.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -187,7 +188,7 @@ void Widget::updateStyleSheet() m_clockLabel->setStyleSheet(labelStyleSheet); m_compilerInfoLabel->setStyleSheet(labelStyleSheet); m_commitInfoLabel->setStyleSheet(labelStyleSheet); - if (FramelessWidgetsHelper::get(this)->isBlurBehindWindowEnabled()) { + if (FramelessWidgetsHelper::get(this)->isBlurBehindWindowEnabled() && Utils::isBlurBehindWindowSupported()) { setStyleSheet(FRAMELESSHELPER_STRING_LITERAL("background-color: transparent;")); } else { const QColor windowBackgroundColor = (dark ? kDefaultSystemDarkColor : kDefaultSystemLightColor); diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 10f837a3..381b5df1 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -843,23 +843,53 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me const auto clientHeight = RECT_HEIGHT(clientRect); const QPoint qtScenePos = Utils::fromNativeLocalPosition(qWindow, QPoint(nativeLocalPos.x, nativeLocalPos.y)); + + const bool isFixedSize = data->callbacks->isWindowFixedSize(); + const bool isTitleBar = data->callbacks->isInsideTitleBarDraggableArea(qtScenePos); + const bool dontOverrideCursor = data->callbacks->getProperty(kDontOverrideCursorVar, false).toBool(); + const bool dontToggleMaximize = data->callbacks->getProperty(kDontToggleMaximizeVar, false).toBool(); + + if (dontToggleMaximize) { + static bool warnedOnce = false; + if (!warnedOnce) { + warnedOnce = true; + DEBUG << "To disable window maximization, you should remove the " + "WS_MAXIMIZEBOX style from the window instead. FramelessHelper " + "won't do that for you, so you'll have to do it manually yourself."; + } + } + SystemButtonType sysButtonType = SystemButtonType::Unknown; - if (data->callbacks->isInsideSystemButtons(qtScenePos, &sysButtonType)) { + if (!isFixedSize && data->callbacks->isInsideSystemButtons(qtScenePos, &sysButtonType)) { + // Firstly, we set the hit test result to a default value to be able to detect whether we + // have changed it or not afterwards. + *result = HTNOWHERE; // Even if the mouse is inside the chrome button area now, we should still allow the user // to be able to resize the window with the top or right window border, this is also the - // normal behavior of a native Win32 window. - static constexpr const int kBorderSize = 2; - const bool isTop = (nativeLocalPos.y <= kBorderSize); - const bool isRight = (nativeLocalPos.x >= (clientWidth - kBorderSize)); - if (isTop || isRight) { - if (isTop && isRight) { - *result = HTTOPRIGHT; - } else if (isTop) { - *result = HTTOP; - } else { - *result = HTRIGHT; + // normal behavior of a native Win32 window (but only when the window is not maximized/ + // fullscreened/minimized, of course). + if (Utils::isWindowNoState(windowId)) { + static constexpr const int kBorderSize = 2; + const bool isTop = (nativeLocalPos.y <= kBorderSize); + const bool isRight = (nativeLocalPos.x >= (clientWidth - kBorderSize)); + if (isTop || isRight) { + if (dontOverrideCursor) { + // The user doesn't want the window to be resized, so we tell Windows we are + // in the client area so that the controls beneath the mouse cursor can still + // be hovered or clicked. + *result = (isTitleBar ? HTCAPTION : HTCLIENT); + } else { + if (isTop && isRight) { + *result = HTTOPRIGHT; + } else if (isTop) { + *result = HTTOP; + } else { + *result = HTRIGHT; + } + } } - } else { + } + if (*result == HTNOWHERE) { // OK, we are now really inside one of the chrome buttons, tell Windows the exact role of our button. // The Snap Layout feature introduced in Windows 11 won't work without this. switch (sysButtonType) { @@ -880,10 +910,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me *result = HTCLOSE; break; case SystemButtonType::Unknown: - *result = HTCLIENT; // Normally we'd never enter this branch. break; } } + if (*result == HTNOWHERE) { + // OK, it seems we are not inside the window resize area, nor inside the chrome buttons, + // tell Windows we are in the client area to let Qt handle this event. + *result = HTCLIENT; + } return true; } // OK, we are not inside of any chrome buttons, try to find out which part of the window @@ -893,26 +927,16 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me const bool full = Utils::isFullScreen(windowId); const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); const bool isTop = (nativeLocalPos.y < frameSizeY); - const bool isTitleBar = data->callbacks->isInsideTitleBarDraggableArea(qtScenePos); - const bool isFixedSize = data->callbacks->isWindowFixedSize(); - const bool dontOverrideCursor = data->callbacks->getProperty(kDontOverrideCursorVar, false).toBool(); - const bool dontToggleMaximize = data->callbacks->getProperty(kDontToggleMaximizeVar, false).toBool(); - - if (dontToggleMaximize) { - static bool once = false; - if (!once) { - once = true; - DEBUG << "To disable window maximization, you should remove the " - "WS_MAXIMIZEBOX style from the window instead. FramelessHelper " - "won't do that for you, so you'll have to do it manually yourself."; - } - } if (frameBorderVisible) { // This will handle the left, right and bottom parts of the frame // because we didn't change them. const LRESULT originalHitTestResult = ::DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam); if (originalHitTestResult != HTCLIENT) { + // Even if the window is not resizable, we still can't return HTCLIENT here because + // when we enters this code path, it means the mouse cursor is outside of the window, + // that is, the three transparent window resize area. Returning HTCLIENT will confuse + // Windows and we can't put our controls there anyway. *result = ((isFixedSize || dontOverrideCursor) ? HTBORDER : originalHitTestResult); return true; } @@ -933,7 +957,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // Return HTCLIENT instead of HTBORDER here, because the mouse is // inside our homemade title bar now, return HTCLIENT to let our // title bar can still capture mouse events. - *result = ((isFixedSize || dontOverrideCursor) ? HTCLIENT : HTTOP); + *result = ((isFixedSize || dontOverrideCursor) ? (isTitleBar ? HTCAPTION : HTCLIENT) : HTTOP); return true; } if (isTitleBar) { @@ -962,7 +986,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // Return HTCLIENT instead of HTBORDER here, because the mouse is // inside the window now, return HTCLIENT to let the controls // inside our window can still capture mouse events. - *result = HTCLIENT; + *result = (isTitleBar ? HTCAPTION : HTCLIENT); return true; } if (isTop) { diff --git a/src/quick/framelessquickhelper.cpp b/src/quick/framelessquickhelper.cpp index d8f19e08..21c51ca7 100644 --- a/src/quick/framelessquickhelper.cpp +++ b/src/quick/framelessquickhelper.cpp @@ -594,7 +594,10 @@ bool FramelessQuickHelperPrivate::shouldIgnoreMouseEvents(const QPoint &pos) con if (!window) { return false; } - const auto withinFrameBorder = [&pos, window]() -> bool { + const auto withinFrameBorder = [q, &pos, window]() -> bool { + if (q->isWindowFixedSize()) { + return false; + } if (pos.y() < kDefaultResizeBorderThickness) { return true; } diff --git a/src/widgets/framelesswidgetshelper.cpp b/src/widgets/framelesswidgetshelper.cpp index be74663a..965d0ff9 100644 --- a/src/widgets/framelesswidgetshelper.cpp +++ b/src/widgets/framelesswidgetshelper.cpp @@ -655,6 +655,9 @@ bool FramelessWidgetsHelperPrivate::shouldIgnoreMouseEvents(const QPoint &pos) c return false; } const auto withinFrameBorder = [this, &pos]() -> bool { + if (isWidgetFixedSize(window)) { + return false; + } if (pos.y() < kDefaultResizeBorderThickness) { return true; }