diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 42cdded1..701cbe58 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -99,7 +99,7 @@ enum class WindowPart : quint8 struct FramelessWin32HelperData { SystemParameters params = {}; - int hitTestResult = HTNOWHERE; + std::pair, std::optional> hitTestResult = {}; Dpi dpi = {}; #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) QRect restoreGeometry = {}; @@ -329,7 +329,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me }; #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) - const auto emulateClientAreaMessage = [hWnd, uMsg, wParam, lParam]() -> void { + const auto emulateClientAreaMessage = [hWnd, uMsg, wParam, lParam](const std::optional overrideMessage = std::nullopt) -> void { const auto wparam = [uMsg, wParam]() -> WPARAM { if (uMsg == WM_NCMOUSELEAVE) { return 0; @@ -358,7 +358,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me #else # define SEND_MESSAGE ::PostMessageW #endif - switch (uMsg) { + switch (overrideMessage.value_or(uMsg)) { case WM_NCHITTEST: // Treat hit test messages as mouse move events. case WM_NCMOUSEMOVE: SEND_MESSAGE(hWnd, WM_MOUSEMOVE, wparam, lparam); @@ -764,7 +764,21 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // color, our homemade top border can almost have exactly the same // appearance with the system's one. - const auto hitTestRecorder = qScopeGuard([&muData, &result](){ muData.hitTestResult = *result; }); + const auto hitTestRecorder = qScopeGuard([&muData, &result, &emulateClientAreaMessage](){ + auto &first = std::get<0>(muData.hitTestResult); + auto &second = std::get<1>(muData.hitTestResult); + if (first.has_value()) { + if (second.has_value()) { + std::swap(first, second); + } + second = *result; + } else { + first = *result; + } + if (isSnapLayoutEnabled() && (getHittedWindowPart(second.value_or(HTNOWHERE)) == WindowPart::TitleBar) && (getHittedWindowPart(first.value_or(HTNOWHERE)) == WindowPart::ChromeButton)) { + emulateClientAreaMessage(WM_NCMOUSELEAVE); + } + }); const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; POINT nativeLocalPos = nativeGlobalPos; @@ -946,17 +960,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me #endif case WM_NCMOUSEHOVER: case WM_NCMOUSELEAVE: { - const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult); + const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult.first.value_or(HTNOWHERE)); const bool isXButtonMessage = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)); const WindowPart nowWindowPart = getHittedWindowPart(isXButtonMessage ? GET_NCHITTEST_WPARAM(wParam) : wParam); if (uMsg == WM_NCMOUSELEAVE) { - if (previousWindowPart == WindowPart::ChromeButton) { - if (nowWindowPart == WindowPart::ClientArea) { - *result = FALSE; - return true; - } else { - emulateClientAreaMessage(); - } + emulateClientAreaMessage(); + if ((previousWindowPart == WindowPart::ChromeButton) && (nowWindowPart == WindowPart::ClientArea)) { + *result = FALSE; + return true; } } else { if ((uMsg == WM_NCMOUSEMOVE) && (nowWindowPart != WindowPart::ChromeButton)) { diff --git a/src/widgets/framelesswidgetshelper.cpp b/src/widgets/framelesswidgetshelper.cpp index 6498e68b..b1896d26 100644 --- a/src/widgets/framelesswidgetshelper.cpp +++ b/src/widgets/framelesswidgetshelper.cpp @@ -705,31 +705,31 @@ bool FramelessWidgetsHelperPrivate::isInSystemButtons(const QPoint &pos, SystemB } *button = SystemButtonType::Unknown; if (data->windowIconButton && data->windowIconButton->isVisible() && data->windowIconButton->isEnabled()) { - if (data->windowIconButton->geometry().contains(pos)) { + if (mapWidgetGeometryToScene(data->windowIconButton).contains(pos)) { *button = SystemButtonType::WindowIcon; return true; } } if (data->contextHelpButton && data->contextHelpButton->isVisible() && data->contextHelpButton->isEnabled()) { - if (data->contextHelpButton->geometry().contains(pos)) { + if (mapWidgetGeometryToScene(data->contextHelpButton).contains(pos)) { *button = SystemButtonType::Help; return true; } } if (data->minimizeButton && data->minimizeButton->isVisible() && data->minimizeButton->isEnabled()) { - if (data->minimizeButton->geometry().contains(pos)) { + if (mapWidgetGeometryToScene(data->minimizeButton).contains(pos)) { *button = SystemButtonType::Minimize; return true; } } if (data->maximizeButton && data->maximizeButton->isVisible() && data->maximizeButton->isEnabled()) { - if (data->maximizeButton->geometry().contains(pos)) { + if (mapWidgetGeometryToScene(data->maximizeButton).contains(pos)) { *button = SystemButtonType::Maximize; return true; } } if (data->closeButton && data->closeButton->isVisible() && data->closeButton->isEnabled()) { - if (data->closeButton->geometry().contains(pos)) { + if (mapWidgetGeometryToScene(data->closeButton).contains(pos)) { *button = SystemButtonType::Close; return true; }