Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Commit

Permalink
Fix WM_NCMOUSELEAVE message mistakes and crash
Browse files Browse the repository at this point in the history
  • Loading branch information
SineStriker committed Aug 25, 2023
1 parent c4395bf commit a0f7751
Showing 1 changed file with 25 additions and 6 deletions.
31 changes: 25 additions & 6 deletions src/core/framelesshelper_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,17 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
const UINT uMsg = msg->message;
// WM_QUIT won't be posted to the WindowProc function.
if ((uMsg == WM_CLOSE) || (uMsg == WM_DESTROY)) {
switch (uMsg) {
case WM_CLOSE:
case WM_DESTROY:
case WM_NCDESTROY:
case 144:
case 626:
return false;
default:
break;
}

const auto it = g_framelessWin32HelperData()->data.find(windowId);
if (it == g_framelessWin32HelperData()->data.end()) {
return false;
Expand Down Expand Up @@ -999,13 +1007,20 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// behavior of a native Win32 window.
const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult.first.value_or(HTNOWHERE));
const WindowPart currentWindowPart = getHittedWindowPart(data.hitTestResult.second.value_or(HTNOWHERE));
const bool isXButtonMessage = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK));

if (uMsg == WM_NCMOUSELEAVE) {
if (previousWindowPart == WindowPart::ChromeButton) {
if (currentWindowPart == WindowPart::ClientArea) {
// Since we filter the WM_MOUSELEAVE event when the mouse is above the buttons,
// Qt will always think it's tracking the mouse.
// If we don't track the mouse after the mouse enter client area, there will
// be no WM_MOUSELEAVE sent by Windows which should be sent.
std::ignore = listenForMouseLeave(hWnd, false);
*result = FALSE;

// According to numerous experiments we've conducted, Windows maintains the mouse
// state internally, we must eventually let Windows handle the WM_NCMOUSELEAVE
// otherwise the internal state will be broken so that Windows may fail to send
// the WM_NCMOUSELEAVE messages which we need.
*result = ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
return true;
} else if (currentWindowPart == WindowPart::NotInterested) {
emulateClientAreaMessage(WM_NCMOUSELEAVE);
Expand Down Expand Up @@ -1049,8 +1064,12 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
if (currentWindowPart == WindowPart::ChromeButton) {
emulateClientAreaMessage();
std::ignore = listenForMouseLeave(hWnd, true);
*result = (isXButtonMessage ? TRUE : FALSE);
if (uMsg == WM_NCMOUSEMOVE) {
// We should pass WM_NCMOUSEMOVE to Windows as well as WM_NCMOUSELEAVE
*result = ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
} else {
*result = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)) ? TRUE : FALSE;
}
return true;
}
}
Expand Down

0 comments on commit a0f7751

Please sign in to comment.