snap layout: improve

This commit is contained in:
Yuhang Zhao 2023-08-25 14:13:39 +08:00
parent e8977c7486
commit e0abdb04ce
1 changed files with 29 additions and 27 deletions

View File

@ -143,20 +143,6 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData)
return result; return result;
} }
[[nodiscard]] static inline bool isSnapLayoutEnabled()
{
static const auto result = []() -> bool {
if (!WindowsVersionHelper::isWin11OrGreater()) {
return false;
}
if (FramelessConfig::instance()->isSet(Option::DisableWindowsSnapLayout)) {
return false;
}
return true;
}();
return result;
}
[[nodiscard]] static inline WindowPart getHittedWindowPart(const int hitTestResult) [[nodiscard]] static inline WindowPart getHittedWindowPart(const int hitTestResult)
{ {
switch (hitTestResult) { switch (hitTestResult) {
@ -416,11 +402,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
} }
}; };
if (isSnapLayoutEnabled() && (uMsg == WM_MOUSELEAVE)) { if (uMsg == WM_MOUSELEAVE) {
// For some unknown reason, there will be many invalid mouse leave events generated // Qt will call TrackMouseEvent() to get the WM_MOUSELEAVE message when it receives
// when the mouse is hovering above our chrome buttons, which will cause Qt to ignore // WM_MOUSEMOVE messages, and since we are converting every WM_NCMOUSEMOVE message
// all our mouse move events and thus break the hover state of our controls. // to WM_MOUSEMOVE message and send it back to the window to be able to hover our
// So we filter out these superfluous mouse leave events here. // controls, we also get lots of WM_MOUSELEAVE messages at the same time because of
// the reason above, and these superfluous mouse leave events cause Qt to think the
// mouse has left the control, and thus we actually lost the hover state.
// So we filter out these superfluous mouse leave events here to avoid this issue.
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint{ msg->pt.x, msg->pt.y }); const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint{ msg->pt.x, msg->pt.y });
SystemButtonType dummy = SystemButtonType::Unknown; SystemButtonType dummy = SystemButtonType::Unknown;
if (data.params.isInsideSystemButtons(qtScenePos, &dummy)) { if (data.params.isInsideSystemButtons(qtScenePos, &dummy)) {
@ -764,7 +753,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// color, our homemade top border can almost have exactly the same // color, our homemade top border can almost have exactly the same
// appearance with the system's one. // appearance with the system's one.
const auto hitTestRecorder = qScopeGuard([&muData, &result, &emulateClientAreaMessage](){ const auto hitTestRecorder = qScopeGuard([&muData, &result](){
auto &first = std::get<0>(muData.hitTestResult); auto &first = std::get<0>(muData.hitTestResult);
auto &second = std::get<1>(muData.hitTestResult); auto &second = std::get<1>(muData.hitTestResult);
if (first.has_value()) { if (first.has_value()) {
@ -775,9 +764,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
} else { } else {
first = *result; 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) }; const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
@ -789,7 +775,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint(nativeLocalPos.x, nativeLocalPos.y)); const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint(nativeLocalPos.x, nativeLocalPos.y));
SystemButtonType sysButtonType = SystemButtonType::Unknown; SystemButtonType sysButtonType = SystemButtonType::Unknown;
if (isSnapLayoutEnabled() && data.params.isInsideSystemButtons(qtScenePos, &sysButtonType)) { if (data.params.isInsideSystemButtons(qtScenePos, &sysButtonType)) {
// OK, we are now inside one of the chrome buttons, tell Windows the exact role of our button. // OK, we are now inside one of the chrome buttons, tell Windows the exact role of our button.
switch (sysButtonType) { switch (sysButtonType) {
case SystemButtonType::WindowIcon: case SystemButtonType::WindowIcon:
@ -964,15 +950,31 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const bool isXButtonMessage = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)); const bool isXButtonMessage = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK));
const WindowPart nowWindowPart = getHittedWindowPart(isXButtonMessage ? GET_NCHITTEST_WPARAM(wParam) : wParam); const WindowPart nowWindowPart = getHittedWindowPart(isXButtonMessage ? GET_NCHITTEST_WPARAM(wParam) : wParam);
if (uMsg == WM_NCMOUSELEAVE) { if (uMsg == WM_NCMOUSELEAVE) {
emulateClientAreaMessage();
if ((previousWindowPart == WindowPart::ChromeButton) && (nowWindowPart == WindowPart::ClientArea)) { if ((previousWindowPart == WindowPart::ChromeButton) && (nowWindowPart == WindowPart::ClientArea)) {
TRACKMOUSEEVENT tme;
SecureZeroMemory(&tme, sizeof(tme));
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hWnd;
tme.dwHoverTime = HOVER_DEFAULT;
if (::TrackMouseEvent(&tme) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kTrackMouseEvent);
}
*result = FALSE; *result = FALSE;
return true; return true;
} }
} else { } else {
if ((uMsg == WM_NCMOUSEMOVE) && (nowWindowPart != WindowPart::ChromeButton)) { if (uMsg == WM_NCMOUSEMOVE) {
if (nowWindowPart != WindowPart::ChromeButton) {
data.params.resetQtGrabbedControl(); data.params.resetQtGrabbedControl();
} }
if ((previousWindowPart == WindowPart::ChromeButton)
&& ((nowWindowPart == WindowPart::TitleBar)
|| (nowWindowPart == WindowPart::ResizeBorder)
|| (nowWindowPart == WindowPart::FixedBorder))) {
emulateClientAreaMessage(WM_NCMOUSELEAVE);
}
}
if (nowWindowPart == WindowPart::ChromeButton) { if (nowWindowPart == WindowPart::ChromeButton) {
emulateClientAreaMessage(); emulateClientAreaMessage();
*result = (isXButtonMessage ? TRUE : FALSE); *result = (isXButtonMessage ? TRUE : FALSE);