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

Commit

Permalink
Linux: fix mouse release event not being sent due to wrong parameter
Browse files Browse the repository at this point in the history
Also simplifies a little Windows implementation.

Signed-off-by: Yuhang Zhao <[email protected]>
  • Loading branch information
wangwenx190 committed Apr 25, 2022
1 parent 3d7576e commit fd2b3f5
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 141 deletions.
146 changes: 144 additions & 2 deletions include/FramelessHelper/Core/framelesshelpercore_global.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,98 @@ enum class ButtonState
};
Q_ENUM_NS(ButtonState)

enum class WindowsVersion
{
_2000 = 0,
_XP = 1,
_XP_64 = 2,
_Vista = 3,
_Vista_SP1 = 4,
_Vista_SP2 = 5,
_7 = 6,
_7_SP1 = 7,
_8 = 8,
_8_1 = 9,
_8_1_Update1 = 10,
_10_1507 = 11,
_10_1511 = 12,
_10_1607 = 13,
_10_1703 = 14,
_10_1709 = 15,
_10_1803 = 16,
_10_1809 = 17,
_10_1903 = 18,
_10_1909 = 19,
_10_2004 = 20,
_10_20H2 = 21,
_10_21H1 = 22,
_10_21H2 = 23,
_11_21H2 = 24
};
Q_ENUM_NS(WindowsVersion)

struct VersionNumber
{
int major = 0;
int minor = 0;
int patch = 0;
int tweak = 0;

[[nodiscard]] friend bool operator==(const VersionNumber &lhs, const VersionNumber &rhs) noexcept
{
return ((lhs.major == rhs.major) && (lhs.minor == rhs.minor) && (lhs.patch == rhs.patch) && (lhs.tweak == rhs.tweak));
}

[[nodiscard]] friend bool operator!=(const VersionNumber &lhs, const VersionNumber &rhs) noexcept
{
return !(lhs == rhs);
}

[[nodiscard]] friend bool operator>(const VersionNumber &lhs, const VersionNumber &rhs) noexcept
{
if (lhs.major > rhs.major) {
return true;
}
if (lhs.major < rhs.major) {
return false;
}
if (lhs.minor > rhs.minor) {
return true;
}
if (lhs.minor < rhs.minor) {
return false;
}
if (lhs.patch > rhs.patch) {
return true;
}
if (lhs.patch < rhs.patch) {
return false;
}
if (lhs.tweak > rhs.tweak) {
return true;
}
if (lhs.tweak < rhs.tweak) {
return false;
}
return false;
}

[[nodiscard]] friend bool operator<(const VersionNumber &lhs, const VersionNumber &rhs) noexcept
{
return ((lhs != rhs) && !(lhs > rhs));
}

[[nodiscard]] friend bool operator>=(const VersionNumber &lhs, const VersionNumber &rhs) noexcept
{
return ((lhs > rhs) || (lhs == rhs));
}

[[nodiscard]] friend bool operator<=(const VersionNumber &lhs, const VersionNumber &rhs) noexcept
{
return ((lhs < rhs) || (lhs == rhs));
}
};

using GetWindowFlagsCallback = std::function<Qt::WindowFlags()>;
using SetWindowFlagsCallback = std::function<void(const Qt::WindowFlags)>;

Expand Down Expand Up @@ -361,6 +453,25 @@ struct SystemParameters

[[nodiscard]] inline bool isValid() const
{
Q_ASSERT(getWindowFlags);
Q_ASSERT(setWindowFlags);
Q_ASSERT(getWindowSize);
Q_ASSERT(setWindowSize);
Q_ASSERT(getWindowPosition);
Q_ASSERT(setWindowPosition);
Q_ASSERT(getWindowScreen);
Q_ASSERT(isWindowFixedSize);
Q_ASSERT(setWindowFixedSize);
Q_ASSERT(getWindowState);
Q_ASSERT(setWindowState);
Q_ASSERT(getWindowHandle);
Q_ASSERT(windowToScreen);
Q_ASSERT(screenToWindow);
Q_ASSERT(isInsideSystemButtons);
Q_ASSERT(isInsideTitleBarDraggableArea);
Q_ASSERT(getWindowDevicePixelRatio);
Q_ASSERT(setSystemButtonState);
Q_ASSERT(getWindowId);
return (getWindowFlags && setWindowFlags && getWindowSize
&& setWindowSize && getWindowPosition && setWindowPosition
&& getWindowScreen && isWindowFixedSize && setWindowFixedSize
Expand All @@ -371,6 +482,36 @@ struct SystemParameters
}
};

