Skip to content

Commit

Permalink
snap layout: fix qt events
Browse files Browse the repository at this point in the history
  • Loading branch information
wangwenx190 committed Aug 19, 2023
1 parent 2c8bd8c commit ca968b7
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 33 deletions.
4 changes: 3 additions & 1 deletion include/FramelessHelper/Core/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,11 @@ FRAMELESSHELPER_CORE_API void registerThemeChangeNotification();
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 defaultScreenDpi();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowAccelerated(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowTransparent(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::MouseButtons queryMouseButtons();
FRAMELESSHELPER_CORE_API void emulateQtMouseEvent(
const QObject *target, const QWindow *window, const Global::ButtonState buttonState,
const QPoint &globalPos, const QPoint &scenePos, const QPoint &localPos);
const QPoint &globalPos, const QPoint &scenePos, const QPoint &localPos,
const bool underMouse, const bool hoverEnabled);

#ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
Expand Down
77 changes: 47 additions & 30 deletions src/core/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,8 +631,8 @@ bool Utils::isWindowTransparent(const QWindow *window)
return window->format().hasAlpha();
}

void Utils::emulateQtMouseEvent(const QObject *target, const QWindow *window,
const ButtonState buttonState, const QPoint &globalPos, const QPoint &scenePos, const QPoint &localPos)
void Utils::emulateQtMouseEvent(const QObject *target, const QWindow *window, const ButtonState buttonState,
const QPoint &globalPos, const QPoint &scenePos, const QPoint &localPos, const bool underMouse, const bool enableHover)
{
Q_ASSERT(target);
Q_ASSERT(window);
Expand All @@ -642,14 +642,17 @@ void Utils::emulateQtMouseEvent(const QObject *target, const QWindow *window,
const auto targetObj = const_cast<QObject *>(target);
const auto windowObj = static_cast<QObject *>(const_cast<QWindow *>(window));
const bool isWidget = target->isWidgetType();
const bool mouseTrackingEnabled = (isWidget ? target->property("mouseTracking").toBool() : true);
static constexpr const char kMouseTrackingProp[] = "mouseTracking";
const bool mouseTrackingEnabled = (isWidget ? target->property(kMouseTrackingProp).toBool() : true);
const bool hoverEnabled = (isWidget ? enableHover : true);
static constexpr const QPoint oldPos = {}; // Not needed.
static constexpr const Qt::MouseButton button = Qt::LeftButton;
const Qt::MouseButtons buttons = QGuiApplication::mouseButtons();
const Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
static constexpr const char kEnteredFlag[] = "__FRAMELESSHELPER_WIDGET_ITEM_ENTERED";
static constexpr const char kEnteredFlag[] = "__FRAMELESSHELPER_WIDGET_QUICKITEM_ENTERED";
const bool entered = target->property(kEnteredFlag).toBool();
const auto sendEnterEvent = [&localPos, &scenePos, &globalPos, &modifiers](QObject *obj) -> void {
const bool leftButtonPressed = (queryMouseButtons() & Qt::LeftButton);
const auto sendEnterEvent = [&localPos, &scenePos, &globalPos, &modifiers, hoverEnabled](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
Expand All @@ -659,33 +662,41 @@ void Utils::emulateQtMouseEvent(const QObject *target, const QWindow *window,
#else
QEvent enterEvent(QEvent::Enter);
#endif
QHoverEvent hoverEnterEvent(QEvent::HoverEnter, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(obj, &enterEvent);
QCoreApplication::sendEvent(obj, &hoverEnterEvent);
if (hoverEnabled) {
QHoverEvent hoverEnterEvent(QEvent::HoverEnter, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(obj, &hoverEnterEvent);
}
};
const auto sendLeaveEvent = [&scenePos, &globalPos, &modifiers](QObject *obj) -> void {
const auto sendLeaveEvent = [&scenePos, &globalPos, &modifiers, hoverEnabled](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
QEvent leaveEvent(QEvent::Leave);
QHoverEvent hoverLeaveEvent(QEvent::HoverLeave, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(obj, &leaveEvent);
QCoreApplication::sendEvent(obj, &hoverLeaveEvent);
if (hoverEnabled) {
QHoverEvent hoverLeaveEvent(QEvent::HoverLeave, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(obj, &hoverLeaveEvent);
}
};
const auto sendMouseMoveEvent = [&localPos, &scenePos, &globalPos, &buttons, &modifiers](QObject *obj) -> void {
const auto sendMouseMoveEvent = [&localPos, &scenePos, &globalPos, &buttons, &modifiers, leftButtonPressed](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
QMouseEvent event(QEvent::MouseMove, localPos, scenePos, globalPos, Qt::NoButton, buttons, modifiers);
const Qt::MouseButton actualButton = (leftButtonPressed ? button : Qt::NoButton);
QMouseEvent event(QEvent::MouseMove, localPos, scenePos, globalPos, actualButton, buttons, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
const auto sendHoverMoveEvent = [&scenePos, &globalPos, &modifiers](QObject *obj) -> void {
const auto sendHoverMoveEvent = [&scenePos, &globalPos, &modifiers, hoverEnabled](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
if (!hoverEnabled) {
return;
}
QHoverEvent event(QEvent::HoverMove, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
Expand All @@ -697,53 +708,59 @@ void Utils::emulateQtMouseEvent(const QObject *target, const QWindow *window,
QMouseEvent event(QEvent::MouseButtonPress, localPos, scenePos, globalPos, button, buttons, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
const auto sendMouseReleaseEvent = [&localPos, &scenePos, &globalPos, &buttons, &modifiers](QObject *obj) -> void {
const auto sendMouseReleaseEvent = [&localPos, &scenePos, &globalPos, &buttons, &modifiers](QObject *obj, const bool fake = false) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
QMouseEvent event(QEvent::MouseButtonRelease, localPos, scenePos, globalPos, button, buttons, modifiers);
static constexpr const auto fakePos = QPoint{ -999, -999 };
const QPoint tweakedLocalPos = (fake ? fakePos : localPos);
const QPoint tweakedScenePos = (fake ? fakePos : scenePos);
const QPoint tweakedGlobalPos = (fake ? fakePos : globalPos);
QMouseEvent event(QEvent::MouseButtonRelease, tweakedLocalPos, tweakedScenePos, tweakedGlobalPos, button, buttons, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
switch (buttonState) {
case ButtonState::Normal: {
targetObj->setProperty(kEnteredFlag, {});
// sendMouseReleaseEvent(windowObj);
// if (isWidget) {
// sendMouseReleaseEvent(targetObj);
// }
sendLeaveEvent(windowObj);
// Send an extra mouse release event to let the control dismiss it's hover state.
sendMouseReleaseEvent(targetObj, true);
if (isWidget) {
sendLeaveEvent(targetObj);
} else {
sendLeaveEvent(windowObj);
}
} break;
case ButtonState::Hovered: {
if (!entered) {
targetObj->setProperty(kEnteredFlag, true);
sendEnterEvent(windowObj);
if (isWidget) {
sendEnterEvent(targetObj);
} else {
sendEnterEvent(windowObj);
}
}
sendHoverMoveEvent(windowObj);
if (isWidget) {
sendHoverMoveEvent(targetObj);
} else {
sendHoverMoveEvent(windowObj);
}
if (mouseTrackingEnabled) {
sendMouseMoveEvent(windowObj);
if (leftButtonPressed || mouseTrackingEnabled) {
if (isWidget) {
sendMouseMoveEvent(targetObj);
} else {
sendMouseMoveEvent(windowObj);
}
}
} break;
case ButtonState::Pressed: {
sendMousePressEvent(windowObj);
case ButtonState::Pressed:
// Sending mouse event to the window has no effect.
sendMousePressEvent(targetObj);
} break;
case ButtonState::Released: {
sendMouseReleaseEvent(windowObj);
break;
case ButtonState::Released:
// Sending mouse event to the window has no effect.
sendMouseReleaseEvent(targetObj);
} break;
break;
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/core/utils_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -987,4 +987,10 @@ bool Utils::setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &
return true;
}

Qt::MouseButtons Utils::queryMouseButtons()
{
// ### FIXME
return {};
}

FRAMELESSHELPER_END_NAMESPACE
6 changes: 6 additions & 0 deletions src/core/utils_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,12 @@ static inline void cleanupProxy()
return (active ? getAccentColor() : kDefaultDarkGrayColor);
}

Qt::MouseButtons Utils::queryMouseButtons()
{
// ### FIXME
return {};
}

FRAMELESSHELPER_END_NAMESPACE

#include "utils_mac.moc"
25 changes: 25 additions & 0 deletions src/core/utils_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2571,6 +2571,31 @@ quint64 Utils::queryMouseButtonState()
return result;
}

Qt::MouseButtons Utils::queryMouseButtons()
{
const quint64 buttonMask = queryMouseButtonState();
if (buttonMask == 0) {
return {};
}
Qt::MouseButtons buttons = {};
if (buttonMask & MK_LBUTTON) {
buttons |= Qt::LeftButton;
}
if (buttonMask & MK_RBUTTON) {
buttons |= Qt::RightButton;
}
if (buttonMask & MK_MBUTTON) {
buttons |= Qt::MiddleButton;
}
if (buttonMask & MK_XBUTTON1) {
buttons |= Qt::XButton1;
}
if (buttonMask & MK_XBUTTON2) {
buttons |= Qt::XButton2;
}
return buttons;
}

bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel)
{
Q_ASSERT(windowId);
Expand Down
11 changes: 10 additions & 1 deletion src/quick/framelessquickhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,16 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System
const QPoint globalPos = (screen ? QCursor::pos(screen) : QCursor::pos());
const QPoint localPos = btn->mapFromGlobal(globalPos).toPoint();
const QPoint scenePos = window->mapFromGlobal(globalPos);
Utils::emulateQtMouseEvent(btn, window, FRAMELESSHELPER_ENUM_QUICK_TO_CORE(ButtonState, state), globalPos, scenePos, localPos);
const auto underMouse = [btn, &globalPos]() -> bool {
const QPointF originPoint = btn->mapToGlobal(QPointF{ 0, 0 });
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
const QSizeF size = btn->size();
#else
const auto size = QSizeF{ btn->width(), btn->height() };
#endif
return QRectF{ originPoint, size }.contains(globalPos);
}();
Utils::emulateQtMouseEvent(btn, window, FRAMELESSHELPER_ENUM_QUICK_TO_CORE(ButtonState, state), globalPos, scenePos, localPos, underMouse, true);
};
updateButtonState(quickButton);
#endif // FRAMELESSHELPER_QUICK_NO_PRIVATE
Expand Down
9 changes: 8 additions & 1 deletion src/widgets/framelesswidgetshelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,14 @@ void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType
const QPoint globalPos = (screen ? QCursor::pos(screen) : QCursor::pos());
const QPoint localPos = btn->mapFromGlobal(globalPos);
const QPoint scenePos = window->mapFromGlobal(globalPos);
Utils::emulateQtMouseEvent(btn, window->windowHandle(), state, globalPos, scenePos, localPos);
#if 0
const auto underMouse = [btn, &globalPos]() -> bool {
const QPoint originPoint = btn->mapToGlobal(QPoint{ 0, 0 });
return QRect{ originPoint, btn->size() }.contains(globalPos);
}();
#endif
const bool hoverEnabled = btn->testAttribute(Qt::WA_Hover);
Utils::emulateQtMouseEvent(btn, window->windowHandle(), state, globalPos, scenePos, localPos, btn->underMouse(), hoverEnabled);
};
updateButtonState(widgetButton);
}
Expand Down

0 comments on commit ca968b7

Please sign in to comment.