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

Commit

Permalink
win: minor improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
wangwenx190 committed Aug 18, 2023
1 parent 44eeb53 commit 2c8bd8c
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 42 deletions.
2 changes: 1 addition & 1 deletion include/FramelessHelper/Core/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ FRAMELESSHELPER_CORE_API void registerThemeChangeNotification();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowTransparent(const QWindow *window);
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 bool underMouse);
const QPoint &globalPos, const QPoint &scenePos, const QPoint &localPos);

#ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
Expand Down
14 changes: 11 additions & 3 deletions src/core/framelesshelper_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,11 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData)
// top resize border.
switch (wParam) {
case HTTOP:
case HTCAPTION:
case HTCAPTION: {
releaseButtons(std::nullopt);
// Pass caption-related nonclient messages to the parent window.
return SendMessageW(parentWindowHandle, uMsg, wParam, lParam);
}
// The buttons won't work as you'd expect; we need to handle those
// ourselves.
case HTSYSMENU:
Expand All @@ -336,6 +338,7 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData)
pressButton(SystemButtonType::Close);
break;
default:
releaseButtons(std::nullopt);
break;
}
return 0;
Expand All @@ -348,9 +351,11 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData)
// to the root HWND.
switch (wParam) {
case HTTOP:
case HTCAPTION:
case HTCAPTION: {
releaseButtons(std::nullopt);
// Pass caption-related nonclient messages to the parent window.
return SendMessageW(parentWindowHandle, uMsg, wParam, lParam);
}
// The buttons won't work as you'd expect; we need to handle those ourselves.
case HTSYSMENU:
clickButton(SystemButtonType::WindowIcon);
Expand All @@ -368,6 +373,7 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData)
clickButton(SystemButtonType::Close);
break;
default:
releaseButtons(std::nullopt);
break;
}
return 0;
Expand All @@ -376,8 +382,10 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData)
// - we don't need to handle these.
case WM_NCRBUTTONDOWN:
case WM_NCRBUTTONDBLCLK:
case WM_NCRBUTTONUP:
case WM_NCRBUTTONUP: {
releaseButtons(std::nullopt);
return SendMessageW(parentWindowHandle, uMsg, wParam, lParam);
}
default:
break;
}
Expand Down
120 changes: 93 additions & 27 deletions src/core/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,52 +631,118 @@ 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, const bool underMouse)
void Utils::emulateQtMouseEvent(const QObject *target, const QWindow *window,
const ButtonState buttonState, const QPoint &globalPos, const QPoint &scenePos, const QPoint &localPos)
{
Q_ASSERT(target);
Q_ASSERT(window);
if (!target || !window) {
return;
}
const auto object = const_cast<QObject *>(target);
const auto candidateObject = const_cast<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 QPoint oldPos = {}; // Not needed.
static constexpr const Qt::MouseButton button = Qt::LeftButton;
const Qt::MouseButtons buttons = QGuiApplication::mouseButtons();
const Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
switch (buttonState) {
case ButtonState::Normal: {
static constexpr const char kEnteredFlag[] = "__FRAMELESSHELPER_WIDGET_ITEM_ENTERED";
const bool entered = target->property(kEnteredFlag).toBool();
const auto sendEnterEvent = [&localPos, &scenePos, &globalPos, &modifiers](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QEnterEvent enterEvent(localPos, scenePos, globalPos);
#else
QEvent enterEvent(QEvent::Enter);
#endif
QHoverEvent hoverEnterEvent(QEvent::HoverEnter, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(obj, &enterEvent);
QCoreApplication::sendEvent(obj, &hoverEnterEvent);
};
const auto sendLeaveEvent = [&scenePos, &globalPos, &modifiers](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
QEvent leaveEvent(QEvent::Leave);
QHoverEvent hoverLeaveEvent(QEvent::HoverLeave, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(object, &leaveEvent);
QCoreApplication::sendEvent(object, &hoverLeaveEvent);
QCoreApplication::sendEvent(obj, &leaveEvent);
QCoreApplication::sendEvent(obj, &hoverLeaveEvent);
};
const auto sendMouseMoveEvent = [&localPos, &scenePos, &globalPos, &buttons, &modifiers](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
QMouseEvent event(QEvent::MouseMove, localPos, scenePos, globalPos, Qt::NoButton, buttons, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
const auto sendHoverMoveEvent = [&scenePos, &globalPos, &modifiers](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
QHoverEvent event(QEvent::HoverMove, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
const auto sendMousePressEvent = [&localPos, &scenePos, &globalPos, &buttons, &modifiers](QObject *obj) -> void {
Q_ASSERT(obj);
if (!obj) {
return;
}
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 {
Q_ASSERT(obj);
if (!obj) {
return;
}
QMouseEvent event(QEvent::MouseButtonRelease, localPos, scenePos, globalPos, button, buttons, modifiers);
QCoreApplication::sendEvent(obj, &event);
};
switch (buttonState) {
case ButtonState::Normal: {
targetObj->setProperty(kEnteredFlag, {});
// sendMouseReleaseEvent(windowObj);
// if (isWidget) {
// sendMouseReleaseEvent(targetObj);
// }
sendLeaveEvent(windowObj);
if (isWidget) {
sendLeaveEvent(targetObj);
}
} break;
case ButtonState::Hovered: {
const auto receiver = (target->isWidgetType() ? object : static_cast<QObject *>(candidateObject));
if (underMouse) {
QMouseEvent mouseMoveEvent(QEvent::MouseMove, localPos, scenePos, globalPos, Qt::NoButton, buttons, modifiers);
QHoverEvent hoverMoveEvent(QEvent::HoverMove, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(receiver, &mouseMoveEvent);
QCoreApplication::sendEvent(receiver, &hoverMoveEvent);
} else {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QEnterEvent enterEvent(localPos, scenePos, globalPos);
#else
QEvent enterEvent(QEvent::Enter);
#endif
QHoverEvent hoverEnterEvent(QEvent::HoverEnter, scenePos, globalPos, oldPos, modifiers);
QCoreApplication::sendEvent(receiver, &enterEvent);
QCoreApplication::sendEvent(receiver, &hoverEnterEvent);
if (!entered) {
targetObj->setProperty(kEnteredFlag, true);
sendEnterEvent(windowObj);
if (isWidget) {
sendEnterEvent(targetObj);
}
}
sendHoverMoveEvent(windowObj);
if (isWidget) {
sendHoverMoveEvent(targetObj);
}
if (mouseTrackingEnabled) {
sendMouseMoveEvent(windowObj);
if (isWidget) {
sendMouseMoveEvent(targetObj);
}
}
} break;
case ButtonState::Pressed: {
QMouseEvent event(QEvent::MouseButtonPress, localPos, scenePos, globalPos, button, buttons, modifiers);
QCoreApplication::sendEvent(object, &event);
sendMousePressEvent(windowObj);
sendMousePressEvent(targetObj);
} break;
case ButtonState::Released: {
QMouseEvent event(QEvent::MouseButtonRelease, localPos, scenePos, globalPos, button, buttons, modifiers);
QCoreApplication::sendEvent(object, &event);
sendMouseReleaseEvent(windowObj);
sendMouseReleaseEvent(targetObj);
} break;
}
}
Expand Down
11 changes: 1 addition & 10 deletions src/quick/framelessquickhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,16 +903,7 @@ 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);
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);
Utils::emulateQtMouseEvent(btn, window, FRAMELESSHELPER_ENUM_QUICK_TO_CORE(ButtonState, state), globalPos, scenePos, localPos);
};
updateButtonState(quickButton);
#endif // FRAMELESSHELPER_QUICK_NO_PRIVATE
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/framelesswidgetshelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@ 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, btn->underMouse());
Utils::emulateQtMouseEvent(btn, window->windowHandle(), state, globalPos, scenePos, localPos);
};
updateButtonState(widgetButton);
}
Expand Down

0 comments on commit 2c8bd8c

Please sign in to comment.