From 3d0d0c24adf5001be1c42b2fa86129b1b258cf70 Mon Sep 17 00:00:00 2001 From: Sine Striker <trueful@163.com> Date: 周一, 04 12月 2023 20:31:36 +0800 Subject: [PATCH] Fix NCHITTEST --- src/core/contexts/win32windowcontext.cpp | 91 +++++++++++++++++++++++++-------------------- 1 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp index 09c2b83..d3b34ec 100644 --- a/src/core/contexts/win32windowcontext.cpp +++ b/src/core/contexts/win32windowcontext.cpp @@ -6,6 +6,7 @@ #include <QtCore/QAbstractNativeEventFilter> #include <QtCore/QCoreApplication> #include <QtCore/QOperatingSystemVersion> +#include <QtCore/QScopeGuard> #include <QtCore/private/qsystemlibrary_p.h> #include <QtGui/private/qhighdpiscaling_p.h> @@ -213,8 +214,7 @@ return (windowRect == mi.value_or(MONITORINFOEXW{}).rcMonitor); } - static inline bool isWindowNoState(HWND hwnd) - { + static inline bool isWindowNoState(HWND hwnd) { Q_ASSERT(hwnd); if (!hwnd) { return false; @@ -332,11 +332,11 @@ static inline void install() { instance = new WindowsNativeEventFilter(); - qApp->installNativeEventFilter(instance); + installNativeEventFilter(instance); } static inline void uninstall() { - qApp->removeNativeEventFilter(instance); + removeNativeEventFilter(instance); delete instance; instance = nullptr; } @@ -1093,39 +1093,44 @@ // color, our homemade top border can almost have exactly the same // appearance with the system's one. - const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + [[maybe_unused]] const auto &hitTestRecorder = qScopeGuard([this, result]() { + lastHitTestResult = getHitWindowPart(int(*result)); // + }); + + POINT nativeGlobalPos{GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; POINT nativeLocalPos = nativeGlobalPos; ::ScreenToClient(hWnd, &nativeLocalPos); - auto clientRect = RECT{ 0, 0, 0, 0 }; + RECT clientRect{0, 0, 0, 0}; ::GetClientRect(hWnd, &clientRect); - const auto clientWidth = RECT_WIDTH(clientRect); - const auto clientHeight = RECT_HEIGHT(clientRect); + auto clientWidth = RECT_WIDTH(clientRect); + auto clientHeight = RECT_HEIGHT(clientRect); - const QPoint qtScenePos = fromNativeLocalPosition(m_windowHandle, QPoint(nativeLocalPos.x, nativeLocalPos.y)); + QPoint qtScenePos = fromNativeLocalPosition( + m_windowHandle, QPoint(nativeLocalPos.x, nativeLocalPos.y)); - const bool isFixedSize = /*isWindowFixedSize()*/false; // ### FIXME - const bool isTitleBar = isInTitleBarDraggableArea(qtScenePos); - const bool dontOverrideCursor = false; // ### TODO + bool isFixedSize = /*isWindowFixedSize()*/ false; // ### FIXME + bool isTitleBar = isInTitleBarDraggableArea(qtScenePos); + bool dontOverrideCursor = false; // ### TODO CoreWindowAgent::SystemButton sysButtonType = CoreWindowAgent::Unknown; if (!isFixedSize && isInSystemButtons(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. + // 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 (but only when the window is not maximized/ - // fullscreened/minimized, of course). + // 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 (but only when the + // window is not maximized/fullscreen/minimized, of course). if (isWindowNoState(hWnd)) { static constexpr const int kBorderSize = 2; - const bool isTop = (nativeLocalPos.y <= kBorderSize); - const bool isRight = (nativeLocalPos.x >= (clientWidth - kBorderSize)); + bool isTop = (nativeLocalPos.y <= kBorderSize); + 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. + // 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) { @@ -1139,8 +1144,9 @@ } } 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. + // 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) { case CoreWindowAgent::WindowIcon: *result = HTSYSMENU; @@ -1162,30 +1168,33 @@ } } 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. + // 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 any chrome buttons, try to find out which part of the window - // are we hitting. + // OK, we are not inside any chrome buttons, try to find out which part of the + // window are we hitting. - const bool max = IsMaximized(hWnd); - const bool full = isFullScreen(hWnd); - const int frameSize = getResizeBorderThickness(hWnd); - const bool isTop = (nativeLocalPos.y < frameSize); + bool max = IsMaximized(hWnd); + bool full = isFullScreen(hWnd); + int frameSize = getResizeBorderThickness(hWnd); + bool isTop = (nativeLocalPos.y < frameSize); if (isWin10OrGreater()) { // 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); + 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 enter this code path, it means the mouse cursor is outside the window, - // that is, the three transparent window resize area. Returning HTCLIENT will confuse - // Windows, we can't put our controls there anyway. - *result = ((isFixedSize || dontOverrideCursor) ? HTBORDER : originalHitTestResult); + // Even if the window is not resizable, we still can't return HTCLIENT here + // because when we enter this code path, it means the mouse cursor is + // outside the window, that is, the three transparent window resize area. + // Returning HTCLIENT will confuse Windows, we can't put our controls there + // anyway. + *result = ((isFixedSize || dontOverrideCursor) ? HTBORDER + : originalHitTestResult); return true; } if (full) { @@ -1205,7 +1214,9 @@ // 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) ? (isTitleBar ? HTCAPTION : HTCLIENT) : HTTOP); + *result = ((isFixedSize || dontOverrideCursor) + ? (isTitleBar ? HTCAPTION : HTCLIENT) + : HTTOP); return true; } if (isTitleBar) { -- Gitblit v1.9.1