[[maybe_unused]] static constexpr const VersionNumber WindowsVersions[] =
{
{ 5, 0, 2195}, // Windows 2000
{ 5, 1, 2600}, // Windows XP
{ 5, 2, 3790}, // Windows XP x64 Edition or Windows Server 2003
{ 6, 0, 6000}, // Windows Vista
{ 6, 0, 6001}, // Windows Vista with Service Pack 1 or Windows Server 2008
{ 6, 0, 6002}, // Windows Vista with Service Pack 2
{ 6, 1, 7600}, // Windows 7 or Windows Server 2008 R2
{ 6, 1, 7601}, // Windows 7 with Service Pack 1 or Windows Server 2008 R2 with Service Pack 1
{ 6, 2, 9200}, // Windows 8 or Windows Server 2012
{ 6, 3, 9200}, // Windows 8.1 or Windows Server 2012 R2
{ 6, 3, 9600}, // Windows 8.1 with Update 1
{10, 0, 10240}, // Windows 10 Version 1507 (TH1)
{10, 0, 10586}, // Windows 10 Version 1511 (November Update) (TH2)
{10, 0, 14393}, // Windows 10 Version 1607 (Anniversary Update) (RS1) or Windows Server 2016
{10, 0, 15063}, // Windows 10 Version 1703 (Creators Update) (RS2)
{10, 0, 16299}, // Windows 10 Version 1709 (Fall Creators Update) (RS3)
{10, 0, 17134}, // Windows 10 Version 1803 (April 2018 Update) (RS4)
{10, 0, 17763}, // Windows 10 Version 1809 (October 2018 Update) (RS5) or Windows Server 2019
{10, 0, 18362}, // Windows 10 Version 1903 (May 2019 Update) (19H1)
{10, 0, 18363}, // Windows 10 Version 1909 (November 2019 Update) (19H2)
{10, 0, 19041}, // Windows 10 Version 2004 (May 2020 Update) (20H1)
{10, 0, 19042}, // Windows 10 Version 20H2 (October 2020 Update) (20H2)
{10, 0, 19043}, // Windows 10 Version 21H1 (May 2021 Update) (21H1)
{10, 0, 19044}, // Windows 10 Version 21H2 (November 2021 Update) (21H2)
{10, 0, 22000}, // Windows 11 Version 21H2 (21H2)
};
static_assert((sizeof(WindowsVersions) / sizeof(WindowsVersions[0])) == (static_cast<int>(WindowsVersion::_11_21H2) + 1));

} // namespace Global

namespace FramelessHelper::Core
Expand All @@ -380,5 +521,6 @@ FRAMELESSHELPER_CORE_API void initialize(const Global::Options options = {});

FRAMELESSHELPER_END_NAMESPACE

Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Global::UserSettings))
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Global::SystemParameters))
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::VersionNumber)
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::UserSettings)
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::SystemParameters)
9 changes: 1 addition & 8 deletions include/FramelessHelper/Core/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,7 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized();

#ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin8OrGreater();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin8Point1OrGreater();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin10OrGreater();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin10_1607OrGreater();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin10_1809OrGreater();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin10_1903OrGreater();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin10_2004OrGreater();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin11OrGreater();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isDwmCompositionEnabled();
FRAMELESSHELPER_CORE_API void triggerFrameChange(const WId windowId);
FRAMELESSHELPER_CORE_API void updateWindowFrameMargins(const WId windowId, const bool reset);
Expand Down
12 changes: 6 additions & 6 deletions src/core/framelesshelper_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,16 +245,16 @@ void FramelessHelperWin::addWindow(const UserSettings &settings, const SystemPar
}
Utils::updateInternalWindowFrameMargins(params.getWindowHandle(), true);
Utils::updateWindowFrameMargins(windowId, false);
if (Utils::isWin10_1607OrGreater()) {
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1607)) {
const bool dark = Utils::shouldAppsUseDarkMode();
if (!(settings.options & Option::DontTouchWindowFrameBorderColor)) {
Utils::updateWindowFrameBorderColor(windowId, dark);
}
if (Utils::isWin10_1809OrGreater()) {
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1809)) {
if (settings.options & Option::SyncNativeControlsThemeWithSystem) {
Utils::updateGlobalWin32ControlsTheme(windowId, dark);
}
if (Utils::isWin11OrGreater()) {
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2)) {
if (settings.options & Option::MaximizeButtonDocking) {
const auto hwnd = reinterpret_cast<HWND>(windowId);
SetLastError(ERROR_SUCCESS);
Expand Down Expand Up @@ -458,7 +458,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// Due to ABM_GETAUTOHIDEBAREX only exists from Win8.1,
// we have to use another way to judge this if we are
// running on Windows 7 or Windows 8.
if (Utils::isWin8Point1OrGreater()) {
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_8_1)) {
MONITORINFO monitorInfo;
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo);
Expand Down Expand Up @@ -821,7 +821,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
bool systemThemeChanged = ((uMsg == WM_THEMECHANGED) || (uMsg == WM_SYSCOLORCHANGE)
|| (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED));
if (Utils::isWin10_1607OrGreater()) {
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1607)) {
if (uMsg == WM_SETTINGCHANGE) {
if ((wParam == 0) && (QString::fromWCharArray(reinterpret_cast<LPCWSTR>(lParam))
.compare(qThemeSettingChangeEventName, Qt::CaseInsensitive) == 0)) {
Expand All @@ -830,7 +830,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if (!(data.settings.options & Option::DontTouchWindowFrameBorderColor)) {
Utils::updateWindowFrameBorderColor(windowId, dark);
}
if (Utils::isWin10_1809OrGreater()) {
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1809)) {
if (data.settings.options & Option::SyncNativeControlsThemeWithSystem) {
Utils::updateGlobalWin32ControlsTheme(windowId, dark);
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/framelesswindowsmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ void FramelessHelper::Core::initialize(const Options options)
qRegisterMetaType<DwmColorizationArea>();
qRegisterMetaType<Anchor>();
qRegisterMetaType<ButtonState>();
qRegisterMetaType<WindowsVersion>();
qRegisterMetaType<VersionNumber>();
qRegisterMetaType<UserSettings>();
qRegisterMetaType<SystemParameters>();
}
Expand Down
39 changes: 22 additions & 17 deletions src/core/utils_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,15 @@ static inline void
xcb_button_release_event_t xev;
memset(&xev, 0, sizeof(xev));
xev.response_type = XCB_BUTTON_RELEASE;
xev.time = XCB_CURRENT_TIME;
xev.time = QX11Info::appTime();
xev.root = rootWindow;
xev.root_x = globalPos.x();
xev.root_y = globalPos.y();
xev.event = windowId;
xev.event_x = localPos.x();
xev.event_y = localPos.y();
xev.same_screen = true;
xcb_send_event(connection, false, rootWindow, XCB_EVENT_MASK_BUTTON_RELEASE,
xcb_send_event(connection, false, rootWindow, XCB_EVENT_MASK_STRUCTURE_NOTIFY,
reinterpret_cast<const char *>(&xev));
xcb_flush(connection);
}
Expand Down Expand Up @@ -174,13 +174,26 @@ static inline void
xev.data.data32[3] = XCB_BUTTON_INDEX_1;
// First we need to ungrab the pointer that may have been
// automatically grabbed by Qt on ButtonPressEvent.
xcb_ungrab_pointer(connection, XCB_CURRENT_TIME);
xcb_ungrab_pointer(connection, QX11Info::appTime());
xcb_send_event(connection, false, rootWindow,
(XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY),
reinterpret_cast<const char *>(&xev));
xcb_flush(connection);
}

static inline void sendMouseReleaseEvent(QWindow *window, const QPoint &globalPos)
{
Q_ASSERT(window);
if (!window) {
return;
}
const qreal dpr = window->devicePixelRatio();
const QPoint deviceGlobalPos = QPointF(QPointF(globalPos) * dpr).toPoint();
const QPoint logicalLocalPos = window->mapFromGlobal(globalPos);
const QPoint deviceLocalPos = QPointF(QPointF(logicalLocalPos) * dpr).toPoint();
emulateMouseButtonRelease(window->winId(), deviceGlobalPos, deviceLocalPos);
}

SystemTheme Utils::getSystemTheme()
{
// ### TODO: how to detect high contrast mode on Linux?
Expand All @@ -193,17 +206,13 @@ void Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
if (!window) {
return;
}
const WId windowId = window->winId();
const qreal dpr = window->devicePixelRatio();
const QPoint deviceGlobalPos = QPointF(QPointF(globalPos) * dpr).toPoint();
const QPoint logicalLocalPos = window->mapFromGlobal(globalPos);
const QPoint deviceLocalPos = QPointF(QPointF(logicalLocalPos) * dpr).toPoint();
// Before we start the dragging we need to tell Qt that the mouse is released.
emulateMouseButtonRelease(windowId, deviceGlobalPos, deviceLocalPos);
sendMouseReleaseEvent(window, globalPos);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
window->startSystemMove();
#else
doStartSystemMoveResize(windowId, deviceGlobalPos, _NET_WM_MOVERESIZE_MOVE);
const QPoint deviceGlobalPos = QPointF(QPointF(globalPos) * window->devicePixelRatio()).toPoint();
doStartSystemMoveResize(window->winId(), deviceGlobalPos, _NET_WM_MOVERESIZE_MOVE);
#endif
}

Expand All @@ -216,21 +225,17 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
if (edges == Qt::Edges{}) {
return;
}
const WId windowId = window->winId();
const qreal dpr = window->devicePixelRatio();
const QPoint deviceGlobalPos = QPointF(QPointF(globalPos) * dpr).toPoint();
const QPoint logicalLocalPos = window->mapFromGlobal(globalPos);
const QPoint deviceLocalPos = QPointF(QPointF(logicalLocalPos) * dpr).toPoint();
// Before we start the resizing we need to tell Qt that the mouse is released.
emulateMouseButtonRelease(windowId, deviceGlobalPos, deviceLocalPos);
sendMouseReleaseEvent(window, globalPos);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
window->startSystemResize(edges);
#else
const int section = qtEdgesToWmMoveOrResizeOperation(edges);
if (section < 0) {
return;
}
doStartSystemMoveResize(windowId, deviceGlobalPos, section);
const QPoint deviceGlobalPos = QPointF(QPointF(globalPos) * window->devicePixelRatio()).toPoint();
doStartSystemMoveResize(window->winId(), deviceGlobalPos, section);
#endif
}

Expand Down
Loading

0 comments on commit fd2b3f5

Please sign in to comment.