Fix emulate message bug and git modules, window part mistakes, non client leave mistakes and crash (#269)
* Fix emulate message bug and git modules * Fix window part mistakes * Fix WM_NCMOUSELEAVE message mistakes and crash * Fix maximize minimize button hover problem
This commit is contained in:
parent
bdb1b5d68f
commit
6ff0bc9300
|
@ -1,3 +1,3 @@
|
||||||
[submodule "cmake"]
|
[submodule "cmake"]
|
||||||
path = cmake
|
path = cmake
|
||||||
url = ../cmake-utils.git
|
url = ../../wangwenx190/cmake-utils.git
|
||||||
|
|
|
@ -313,9 +313,17 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
}
|
}
|
||||||
const UINT uMsg = msg->message;
|
const UINT uMsg = msg->message;
|
||||||
// WM_QUIT won't be posted to the WindowProc function.
|
// 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;
|
return false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto it = g_framelessWin32HelperData()->data.find(windowId);
|
const auto it = g_framelessWin32HelperData()->data.find(windowId);
|
||||||
if (it == g_framelessWin32HelperData()->data.end()) {
|
if (it == g_framelessWin32HelperData()->data.end()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -345,19 +353,20 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||||
|
|
||||||
const auto emulateClientAreaMessage = [hWnd, uMsg, wParam, lParam](const std::optional<int> overrideMessage = std::nullopt) -> void {
|
const auto emulateClientAreaMessage = [hWnd, uMsg, wParam, lParam](const std::optional<int> overrideMessage = std::nullopt) -> void {
|
||||||
const auto wparam = [uMsg, wParam]() -> WPARAM {
|
auto myMsg = overrideMessage.value_or(uMsg);
|
||||||
if (uMsg == WM_NCMOUSELEAVE) {
|
const auto wparam = [myMsg, wParam]() -> WPARAM {
|
||||||
|
if (myMsg == WM_NCMOUSELEAVE) {
|
||||||
return kMessageTag;
|
return kMessageTag;
|
||||||
}
|
}
|
||||||
const quint64 keyState = Utils::getKeyState();
|
const quint64 keyState = Utils::getKeyState();
|
||||||
if ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)) {
|
if ((myMsg >= WM_NCXBUTTONDOWN) && (myMsg <= WM_NCXBUTTONDBLCLK)) {
|
||||||
const auto xButtonMask = GET_XBUTTON_WPARAM(wParam);
|
const auto xButtonMask = GET_XBUTTON_WPARAM(wParam);
|
||||||
return MAKEWPARAM(keyState, xButtonMask);
|
return MAKEWPARAM(keyState, xButtonMask);
|
||||||
}
|
}
|
||||||
return keyState;
|
return keyState;
|
||||||
}();
|
}();
|
||||||
const auto lparam = [uMsg, lParam, hWnd]() -> LPARAM {
|
const auto lparam = [myMsg, lParam, hWnd]() -> LPARAM {
|
||||||
if (uMsg == WM_NCMOUSELEAVE) {
|
if (myMsg == WM_NCMOUSELEAVE) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const auto screenPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
const auto screenPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||||
|
@ -373,7 +382,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
#else
|
#else
|
||||||
# define SEND_MESSAGE ::PostMessageW
|
# define SEND_MESSAGE ::PostMessageW
|
||||||
#endif
|
#endif
|
||||||
switch (overrideMessage.value_or(uMsg)) {
|
switch (myMsg) {
|
||||||
case WM_NCHITTEST: // Treat hit test messages as mouse move events.
|
case WM_NCHITTEST: // Treat hit test messages as mouse move events.
|
||||||
case WM_NCMOUSEMOVE:
|
case WM_NCMOUSEMOVE:
|
||||||
SEND_MESSAGE(hWnd, WM_MOUSEMOVE, wparam, lparam);
|
SEND_MESSAGE(hWnd, WM_MOUSEMOVE, wparam, lparam);
|
||||||
|
@ -785,14 +794,12 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
const auto hitTestRecorder = qScopeGuard([&muData, &result](){
|
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 (second.has_value()) {
|
if (second.has_value()) {
|
||||||
std::swap(first, second);
|
first = second;
|
||||||
|
} else if (!first.has_value()){
|
||||||
|
first = HTNOWHERE;
|
||||||
}
|
}
|
||||||
second = *result;
|
second = *result;
|
||||||
} else {
|
|
||||||
first = *result;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||||
|
@ -999,36 +1006,73 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
||||||
// The following code is not workaround anything, it's just try to emulate the original
|
// The following code is not workaround anything, it's just try to emulate the original
|
||||||
// behavior of a native Win32 window.
|
// behavior of a native Win32 window.
|
||||||
const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult.first.value_or(HTNOWHERE));
|
const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult.first.value_or(HTNOWHERE));
|
||||||
const bool isXButtonMessage = ((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK));
|
const WindowPart currentWindowPart = getHittedWindowPart(data.hitTestResult.second.value_or(HTNOWHERE));
|
||||||
const WindowPart nowWindowPart = getHittedWindowPart(isXButtonMessage ? GET_NCHITTEST_WPARAM(wParam) : wParam);
|
|
||||||
if (uMsg == WM_NCMOUSELEAVE) {
|
if (uMsg == WM_NCMOUSELEAVE) {
|
||||||
if (nowWindowPart == WindowPart::NotInterested) {
|
|
||||||
std::ignore = listenForMouseLeave(hWnd, false);
|
|
||||||
}
|
|
||||||
if (previousWindowPart == WindowPart::ChromeButton) {
|
if (previousWindowPart == WindowPart::ChromeButton) {
|
||||||
if (nowWindowPart == WindowPart::ClientArea) {
|
if (currentWindowPart == WindowPart::ClientArea) {
|
||||||
*result = FALSE;
|
// 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);
|
||||||
|
|
||||||
|
// 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;
|
return true;
|
||||||
} else if (nowWindowPart == WindowPart::NotInterested) {
|
} else if (currentWindowPart == WindowPart::NotInterested) {
|
||||||
emulateClientAreaMessage(WM_NCMOUSELEAVE);
|
emulateClientAreaMessage(WM_NCMOUSELEAVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentWindowPart == WindowPart::NotInterested) {
|
||||||
|
// The mouse is leaving window from non-client area, clear window part caches
|
||||||
|
auto &hitTestResult = muData.hitTestResult;
|
||||||
|
hitTestResult.first.reset();
|
||||||
|
hitTestResult.second.reset();
|
||||||
|
|
||||||
|
// Notice: we're not going to clear window part caches when the mouse leaves window
|
||||||
|
// from client area, which means we will get previous window part as HTCLIENT if
|
||||||
|
// the mouse leaves window from client area and enters window from non-client area,
|
||||||
|
// but it has no bad effect.
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (uMsg == WM_NCMOUSEMOVE) {
|
if (uMsg == WM_NCMOUSEMOVE) {
|
||||||
if (nowWindowPart != WindowPart::ChromeButton) {
|
if (currentWindowPart != WindowPart::ChromeButton) {
|
||||||
data.params.resetQtGrabbedControl();
|
data.params.resetQtGrabbedControl();
|
||||||
}
|
}
|
||||||
if ((previousWindowPart == WindowPart::ChromeButton)
|
if ((previousWindowPart == WindowPart::ChromeButton)
|
||||||
&& ((nowWindowPart == WindowPart::TitleBar)
|
&& ((currentWindowPart == WindowPart::TitleBar)
|
||||||
|| (nowWindowPart == WindowPart::ResizeBorder)
|
|| (currentWindowPart == WindowPart::ResizeBorder)
|
||||||
|| (nowWindowPart == WindowPart::FixedBorder))) {
|
|| (currentWindowPart == WindowPart::FixedBorder))) {
|
||||||
emulateClientAreaMessage(WM_NCMOUSELEAVE);
|
emulateClientAreaMessage(WM_NCMOUSELEAVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nowWindowPart == WindowPart::ChromeButton) {
|
|
||||||
|
{
|
||||||
|
// We need to make sure we get the correct window part when a WM_NCMOUSELEAVE come,
|
||||||
|
// so we reset current window part to null when we receive a WM_NCMOUSEMOVE.
|
||||||
|
|
||||||
|
// If the mouse is entering the client area, there must be a WM_NCHITTEST setting current
|
||||||
|
// window part to NCCLIENT before the WM_NCMOUSELEAVE comes;
|
||||||
|
// If the mouse is leaving the window, current window part remains as null.
|
||||||
|
auto &hitTestResult = muData.hitTestResult;
|
||||||
|
if (hitTestResult.second.has_value()) {
|
||||||
|
hitTestResult.first = hitTestResult.second;
|
||||||
|
hitTestResult.second.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentWindowPart == WindowPart::ChromeButton) {
|
||||||
emulateClientAreaMessage();
|
emulateClientAreaMessage();
|
||||||
std::ignore = listenForMouseLeave(hWnd, true);
|
if (uMsg == WM_NCMOUSEMOVE) {
|
||||||
*result = (isXButtonMessage ? TRUE : FALSE);
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue