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

Commit

Permalink
Fix bugs after mouse press (#270)
Browse files Browse the repository at this point in the history
  • Loading branch information
SineStriker authored Aug 26, 2023
1 parent 6ff0bc9 commit 2d63907
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ using SetCursorCallback = std::function<void(const QCursor &)>;
using UnsetCursorCallback = std::function<void()>;
using GetWidgetHandleCallback = std::function<QObject *()>;
using ForceChildrenRepaintCallback = std::function<void(const int)>;
using ResetQtGrabbedControlCallback = std::function<void()>;
using ResetQtGrabbedControlCallback = std::function<bool()>;

struct SystemParameters
{
Expand Down
71 changes: 45 additions & 26 deletions src/core/framelesshelper_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
case WM_CLOSE:
case WM_DESTROY:
case WM_NCDESTROY:
case 144:
case 626:
// undocumented messages
case WM_UNREGISTER_WINDOW_SERVICES:
case WM_UAHDESTROYWINDOW:
return false;
default:
break;
Expand Down Expand Up @@ -916,7 +917,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return true;
}
*result = HTCLIENT;
return true;
} else {
if (full) {
*result = HTCLIENT;
Expand Down Expand Up @@ -979,8 +979,15 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return true;
}
*result = HTCLIENT;
return true;
}
return true;
}
case WM_MOUSEMOVE: {
const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult.first.value_or(HTNOWHERE));
if (previousWindowPart == WindowPart::ChromeButton) {
std::ignore = listenForMouseLeave(hWnd, false);
}
break;
}
case WM_NCMOUSEMOVE:
case WM_NCLBUTTONDOWN:
Expand Down Expand Up @@ -1008,23 +1015,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const WindowPart previousWindowPart = getHittedWindowPart(data.hitTestResult.first.value_or(HTNOWHERE));
const WindowPart currentWindowPart = getHittedWindowPart(data.hitTestResult.second.value_or(HTNOWHERE));
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);

// 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);
}
if (previousWindowPart == WindowPart::ChromeButton && currentWindowPart == WindowPart::NotInterested) {
// If current window part is chrome button, it indicates that we must have clicked
// the minimize button or maximize button, we also should send the client leave
// message to Qt.
emulateClientAreaMessage(WM_NCMOUSELEAVE);
}

if (currentWindowPart == WindowPart::NotInterested) {
Expand All @@ -1037,21 +1032,21 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// 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.

std::ignore = data.params.resetQtGrabbedControl();
}
} else {
if (uMsg == WM_NCMOUSEMOVE) {
if (currentWindowPart != WindowPart::ChromeButton) {
data.params.resetQtGrabbedControl();
std::ignore = data.params.resetQtGrabbedControl();
}
if ((previousWindowPart == WindowPart::ChromeButton)
&& ((currentWindowPart == WindowPart::TitleBar)
|| (currentWindowPart == WindowPart::ResizeBorder)
|| (currentWindowPart == WindowPart::FixedBorder))) {
emulateClientAreaMessage(WM_NCMOUSELEAVE);
}
}

{

// 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.

Expand All @@ -1068,7 +1063,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if (currentWindowPart == WindowPart::ChromeButton) {
emulateClientAreaMessage();
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;
Expand Down Expand Up @@ -1155,7 +1149,32 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
case WM_EXITSIZEMOVE: // Sent to a window when the user releases the mouse button (from dragging the title bar or the resize border).
updateRestoreGeometry(false);
break;
case WM_ACTIVATE: {
auto filteredWParam = LOWORD(wParam);
if (filteredWParam == WA_INACTIVE) {
if (getHittedWindowPart(data.hitTestResult.second.value_or(HTNOWHERE)) == WindowPart::ChromeButton) {
emulateClientAreaMessage(WM_NCMOUSELEAVE);

// Clear window part cache
auto &hitTestResult = muData.hitTestResult;
hitTestResult.first.reset();
hitTestResult.second.reset();
}
}
break;
}
case WM_SIZE: {
if (wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED) {
if (getHittedWindowPart(data.hitTestResult.second.value_or(HTNOWHERE)) == WindowPart::ChromeButton) {
emulateClientAreaMessage(WM_NCMOUSELEAVE);

// Clear window part cache
auto &hitTestResult = muData.hitTestResult;
hitTestResult.first.reset();
hitTestResult.second.reset();
}
break;
}
if (wParam != SIZE_MAXIMIZED) {
break;
}
Expand Down
2 changes: 1 addition & 1 deletion src/quick/framelessquickhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ void FramelessQuickHelperPrivate::attach()
params.unsetCursor = [window]() -> void { window->unsetCursor(); };
params.getWidgetHandle = []() -> QObject * { return nullptr; };
params.forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); };
params.resetQtGrabbedControl = []() -> void {};
params.resetQtGrabbedControl = []() -> bool { return false; };

FramelessManager::instance()->addWindow(&params);

Expand Down
17 changes: 16 additions & 1 deletion src/widgets/framelesswidgetshelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
#include <QtGui/qwindow.h>
#include <QtGui/qpalette.h>
#include <QtGui/qcursor.h>
#include <QtGui/qevent.h>
#include <QtWidgets/qwidget.h>
#include <QtWidgets/qapplication.h>

#ifndef QWIDGETSIZE_MAX
# define QWIDGETSIZE_MAX ((1 << 24) - 1)
Expand Down Expand Up @@ -409,7 +411,20 @@ void FramelessWidgetsHelperPrivate::attach()
params.unsetCursor = [this]() -> void { window->unsetCursor(); };
params.getWidgetHandle = [this]() -> QObject * { return window; };
params.forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); };
params.resetQtGrabbedControl = []() -> void { qt_button_down = nullptr; };
params.resetQtGrabbedControl = []() -> bool {
if (qt_button_down) {
QMouseEvent e(QEvent::MouseButtonRelease,
{-999, -999},
Qt::LeftButton,
Qt::NoButton,
QApplication::keyboardModifiers()
);
QApplication::sendEvent(qt_button_down, &e);
qt_button_down = nullptr;
return true;
}
return false;
};

FramelessManager::instance()->addWindow(&params);

Expand Down

0 comments on commit 2d63907

Please sign in to comment.