From 146384f9b04676010befb34c5226efa9d343e2e7 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao Date: Thu, 14 Sep 2023 17:58:50 +0800 Subject: [PATCH] wip --- CMakeLists.txt | 93 +++--- .../FramelessHelper/Core/framelesshelper_qt.h | 10 +- .../Core/framelesshelper_win.h | 10 +- .../Core/framelesshelper_windows.h | 52 ++- .../FramelessHelper/Core/framelessmanager.h | 6 +- .../private/framelesshelpercore_global_p.h | 53 ++- .../Core/private/framelessmanager_p.h | 7 +- include/FramelessHelper/Core/utils.h | 111 +++---- src/core/CMakeLists.txt | 45 +-- src/core/framelesshelper_qt.cpp | 126 ++++--- src/core/framelesshelper_win.cpp | 120 +++---- src/core/framelessmanager.cpp | 81 +++-- src/core/micamaterial.cpp | 2 +- src/core/utils.cpp | 32 +- src/core/utils_win.cpp | 311 +++++++----------- 15 files changed, 541 insertions(+), 518 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0f00ab..a3dda83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ project(FramelessHelper ) include(CMakeDependentOption) +include(cmake/utils.cmake) # TODO: Use add_feature_info() for every option below? Is it worth doing? option(FRAMELESSHELPER_BUILD_STATIC "Build FramelessHelper as a static library." OFF) @@ -61,16 +62,7 @@ option(FRAMELESSHELPER_NO_TRANSLATION "Don't bundle the I18N translations into t option(FRAMELESSHELPER_NO_MICA_MATERIAL "Disable the cross-platform homemade Mica Material." OFF) option(FRAMELESSHELPER_NO_BORDER_PAINTER "Disable the cross-platform window frame border painter." OFF) option(FRAMELESSHELPER_NO_SYSTEM_BUTTON "Disable the pre-defined StandardSystemButton control." OFF) - -if(FRAMELESSHELPER_NO_WINDOW AND FRAMELESSHELPER_BUILD_EXAMPLES) - message(WARNING "You can't build the examples when the FramelessWindow class is disabled at the same time!") - set(FRAMELESSHELPER_BUILD_EXAMPLES OFF) -endif() - -set(FRAMELESSHELPER_64BIT_POSTFIX "") -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(FRAMELESSHELPER_64BIT_POSTFIX "64") -endif() +cmake_dependent_option(FRAMELESSHELPER_NATIVE_IMPL "Use platform native implementation instead of Qt to get best experience." ON WIN32 OFF) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui) @@ -78,10 +70,18 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui) find_package(QT NAMES Qt6 Qt5 QUIET COMPONENTS Widgets Quick) find_package(Qt${QT_VERSION_MAJOR} QUIET COMPONENTS Widgets Quick) -include(cmake/utils.cmake) +if(FRAMELESSHELPER_NATIVE_IMPL AND NOT WIN32) + message(WARNING "FRAMELESSHELPER_NATIVE_IMPL currently only supports the Windows platform!") + set(FRAMELESSHELPER_NATIVE_IMPL OFF) +endif() -if(NOT APPLE AND FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD) - message(WARNING "Current OS is not macOS, universal build will be disabled.") +if(FRAMELESSHELPER_NO_WINDOW AND FRAMELESSHELPER_BUILD_EXAMPLES) + message(WARNING "You can't build the examples when the FramelessWindow class is disabled at the same time!") + set(FRAMELESSHELPER_BUILD_EXAMPLES OFF) +endif() + +if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD AND NOT APPLE) + message(WARNING "Universal build is a macOS only feature, it will be disabled on current platform.") set(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD OFF) elseif(APPLE AND ((QT_VERSION VERSION_LESS "6.2" AND QT_VERSION VERSION_GREATER_EQUAL "6.0") OR (QT_VERSION VERSION_LESS "5.15.9"))) message(WARNING "Your Qt version ${QT_VERSION} doesn't support universal build, it will be disabled.") @@ -94,6 +94,29 @@ endif() if(FRAMELESSHELPER_ENABLE_VCLTL AND NOT MSVC) message(WARNING "VC-LTL is only available for the MSVC toolchain.") + set(FRAMELESSHELPER_ENABLE_VCLTL OFF) +endif() + +if(FRAMELESSHELPER_ENABLE_YYTHUNKS AND NOT MSVC) + message(WARNING "YY-Thunks is only available for the MSVC toolchain.") + set(FRAMELESSHELPER_ENABLE_YYTHUNKS OFF) +endif() + +if(NOT TARGET Qt${QT_VERSION_MAJOR}::Core OR NOT TARGET Qt${QT_VERSION_MAJOR}::Gui) + message(WARNING "Can't find the QtCore and/or QtGui module. Nothing will be built.") + set(FRAMELESSHELPER_BUILD_WIDGETS OFF) + set(FRAMELESSHELPER_BUILD_QUICK OFF) + set(FRAMELESSHELPER_BUILD_EXAMPLES OFF) +endif() + +if(FRAMELESSHELPER_BUILD_QUICK AND NOT TARGET Qt${QT_VERSION_MAJOR}::Quick) + message(WARNING "Can't find the QtQuick module. FramelessHelper's QtQuick implementation and the QtQuick demo won't be built.") + set(FRAMELESSHELPER_BUILD_QUICK OFF) +endif() + +set(FRAMELESSHELPER_64BIT_POSTFIX "") +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(FRAMELESSHELPER_64BIT_POSTFIX "64") endif() set(FRAMELESSHELPER_LICENSE_HEADER "/* @@ -144,25 +167,23 @@ if(MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(FRAMELESSHELPER_ENABLE_CFGUARD OFF) endif() -if(MSVC) - if(FRAMELESSHELPER_ENABLE_VCLTL) - include(cmake/VC-LTL.cmake) - if("x${SupportLTL}" STREQUAL "xtrue") - # Make sure we will always overwrite the previous settings. - unset(CMAKE_MSVC_RUNTIME_LIBRARY) - unset(CMAKE_MSVC_RUNTIME_LIBRARY CACHE) - #unset(CMAKE_MSVC_RUNTIME_LIBRARY PARENT_SCOPE) - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" CACHE STRING "" FORCE) - endif() - endif() - if(FRAMELESSHELPER_ENABLE_YYTHUNKS) - unset(YYTHUNKS_TARGET_OS) - unset(YYTHUNKS_TARGET_OS CACHE) - #unset(YYTHUNKS_TARGET_OS PARENT_SCOPE) - set(YYTHUNKS_TARGET_OS "WinXP" CACHE STRING "" FORCE) - include(cmake/YY-Thunks.cmake) +if(FRAMELESSHELPER_ENABLE_VCLTL) + include(cmake/VC-LTL.cmake) + if("x${SupportLTL}" STREQUAL "xtrue") + # Make sure we will always overwrite the previous settings. + unset(CMAKE_MSVC_RUNTIME_LIBRARY) + unset(CMAKE_MSVC_RUNTIME_LIBRARY CACHE) + #unset(CMAKE_MSVC_RUNTIME_LIBRARY PARENT_SCOPE) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" CACHE STRING "" FORCE) endif() endif() +if(FRAMELESSHELPER_ENABLE_YYTHUNKS) + unset(YYTHUNKS_TARGET_OS) + unset(YYTHUNKS_TARGET_OS CACHE) + #unset(YYTHUNKS_TARGET_OS PARENT_SCOPE) + set(YYTHUNKS_TARGET_OS "WinXP" CACHE STRING "" FORCE) + include(cmake/YY-Thunks.cmake) +endif() set(__extra_flags "") if(FRAMELESSHELPER_NO_INSTALL) @@ -175,11 +196,6 @@ prepare_package_export( ) unset(__extra_flags) -if(FRAMELESSHELPER_BUILD_QUICK AND NOT TARGET Qt${QT_VERSION_MAJOR}::Quick) - message(WARNING "Can't find the QtQuick module. FramelessHelper's QtQuick implementation and the QtQuick demo won't be built.") - set(FRAMELESSHELPER_BUILD_QUICK OFF) -endif() - set(FRAMELESSHELPER_VERSION_FILE "${PROJECT_BINARY_DIR}/framelesshelper.version") generate_project_version( PATH "${FRAMELESSHELPER_VERSION_FILE}" @@ -202,14 +218,11 @@ add_project_config(KEY "translation" CONDITION NOT FRAMELESSHELPER_NO_TRANSLATIO add_project_config(KEY "mica_material" CONDITION NOT FRAMELESSHELPER_NO_MICA_MATERIAL) add_project_config(KEY "border_painter" CONDITION NOT FRAMELESSHELPER_NO_BORDER_PAINTER) add_project_config(KEY "system_button" CONDITION NOT FRAMELESSHELPER_NO_SYSTEM_BUTTON) +add_project_config(KEY "native_impl" CONDITION FRAMELESSHELPER_NATIVE_IMPL) generate_project_config(PATH "${FRAMELESSHELPER_CONFIG_FILE}") -if(TARGET Qt${QT_VERSION_MAJOR}::Core AND TARGET Qt${QT_VERSION_MAJOR}::Gui) +if(FRAMELESSHELPER_BUILD_WIDGETS OR FRAMELESSHELPER_BUILD_QUICK) add_subdirectory(src) -else() - message(WARNING "Can't find the QtCore and QtGui module. Nothing will be built.") - set(FRAMELESSHELPER_BUILD_WIDGETS OFF) - set(FRAMELESSHELPER_BUILD_EXAMPLES OFF) endif() if(FRAMELESSHELPER_BUILD_EXAMPLES) diff --git a/include/FramelessHelper/Core/framelesshelper_qt.h b/include/FramelessHelper/Core/framelesshelper_qt.h index c9f506e..211419b 100644 --- a/include/FramelessHelper/Core/framelesshelper_qt.h +++ b/include/FramelessHelper/Core/framelesshelper_qt.h @@ -26,9 +26,9 @@ #include -FRAMELESSHELPER_BEGIN_NAMESPACE +#if !FRAMELESSHELPER_CONFIG(native_impl) -struct SystemParameters; +FRAMELESSHELPER_BEGIN_NAMESPACE class FRAMELESSHELPER_CORE_API FramelessHelperQt : public QObject { @@ -40,11 +40,13 @@ public: explicit FramelessHelperQt(QObject *parent = nullptr); ~FramelessHelperQt() override; - static void addWindow(const SystemParameters *params); - static void removeWindow(const WId windowId); + static void addWindow(const QWindow *window); + static void removeWindow(const QWindow *window); protected: Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override; }; FRAMELESSHELPER_END_NAMESPACE + +#endif // !native_impl diff --git a/include/FramelessHelper/Core/framelesshelper_win.h b/include/FramelessHelper/Core/framelesshelper_win.h index 51b7660..01067f1 100644 --- a/include/FramelessHelper/Core/framelesshelper_win.h +++ b/include/FramelessHelper/Core/framelesshelper_win.h @@ -29,9 +29,9 @@ #ifdef Q_OS_WINDOWS -FRAMELESSHELPER_BEGIN_NAMESPACE +#if FRAMELESSHELPER_CONFIG(native_impl) -struct SystemParameters; +FRAMELESSHELPER_BEGIN_NAMESPACE class FRAMELESSHELPER_CORE_API FramelessHelperWin : public QAbstractNativeEventFilter { @@ -41,12 +41,14 @@ public: explicit FramelessHelperWin(); ~FramelessHelperWin() override; - static void addWindow(const SystemParameters *params); - static void removeWindow(const WId windowId); + static void addWindow(const QWindow *window); + static void removeWindow(const QWindow *window); Q_NODISCARD bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override; }; FRAMELESSHELPER_END_NAMESPACE +#endif // native_impl + #endif // Q_OS_WINDOWS diff --git a/include/FramelessHelper/Core/framelesshelper_windows.h b/include/FramelessHelper/Core/framelesshelper_windows.h index 2d41d31..3fcee29 100644 --- a/include/FramelessHelper/Core/framelesshelper_windows.h +++ b/include/FramelessHelper/Core/framelesshelper_windows.h @@ -1107,7 +1107,7 @@ _AdjustWindowRectExForDpi2( EXTERN_C_END -[[maybe_unused]] inline constexpr const int kAutoHideTaskBarThickness = 2; // The thickness of an auto-hide taskbar in pixels. +[[maybe_unused]] inline constexpr const unsigned char kAutoHideTaskBarThickness = 2; // The thickness of an auto-hide taskbar in pixels. [[maybe_unused]] inline constexpr const wchar_t kDwmRegistryKey[] = LR"(Software\Microsoft\Windows\DWM)"; [[maybe_unused]] inline constexpr const wchar_t kPersonalizeRegistryKey[] = LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"; [[maybe_unused]] inline constexpr const wchar_t kThemeSettingChangeEventName[] = L"ImmersiveColorSet"; @@ -1116,3 +1116,53 @@ EXTERN_C_END [[maybe_unused]] inline constexpr const wchar_t kSystemLightThemeResourceName[] = L"Explorer"; [[maybe_unused]] inline constexpr const wchar_t kDesktopRegistryKey[] = LR"(Control Panel\Desktop)"; [[maybe_unused]] inline constexpr const wchar_t kDarkModePropertyName[] = L"UseImmersiveDarkModeColors"; + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator==(const POINT &lhs, const POINT &rhs) noexcept +{ + return ((lhs.x == rhs.x) && (lhs.y == rhs.y)); +} + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator!=(const POINT &lhs, const POINT &rhs) noexcept +{ + return !operator==(lhs, rhs); +} + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return ((lhs.cx == rhs.cx) && (lhs.cy == rhs.cy)); +} + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return !operator==(lhs, rhs); +} + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator>(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return ((lhs.cx * lhs.cy) > (rhs.cx * rhs.cy)); +} + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator>=(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return (operator>(lhs, rhs) || operator==(lhs, rhs)); +} + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator<(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return (operator!=(lhs, rhs) && !operator>(lhs, rhs)); +} + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator<=(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return (operator<(lhs, rhs) || operator==(lhs, rhs)); +} + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator==(const RECT &lhs, const RECT &rhs) noexcept +{ + return ((lhs.left == rhs.left) && (lhs.top == rhs.top) && (lhs.right == rhs.right) && (lhs.bottom == rhs.bottom)); +} + +[[maybe_unused]] [[nodiscard]] inline constexpr bool operator!=(const RECT &lhs, const RECT &rhs) noexcept +{ + return !operator==(lhs, rhs); +} diff --git a/include/FramelessHelper/Core/framelessmanager.h b/include/FramelessHelper/Core/framelessmanager.h index b6ed5bd..fd67e92 100644 --- a/include/FramelessHelper/Core/framelessmanager.h +++ b/include/FramelessHelper/Core/framelessmanager.h @@ -28,7 +28,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE -struct SystemParameters; class FramelessManagerPrivate; class FRAMELESSHELPER_CORE_API FramelessManager : public QObject @@ -45,14 +44,15 @@ class FRAMELESSHELPER_CORE_API FramelessManager : public QObject public: Q_NODISCARD static FramelessManager *instance(); + Q_NODISCARD bool isFramelessWindow(const QWindow *window) const; Q_NODISCARD Global::SystemTheme systemTheme() const; Q_NODISCARD QColor systemAccentColor() const; Q_NODISCARD QString wallpaper() const; Q_NODISCARD Global::WallpaperAspectStyle wallpaperAspectStyle() const; public Q_SLOTS: - void addWindow(const SystemParameters *params); - void removeWindow(const WId windowId); + Q_NODISCARD bool addWindow(const QWindow *window); + Q_NODISCARD bool removeWindow(const QWindow *window); void setOverrideTheme(const Global::SystemTheme theme); Q_SIGNALS: diff --git a/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h b/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h index c0d2fa5..2b1c656 100644 --- a/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h +++ b/include/FramelessHelper/Core/private/framelesshelpercore_global_p.h @@ -25,7 +25,10 @@ #pragma once #include +#include +#include #include +#include QT_BEGIN_NAMESPACE class QScreen; @@ -62,7 +65,7 @@ using GetWidgetHandleCallback = std::function; using ForceChildrenRepaintCallback = std::function; using ResetQtGrabbedControlCallback = std::function; -struct SystemParameters +struct FramelessCallbacks { GetWindowFlagsCallback getWindowFlags = nullptr; SetWindowFlagsCallback setWindowFlags = nullptr; @@ -92,29 +95,61 @@ struct SystemParameters GetWidgetHandleCallback getWidgetHandle = nullptr; ForceChildrenRepaintCallback forceChildrenRepaint = nullptr; ResetQtGrabbedControlCallback resetQtGrabbedControl = nullptr; + +private: + Q_DISABLE_COPY_MOVE(FramelessCallbacks) +}; +using FramelessCallbacksPtr = std::shared_ptr; +#define CreateFramelessCallbacks(...) std::make_shared(__VA_ARGS__) + +struct FramelessData; +using FramelessDataPtr = std::shared_ptr; +#define CreateFramelessData(...) std::make_shared(__VA_ARGS__) + +struct FramelessData +{ + bool frameless = false; + FramelessCallbacksPtr callbacks = nullptr; + + [[nodiscard]] static FramelessDataPtr create(); + +private: + Q_DISABLE_COPY_MOVE(FramelessData) }; -using FramelessParams = SystemParameters *; -using FramelessParamsConst = const SystemParameters *; -using FramelessParamsRef = SystemParameters &; -using FramelessParamsConstRef = const SystemParameters &; +using FramelessDataHash = QHash; + +template +[[nodiscard]] T qWindowId(const QWindow *window) +{ + Q_ASSERT(window); + if (!window) { + return reinterpret_cast(nullptr); + } + return reinterpret_cast(window->winId()); +} FRAMELESSHELPER_END_NAMESPACE #define DECLARE_SIZE_COMPARE_OPERATORS(Type1, Type2) \ - [[maybe_unused]] [[nodiscard]] static inline constexpr bool operator>(const Type1 &lhs, const Type2 &rhs) noexcept \ + [[maybe_unused]] [[nodiscard]] inline constexpr bool operator>(const Type1 &lhs, const Type2 &rhs) noexcept \ { \ return ((lhs.width() * lhs.height()) > (rhs.width() * rhs.height())); \ } \ - [[maybe_unused]] [[nodiscard]] static inline constexpr bool operator>=(const Type1 &lhs, const Type2 &rhs) noexcept \ + [[maybe_unused]] [[nodiscard]] inline constexpr bool operator>=(const Type1 &lhs, const Type2 &rhs) noexcept \ { \ return (operator>(lhs, rhs) || operator==(lhs, rhs)); \ } \ - [[maybe_unused]] [[nodiscard]] static inline constexpr bool operator<(const Type1 &lhs, const Type2 &rhs) noexcept \ + [[maybe_unused]] [[nodiscard]] inline constexpr bool operator<(const Type1 &lhs, const Type2 &rhs) noexcept \ { \ return (operator!=(lhs, rhs) && !operator>(lhs, rhs)); \ } \ - [[maybe_unused]] [[nodiscard]] static inline constexpr bool operator<=(const Type1 &lhs, const Type2 &rhs) noexcept \ + [[maybe_unused]] [[nodiscard]] inline constexpr bool operator<=(const Type1 &lhs, const Type2 &rhs) noexcept \ { \ return (operator<(lhs, rhs) || operator==(lhs, rhs)); \ } + +DECLARE_SIZE_COMPARE_OPERATORS(QSize, QSize) +DECLARE_SIZE_COMPARE_OPERATORS(QSizeF, QSizeF) +DECLARE_SIZE_COMPARE_OPERATORS(QSize, QSizeF) +DECLARE_SIZE_COMPARE_OPERATORS(QSizeF, QSize) diff --git a/include/FramelessHelper/Core/private/framelessmanager_p.h b/include/FramelessHelper/Core/private/framelessmanager_p.h index 5951a0b..7b4a762 100644 --- a/include/FramelessHelper/Core/private/framelessmanager_p.h +++ b/include/FramelessHelper/Core/private/framelessmanager_p.h @@ -30,9 +30,10 @@ FRAMELESSHELPER_BEGIN_NAMESPACE -struct SystemParameters; -class FramelessManager; +struct FramelessData; +using FramelessDataPtr = std::shared_ptr; +class FramelessManager; class FRAMELESSHELPER_CORE_API FramelessManagerPrivate : public QObject { Q_OBJECT @@ -60,6 +61,8 @@ public: void doNotifySystemThemeHasChangedOrNot(); void doNotifyWallpaperHasChangedOrNot(); + Q_NODISCARD static FramelessDataPtr getData(const QWindow *window); + FramelessManager *q_ptr = nullptr; Global::SystemTheme systemTheme = Global::SystemTheme::Unknown; std::optional overrideTheme = std::nullopt; diff --git a/include/FramelessHelper/Core/utils.h b/include/FramelessHelper/Core/utils.h index e922eac..27e3423 100644 --- a/include/FramelessHelper/Core/utils.h +++ b/include/FramelessHelper/Core/utils.h @@ -42,25 +42,19 @@ struct SystemParameters; namespace Utils { -[[nodiscard]] FRAMELESSHELPER_CORE_API - Qt::CursorShape calculateCursorShape(const QWindow *window, const QPoint &pos); -[[nodiscard]] FRAMELESSHELPER_CORE_API - Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos); +[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::CursorShape calculateCursorShape(const QWindow *window, const QPoint &pos); +[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos); [[nodiscard]] FRAMELESSHELPER_CORE_API bool startSystemMove(QWindow *window, const QPoint &globalPos); [[nodiscard]] FRAMELESSHELPER_CORE_API bool startSystemResize(QWindow *window, const Qt::Edges edges, const QPoint &globalPos); [[nodiscard]] FRAMELESSHELPER_CORE_API QString getSystemButtonGlyph(const Global::SystemButtonType button); [[nodiscard]] FRAMELESSHELPER_CORE_API QWindow *findWindow(const WId windowId); -FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter( - const SystemParameters *params, const bool considerTaskBar); -[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::WindowState windowStatesToWindowState( - const Qt::WindowStates states); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool moveWindowToDesktopCenter(const QWindow *window, const bool considerTaskBar); +[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::WindowState windowStatesToWindowState(const Qt::WindowStates states); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isThemeChangeEvent(const QEvent * const event); -[[nodiscard]] FRAMELESSHELPER_CORE_API QColor calculateSystemButtonBackgroundColor( - const Global::SystemButtonType button, const Global::ButtonState state); +[[nodiscard]] FRAMELESSHELPER_CORE_API QColor calculateSystemButtonBackgroundColor(const Global::SystemButtonType button, const Global::ButtonState state); [[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized(); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool - setBlurBehindWindowEnabled(const WId windowId, const Global::BlurMode mode, const QColor &color); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool setBlurBehindWindowEnabled(const QWindow *window, const Global::BlurMode mode, const QColor &color); [[nodiscard]] FRAMELESSHELPER_CORE_API QString getWallpaperFilePath(); [[nodiscard]] FRAMELESSHELPER_CORE_API Global::WallpaperAspectStyle getWallpaperAspectStyle(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isBlurBehindWindowSupported(); @@ -93,71 +87,61 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter( #ifdef Q_OS_WINDOWS [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isDwmCompositionEnabled(); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool triggerFrameChange(const WId windowId); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateWindowFrameMargins(const WId windowId, const bool reset); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool triggerFrameChange(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateWindowFrameMargins(const QWindow *window, const bool reset); [[nodiscard]] FRAMELESSHELPER_CORE_API bool updateInternalWindowFrameMargins(QWindow *window, const bool enable); [[nodiscard]] FRAMELESSHELPER_CORE_API QString getSystemErrorMessage(const QString &function); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId windowId); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId windowId); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API bool syncWmPaintWithDwm(); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool showSystemMenu( - const WId windowId, const QPoint &pos, - const bool selectFirstEntry, const SystemParameters *params); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool showSystemMenu(const QWindow *window, const QPoint &pos, const bool selectFirstEntry); [[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmColorizationColor(bool *opaque = nullptr, bool *ok = nullptr); [[nodiscard]] FRAMELESSHELPER_CORE_API Global::DwmColorizationArea getDwmColorizationArea(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isHighContrastModeEnabled(); [[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getPrimaryScreenDpi(const bool horizontal); -[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getWindowDpi(const WId windowId, const bool horizontal); -[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThicknessForDpi - (const bool horizontal, const quint32 dpi); -[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThickness(const WId windowId, - const bool horizontal, - const bool scaled); +[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getWindowDpi(const QWindow *window, const bool horizontal); +[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThicknessForDpi(const bool horizontal, const quint32 dpi); +[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThickness(const QWindow *window, const bool horizontal, const bool scaled); [[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getCaptionBarHeightForDpi(const quint32 dpi); -[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getCaptionBarHeight(const WId windowId, const bool scaled); +[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getCaptionBarHeight(const QWindow *window, const bool scaled); [[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getTitleBarHeightForDpi(const quint32 dpi); -[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getTitleBarHeight(const WId windowId, const bool scaled); +[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getTitleBarHeight(const QWindow *window, const bool scaled); [[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThicknessForDpi(const quint32 dpi); -[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const WId windowId, - const bool scaled); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool maybeFixupQtInternals(const WId windowId); +[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const QWindow *window, const bool scaled); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool maybeFixupQtInternals(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFrameBorderVisible(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized(); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool installWindowProcHook( - const WId windowId, const SystemParameters *params); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool uninstallWindowProcHook(const WId windowId); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool setAeroSnappingEnabled(const WId windowId, const bool enable); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool installWindowProcHook(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool uninstallWindowProcHook(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool setAeroSnappingEnabled(const QWindow *window, const bool enable); [[nodiscard]] FRAMELESSHELPER_CORE_API bool tryToEnableHighestDpiAwarenessLevel(); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateGlobalWin32ControlsTheme(const WId windowId, const bool dark); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateGlobalWin32ControlsTheme(const QWindow *window, const bool dark); [[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_windows(); [[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_windows(); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool setCornerStyleForWindow(const WId windowId, const Global::WindowCornerStyle style); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool hideOriginalTitleBarElements - (const WId windowId, const bool disable = true); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool setCornerStyleForWindow(const QWindow *window, const Global::WindowCornerStyle style); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool hideOriginalTitleBarElements(const QWindow *window, const bool disable = true); [[nodiscard]] FRAMELESSHELPER_CORE_API bool setQtDarkModeAwareEnabled(const bool enable); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool refreshWin32ThemeResources(const WId windowId, const bool dark); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool enableNonClientAreaDpiScalingForWindow(const WId windowId); -[[nodiscard]] FRAMELESSHELPER_CORE_API - Global::DpiAwareness getDpiAwarenessForCurrentProcess(bool *highest = nullptr); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool fixupChildWindowsDpiMessage(const WId windowId); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool refreshWin32ThemeResources(const QWindow *window, const bool dark); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool enableNonClientAreaDpiScalingForWindow(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_CORE_API Global::DpiAwareness getDpiAwarenessForCurrentProcess(bool *highest = nullptr); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool fixupChildWindowsDpiMessage(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API bool fixupDialogsDpiScaling(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool setDarkModeAllowedForApp(const bool allow = true); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool bringWindowToFront(const WId windowId); -[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const WId windowId); -[[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const WId windowId); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool removeMicaWindow(const WId windowId); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool bringWindowToFront(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool removeMicaWindow(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API quint64 getKeyState(); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const WId windowId); -[[nodiscard]] FRAMELESSHELPER_CORE_API QMargins getWindowSystemFrameMargins(const WId windowId); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool isValidWindow(const QWindow *window, const bool checkVisible, const bool checkTopLevel); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_CORE_API QMargins getWindowSystemFrameMargins(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API QMargins getWindowCustomFrameMargins(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API bool updateAllDirectXSurfaces(); FRAMELESSHELPER_CORE_API void printWin32Message(void *msg); #endif // Q_OS_WINDOWS #if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) -[[nodiscard]] FRAMELESSHELPER_CORE_API QScreen *x11_findScreenForVirtualDesktop - (const int virtualDesktopNumber); +[[nodiscard]] FRAMELESSHELPER_CORE_API QScreen *x11_findScreenForVirtualDesktop(const int virtualDesktopNumber); [[nodiscard]] FRAMELESSHELPER_CORE_API x11_return_type x11_appRootWindow(const int screen); [[nodiscard]] FRAMELESSHELPER_CORE_API int x11_appScreen(); [[nodiscard]] FRAMELESSHELPER_CORE_API x11_return_type x11_appTime(); @@ -166,32 +150,27 @@ FRAMELESSHELPER_CORE_API void printWin32Message(void *msg); [[nodiscard]] FRAMELESSHELPER_CORE_API QByteArray x11_nextStartupId(); [[nodiscard]] FRAMELESSHELPER_CORE_API Display *x11_display(); [[nodiscard]] FRAMELESSHELPER_CORE_API xcb_connection_t *x11_connection(); -[[nodiscard]] FRAMELESSHELPER_CORE_API QByteArray getWindowProperty - (const WId windowId, const xcb_atom_t prop, const xcb_atom_t type, const quint32 data_len); -FRAMELESSHELPER_CORE_API void setWindowProperty - (const WId windowId, const xcb_atom_t prop, const xcb_atom_t type, - const void *data, const quint32 data_len, const uint8_t format); -FRAMELESSHELPER_CORE_API void clearWindowProperty(const WId windowId, const xcb_atom_t prop); +[[nodiscard]] FRAMELESSHELPER_CORE_API QByteArray getWindowProperty(const QWindow *window, const xcb_atom_t prop, const xcb_atom_t type, const quint32 data_len); +FRAMELESSHELPER_CORE_API void setWindowProperty(const QWindow *window, const xcb_atom_t prop, const xcb_atom_t type, const void *data, const quint32 data_len, const uint8_t format); +FRAMELESSHELPER_CORE_API void clearWindowProperty(const QWindow *window, const xcb_atom_t prop); [[nodiscard]] FRAMELESSHELPER_CORE_API xcb_atom_t internAtom(const char *name); [[nodiscard]] FRAMELESSHELPER_CORE_API QString getWindowManagerName(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isSupportedByWindowManager(const xcb_atom_t atom); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isSupportedByRootWindow(const xcb_atom_t atom); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool tryHideSystemTitleBar(const WId windowId, const bool hide = true); -FRAMELESSHELPER_CORE_API void openSystemMenu(const WId windowId, const QPoint &globalPos); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool tryHideSystemTitleBar(const QWindow *window, const bool hide = true); +FRAMELESSHELPER_CORE_API void openSystemMenu(const QWindow *window, const QPoint &globalPos); [[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_linux(); [[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_linux(); -FRAMELESSHELPER_CORE_API void sendMoveResizeMessage - (const WId windowId, const uint32_t action, const QPoint &globalPos, const Qt::MouseButton button = Qt::LeftButton); +FRAMELESSHELPER_CORE_API void sendMoveResizeMessage(const QWindow *window, const uint32_t action, const QPoint &globalPos, const Qt::MouseButton button = Qt::LeftButton); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isCustomDecorationSupported(); -[[nodiscard]] FRAMELESSHELPER_CORE_API bool - setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &props); +[[nodiscard]] FRAMELESSHELPER_CORE_API bool setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &props); #endif // Q_OS_LINUX #ifdef Q_OS_MACOS [[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_macos(); [[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_macos(); -FRAMELESSHELPER_CORE_API void setSystemTitleBarVisible(const WId windowId, const bool visible); -FRAMELESSHELPER_CORE_API void removeWindowProxy(const WId windowId); +FRAMELESSHELPER_CORE_API void setSystemTitleBarVisible(const QWindow *window, const bool visible); +FRAMELESSHELPER_CORE_API void removeWindowProxy(const QWindow *window); #endif // Q_OS_MACOS } // namespace Utils diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9afd116..b7935af 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -35,18 +35,18 @@ if(UNIX AND NOT APPLE) endif() find_package(X11 QUIET COMPONENTS xcb) if(TARGET X11::xcb) - message("Found system XCB. The XCB wrapper will be disabled.") + message(STATUS "--- Found system XCB. The XCB wrapper will be disabled.") else() - message("System XCB not found. The XCB wrapper will be used instead.") + message(STATUS "--- System XCB not found. The XCB wrapper will be used instead.") endif() find_package(PkgConfig QUIET) if(PkgConfig_FOUND) pkg_check_modules(GTK3 QUIET IMPORTED_TARGET gtk+-3.0) endif() if(TARGET PkgConfig::GTK3) - message("Found system GTK. The GTK wrapper will be disabled.") + message(STATUS "--- Found system GTK. The GTK wrapper will be disabled.") else() - message("System GTK not found. The GTK wrapper will be used instead.") + message(STATUS "--- System GTK not found. The GTK wrapper will be used instead.") endif() endif() @@ -61,14 +61,12 @@ set(PUBLIC_HEADERS ${FRAMELESSHELPER_VERSION_FILE} ${FRAMELESSHELPER_CONFIG_FILE} ${INCLUDE_PREFIX}/framelesshelpercore_global.h - ${INCLUDE_PREFIX}/framelesshelper_qt.h ${INCLUDE_PREFIX}/framelessmanager.h ${INCLUDE_PREFIX}/utils.h ) set(PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/Global - ${INCLUDE_PREFIX}/FramelessHelper_Qt ${INCLUDE_PREFIX}/FramelessManager ${INCLUDE_PREFIX}/Utils ) @@ -84,7 +82,6 @@ set(PRIVATE_HEADERS set(SOURCES utils.cpp - framelesshelper_qt.cpp framelessmanager.cpp framelessconfig.cpp sysapiloader.cpp @@ -92,14 +89,8 @@ set(SOURCES ) if(WIN32) - list(APPEND PUBLIC_HEADERS - ${INCLUDE_PREFIX}/framelesshelper_windows.h - ${INCLUDE_PREFIX}/framelesshelper_win.h - ) - list(APPEND PUBLIC_HEADERS_ALIAS - ${INCLUDE_PREFIX}/FramelessHelper_Windows - ${INCLUDE_PREFIX}/FramelessHelper_Win - ) + list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_windows.h) + list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Windows) list(APPEND PRIVATE_HEADERS ${INCLUDE_PREFIX}/private/registrykey_p.h ${INCLUDE_PREFIX}/private/winverhelper_p.h @@ -107,25 +98,35 @@ if(WIN32) list(APPEND SOURCES registrykey.cpp utils_win.cpp - framelesshelper_win.cpp winverhelper.cpp platformsupport_win.cpp ) elseif(APPLE) list(APPEND SOURCES utils_mac.mm) elseif(UNIX) - list(APPEND PUBLIC_HEADERS - ${INCLUDE_PREFIX}/framelesshelper_linux.h - ) - list(APPEND PUBLIC_HEADERS_ALIAS - ${INCLUDE_PREFIX}/FramelessHelper_Linux - ) + list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_linux.h) + list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Linux) list(APPEND SOURCES utils_linux.cpp platformsupport_linux.cpp ) endif() +if(FRAMELESSHELPER_NATIVE_IMPL) + if(WIN32) + list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_win.h) + list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Win) + list(APPEND SOURCES framelesshelper_win.cpp) + elseif(APPLE) + elseif(UNIX) + else() + endif() +else() + list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_qt.h) + list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Qt) + list(APPEND SOURCES framelesshelper_qt.cpp) +endif() + if(NOT FRAMELESSHELPER_NO_TITLEBAR) list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/chromepalette.h) list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/ChromePalette) diff --git a/src/core/framelesshelper_qt.cpp b/src/core/framelesshelper_qt.cpp index a5e663a..fea2215 100644 --- a/src/core/framelesshelper_qt.cpp +++ b/src/core/framelesshelper_qt.cpp @@ -23,6 +23,9 @@ */ #include "framelesshelper_qt.h" + +#if !FRAMELESSHELPER_CONFIG(native_impl) + #include "framelessmanager.h" #include "framelessmanager_p.h" #include "framelessconfig_p.h" @@ -49,39 +52,36 @@ FRAMELESSHELPER_BEGIN_NAMESPACE using namespace Global; -struct FramelessQtHelperData +using FramelessHelperQtPtr = std::shared_ptr; +#define CreateFramelessHelperQt(...) std::make_shared(__VA_ARGS__) + +struct FramelessDataQt : public FramelessData { - SystemParameters params = {}; - FramelessHelperQt *eventFilter = nullptr; + FramelessHelperQtPtr eventFilter = nullptr; bool cursorShapeChanged = false; bool leftButtonPressed = false; }; +using FramelessDataQtPtr = std::shared_ptr; +#define CreateFramelessDataQt(...) std::make_shared(__VA_ARGS__) -using FramelessQtHelperInternal = QHash; - -Q_GLOBAL_STATIC(FramelessQtHelperInternal, g_framelessQtHelperData) +[[nodiscard]] FramelessDataQtPtr CreateEmptyDataQt() { return CreateFramelessDataQt(); } FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent) {} FramelessHelperQt::~FramelessHelperQt() = default; -void FramelessHelperQt::addWindow(FramelessParamsConst params) +void FramelessHelperQt::addWindow(const QWindow *window) { - Q_ASSERT(params); - if (!params) { + Q_ASSERT(window); + if (!window) { return; } - const WId windowId = params->getWindowId(); - const auto it = g_framelessQtHelperData()->constFind(windowId); - if (it != g_framelessQtHelperData()->constEnd()) { + const auto data = std::dynamic_pointer_cast(FramelessManagerPrivate::getData(window)); + Q_ASSERT(data->callbacks); + if (!data->callbacks) { return; } - FramelessQtHelperData data = {}; - data.params = *params; - QWindow *window = params->getWindowHandle(); - // Give it a parent so that it can be automatically deleted by Qt. - data.eventFilter = new FramelessHelperQt(window); - g_framelessQtHelperData()->insert(windowId, data); + data->eventFilter = CreateFramelessHelperQt(); const auto shouldApplyFramelessFlag = []() -> bool { #ifdef Q_OS_MACOS return false; @@ -95,31 +95,32 @@ void FramelessHelperQt::addWindow(FramelessParamsConst params) window->setProperty("_q_mac_wantsLayer", 1); #endif // (defined(Q_OS_MACOS) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))) if (shouldApplyFramelessFlag) { - params->setWindowFlags(params->getWindowFlags() | Qt::FramelessWindowHint); + data->callbacks->setWindowFlags(data->callbacks->getWindowFlags() | Qt::FramelessWindowHint); } else { #if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) - std::ignore = Utils::tryHideSystemTitleBar(windowId, true); + std::ignore = Utils::tryHideSystemTitleBar(window, true); #elif defined(Q_OS_MACOS) - Utils::setSystemTitleBarVisible(windowId, false); + Utils::setSystemTitleBarVisible(window, false); #endif // Q_OS_LINUX } - window->installEventFilter(data.eventFilter); + const_cast(window)->installEventFilter(data->eventFilter.get()); FramelessHelperEnableThemeAware(); } -void FramelessHelperQt::removeWindow(const WId windowId) +void FramelessHelperQt::removeWindow(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return; } - const auto it = g_framelessQtHelperData()->constFind(windowId); - if (it == g_framelessQtHelperData()->constEnd()) { - return; + const auto data = std::dynamic_pointer_cast(FramelessManagerPrivate::getData(window)); + Q_ASSERT(data->eventFilter); + if (data->eventFilter) { + const_cast(window)->removeEventFilter(data->eventFilter.get()); + data->eventFilter = nullptr; } - g_framelessQtHelperData()->erase(it); #ifdef Q_OS_MACOS - Utils::removeWindowProxy(windowId); + Utils::removeWindowProxy(window); #endif } @@ -159,21 +160,15 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) ) { return QObject::eventFilter(object, event); } - const auto window = qobject_cast(object); - const WId windowId = window->winId(); - const auto it = g_framelessQtHelperData()->find(windowId); - if (it == g_framelessQtHelperData()->end()) { - return QObject::eventFilter(object, event); - } - const FramelessQtHelperData &data = it.value(); - FramelessQtHelperData &muData = it.value(); + const auto window = qobject_cast(object); + const auto data = std::dynamic_pointer_cast(FramelessManagerPrivate::getData(window)); #if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) if (type == QEvent::DevicePixelRatioChange) #else // QT_VERSION < QT_VERSION_CHECK(6, 6, 0) if (type == QEvent::ScreenChangeInternal) #endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) { - data.params.forceChildrenRepaint(500); + data->callbacks->forceChildrenRepaint(500); return QObject::eventFilter(object, event); } const auto mouseEvent = static_cast(event); @@ -185,64 +180,63 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) const QPoint scenePos = mouseEvent->windowPos().toPoint(); const QPoint globalPos = mouseEvent->screenPos().toPoint(); #endif - const bool windowFixedSize = data.params.isWindowFixedSize(); - const bool ignoreThisEvent = data.params.shouldIgnoreMouseEvents(scenePos); - const bool insideTitleBar = data.params.isInsideTitleBarDraggableArea(scenePos); - const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool(); - const bool dontToggleMaximize = data.params.getProperty(kDontToggleMaximizeVar, false).toBool(); + const bool windowFixedSize = data->callbacks->isWindowFixedSize(); + const bool ignoreThisEvent = data->callbacks->shouldIgnoreMouseEvents(scenePos); + const bool insideTitleBar = data->callbacks->isInsideTitleBarDraggableArea(scenePos); + const bool dontOverrideCursor = data->callbacks->getProperty(kDontOverrideCursorVar, false).toBool(); + const bool dontToggleMaximize = data->callbacks->getProperty(kDontToggleMaximizeVar, false).toBool(); switch (type) { - case QEvent::MouseButtonPress: { + case QEvent::MouseButtonPress: if (button == Qt::LeftButton) { - muData.leftButtonPressed = true; + data->leftButtonPressed = true; if (!windowFixedSize) { const Qt::Edges edges = Utils::calculateWindowEdges(window, scenePos); if (edges != Qt::Edges{}) { - std::ignore = Utils::startSystemResize(window, edges, globalPos); + std::ignore = Utils::startSystemResize(const_cast(window), edges, globalPos); event->accept(); return true; } } } - } break; - case QEvent::MouseButtonRelease: { + break; + case QEvent::MouseButtonRelease: if (button == Qt::LeftButton) { - muData.leftButtonPressed = false; - } - if (button == Qt::RightButton) { + data->leftButtonPressed = false; + } else if (button == Qt::RightButton) { if (!ignoreThisEvent && insideTitleBar) { - data.params.showSystemMenu(globalPos); + data->callbacks->showSystemMenu(globalPos); event->accept(); return true; } } - } break; - case QEvent::MouseButtonDblClick: { + break; + case QEvent::MouseButtonDblClick: if (!dontToggleMaximize && (button == Qt::LeftButton) && !windowFixedSize && !ignoreThisEvent && insideTitleBar) { Qt::WindowState newWindowState = Qt::WindowNoState; - if (data.params.getWindowState() != Qt::WindowMaximized) { + if (data->callbacks->getWindowState() != Qt::WindowMaximized) { newWindowState = Qt::WindowMaximized; } - data.params.setWindowState(newWindowState); + data->callbacks->setWindowState(newWindowState); event->accept(); return true; } - } break; + break; case QEvent::MouseMove: { if (!dontOverrideCursor && !windowFixedSize) { const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos); if (cs == Qt::ArrowCursor) { - if (data.cursorShapeChanged) { - data.params.unsetCursor(); - muData.cursorShapeChanged = false; + if (data->cursorShapeChanged) { + data->callbacks->unsetCursor(); + data->cursorShapeChanged = false; } } else { - data.params.setCursor(cs); - muData.cursorShapeChanged = true; + data->callbacks->setCursor(cs); + data->cursorShapeChanged = true; } } - if (data.leftButtonPressed) { + if (data->leftButtonPressed) { if (!ignoreThisEvent && insideTitleBar) { - std::ignore = Utils::startSystemMove(window, globalPos); + std::ignore = Utils::startSystemMove(const_cast(window), globalPos); event->accept(); return true; } @@ -255,3 +249,5 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) } FRAMELESSHELPER_END_NAMESPACE + +#endif // !native_impl diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 78ee8d6..9b9552a 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -26,6 +26,8 @@ #ifdef Q_OS_WINDOWS +#if FRAMELESSHELPER_CONFIG(native_impl) + #include "framelessmanager.h" #include "framelessmanager_p.h" #include "framelessconfig_p.h" @@ -100,9 +102,8 @@ enum class WindowPart : quint8 TitleBar }; -struct FramelessWin32HelperData +struct FramelessDataWin : public FramelessData { - SystemParameters params = {}; // Store the last hit test result, it's helpful to handle WM_MOUSEMOVE and WM_NCMOUSELEAVE. WindowPart lastHitTestResult = WindowPart::Outside; // True if we blocked a WM_MOUSELEAVE when mouse moves on chrome button, false when a @@ -113,23 +114,16 @@ struct FramelessWin32HelperData QRect restoreGeometry = {}; #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) }; +#define CreateFramelessDataWin(...) std::make_shared(__VA_ARGS__) -struct FramelessWin32HelperInternal +#define GetFramelessDataWin(Window) std::dynamic_pointer_cast(FramelessManagerPrivate::getData(Window)) + +[[nodiscard]] FramelessDataPtr FramelessData::create() { - std::unique_ptr nativeEventFilter = nullptr; - QHash data = {}; -}; + return CreateFramelessDataWin(); +} -Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData) - -[[nodiscard]] extern bool operator==(const POINT &lhs, const POINT &rhs) noexcept; -[[nodiscard]] extern bool operator!=(const POINT &lhs, const POINT &rhs) noexcept; - -[[nodiscard]] extern bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept; -[[nodiscard]] extern bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept; - -[[nodiscard]] extern bool operator==(const RECT &lhs, const RECT &rhs) noexcept; -[[nodiscard]] extern bool operator!=(const RECT &lhs, const RECT &rhs) noexcept; +static std::unique_ptr g_framelessHelperWin = nullptr; [[nodiscard]] extern QPoint point2qpoint(const POINT &point); [[nodiscard]] extern POINT qpoint2point(const QPoint &point); @@ -140,7 +134,6 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData) [[nodiscard]] extern QRect rect2qrect(const RECT &rect); [[nodiscard]] extern RECT qrect2rect(const QRect &qrect); -[[nodiscard]] extern QString hwnd2str(const WId windowId); [[nodiscard]] extern QString hwnd2str(const HWND hwnd); [[nodiscard]] extern std::optional getMonitorForWindow(const HWND hwnd); @@ -212,31 +205,28 @@ FramelessHelperWin::FramelessHelperWin() : QAbstractNativeEventFilter() {} FramelessHelperWin::~FramelessHelperWin() = default; -void FramelessHelperWin::addWindow(FramelessParamsConst params) +void FramelessHelperWin::addWindow(const QWindow *window) { - Q_ASSERT(params); - if (!params) { + Q_ASSERT(window); + if (!window) { return; } - const WId windowId = params->getWindowId(); - const auto it = g_framelessWin32HelperData()->data.constFind(windowId); - if (it != g_framelessWin32HelperData()->data.constEnd()) { + const auto data = GetFramelessDataWin(window); + Q_ASSERT(data); + if (!data || data->frameless) { return; } - FramelessWin32HelperData data = {}; - data.params = *params; - data.dpi = {Utils::getWindowDpi(windowId, true), Utils::getWindowDpi(windowId, false)}; - g_framelessWin32HelperData()->data.insert(windowId, data); - if (!g_framelessWin32HelperData()->nativeEventFilter) { - g_framelessWin32HelperData()->nativeEventFilter = std::make_unique(); - qApp->installNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get()); + data->frameless = true; + data->dpi = Dpi{ Utils::getWindowDpi(window, true), Utils::getWindowDpi(window, false) }; + if (!g_framelessHelperWin) { + g_framelessHelperWin = std::make_unique(); + qApp->installNativeEventFilter(g_framelessHelperWin.get()); } - DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data.dpi; - const QWindow *window = params->getWindowHandle(); + DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data->dpi; // Remove the bad window styles added by Qt (it's not that "bad" though). - std::ignore = Utils::maybeFixupQtInternals(windowId); + std::ignore = Utils::maybeFixupQtInternals(window); #if 0 - params->setWindowFlags(params->getWindowFlags() | Qt::FramelessWindowHint); + data->callbacks->setWindowFlags(data->callbacks->getWindowFlags() | Qt::FramelessWindowHint); #else // Qt maintains a frame margin internally, we need to update it accordingly // otherwise we'll get lots of warning messages when we change the window @@ -245,57 +235,51 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params) std::ignore = Utils::updateInternalWindowFrameMargins(const_cast(window), true); #endif // Tell DWM our preferred frame margin. - std::ignore = Utils::updateWindowFrameMargins(windowId, false); + std::ignore = Utils::updateWindowFrameMargins(window, false); // Tell DWM we don't use the window icon/caption/sysmenu, don't draw them. - std::ignore = Utils::hideOriginalTitleBarElements(windowId); + std::ignore = Utils::hideOriginalTitleBarElements(window); // Without this hack, the child windows can't get DPI change messages from // Windows, which means only the top level windows can be scaled to the correct // size, we of course don't want such thing from happening. - std::ignore = Utils::fixupChildWindowsDpiMessage(windowId); + std::ignore = Utils::fixupChildWindowsDpiMessage(window); if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) { - std::ignore = Utils::updateFramebufferTransparency(windowId); + std::ignore = Utils::updateFramebufferTransparency(window); } if (WindowsVersionHelper::isWin10RS1OrGreater()) { // Tell DWM we may need dark theme non-client area (title bar & frame border). FramelessHelperEnableThemeAware(); if (WindowsVersionHelper::isWin10RS5OrGreater()) { const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark); - const auto isWidget = [params]() -> bool { - const QObject *widget = params->getWidgetHandle(); + const auto isWidget = [data]() -> bool { + const QObject *widget = data->callbacks->getWidgetHandle(); return (widget && widget->isWidgetType()); }(); if (!isWidget) { // Tell UXTheme we may need dark theme controls. // Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications. - std::ignore = Utils::updateGlobalWin32ControlsTheme(windowId, dark); + std::ignore = Utils::updateGlobalWin32ControlsTheme(window, dark); } - std::ignore = Utils::refreshWin32ThemeResources(windowId, dark); + std::ignore = Utils::refreshWin32ThemeResources(window, dark); if (WindowsVersionHelper::isWin11OrGreater()) { if (FramelessConfig::instance()->isSet(Option::WindowUseSquareCorners)) { - std::ignore = Utils::setCornerStyleForWindow(windowId, WindowCornerStyle::Square); + std::ignore = Utils::setCornerStyleForWindow(window, WindowCornerStyle::Square); } } } } } -void FramelessHelperWin::removeWindow(const WId windowId) +void FramelessHelperWin::removeWindow(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return; } - const auto it = g_framelessWin32HelperData()->data.constFind(windowId); - if (it == g_framelessWin32HelperData()->data.constEnd()) { + const auto data = GetFramelessDataWin(window); + if (!data || !data->frameless) { return; } - g_framelessWin32HelperData()->data.erase(it); - if (g_framelessWin32HelperData()->data.isEmpty()) { - if (g_framelessWin32HelperData()->nativeEventFilter) { - qApp->removeNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get()); - g_framelessWin32HelperData()->nativeEventFilter.reset(); - } - } + data->frameless = false; } bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) @@ -317,15 +301,20 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // Anyway, we should skip the entire processing in this case. return false; } - const auto windowId = reinterpret_cast(hWnd); + const QWindow *window = Utils::findWindow(reinterpret_cast(hWnd)); + const auto data = GetFramelessDataWin(window); + Q_ASSERT(data); + if (!data || !data->frameless) { + return false; + } // Let's be extra safe. - if (!Utils::isValidWindow(windowId, false, true)) { + if (!Utils::isValidWindow(window, false, true)) { return false; } const UINT uMsg = msg->message; // We should skip these messages otherwise we will get crashes. - // WM_QUIT won't be posted to the WindowProc function. + // NOTE: WM_QUIT won't be posted to the WindowProc function. switch (uMsg) { case WM_CLOSE: case WM_DESTROY: @@ -338,23 +327,16 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me break; } - const auto it = g_framelessWin32HelperData()->data.find(windowId); - if (it == g_framelessWin32HelperData()->data.end()) { - return false; - } - const FramelessWin32HelperData &data = it.value(); - FramelessWin32HelperData &muData = it.value(); - const QWindow *window = data.params.getWindowHandle(); const bool frameBorderVisible = Utils::isWindowFrameBorderVisible(); const WPARAM wParam = msg->wParam; const LPARAM lParam = msg->lParam; #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) - const auto updateRestoreGeometry = [windowId, &data, &muData](const bool ignoreWindowState) -> void { - if (!ignoreWindowState && !Utils::isWindowNoState(windowId)) { + const auto updateRestoreGeometry = [window](const bool ignoreWindowState) -> void { + if (!ignoreWindowState && !Utils::isWindowNoState(window)) { return; } - const QRect rect = Utils::getWindowRestoreGeometry(windowId); + const QRect rect = Utils::getWindowRestoreGeometry(window); if (!Utils::isValidGeometry(rect)) { WARNING << "The calculated restore geometry is invalid."; return; @@ -1315,4 +1297,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me FRAMELESSHELPER_END_NAMESPACE +#endif // native_impl + #endif // Q_OS_WINDOWS diff --git a/src/core/framelessmanager.cpp b/src/core/framelessmanager.cpp index 4dedaf6..3114da9 100644 --- a/src/core/framelessmanager.cpp +++ b/src/core/framelessmanager.cpp @@ -59,9 +59,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE using namespace Global; -using FramelessManagerData = QList; - -Q_GLOBAL_STATIC(FramelessManagerData, g_framelessManagerData) +Q_GLOBAL_STATIC(FramelessDataHash, g_internalData) static constexpr const int kEventDelayInterval = 1000; @@ -133,7 +131,7 @@ void FramelessManagerPrivate::initializeIconFont() return; } inited = true; - framelesshelpercore_initResource(); + FramelessHelperCoreInitResource(); // We always register this font because it's our only fallback. const int id = QFontDatabase::addApplicationFont(FRAMELESSHELPER_STRING_LITERAL(":/org.wangwenx190.FramelessHelper/resources/fonts/iconfont.ttf")); if (id < 0) { @@ -229,6 +227,19 @@ void FramelessManagerPrivate::doNotifyWallpaperHasChangedOrNot() } } +FramelessDataPtr FramelessManagerPrivate::getData(const QWindow *window) +{ + Q_ASSERT(window); + if (!window) { + return nullptr; + } + auto it = g_internalData()->find(window); + if (it == g_internalData()->end()) { + it = g_internalData()->insert(window, FramelessData::create()); + } + return it.value(); +} + bool FramelessManagerPrivate::isThemeOverrided() const { return (overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown); @@ -299,6 +310,15 @@ FramelessManager *FramelessManager::instance() return &manager; } +bool FramelessManager::isFramelessWindow(const QWindow *window) const +{ + Q_ASSERT(window); + if (!window) { + return false; + } + return FramelessManagerPrivate::getData(window)->isFrameless; +} + SystemTheme FramelessManager::systemTheme() const { Q_D(const FramelessManager); @@ -342,51 +362,54 @@ void FramelessManager::setOverrideTheme(const SystemTheme theme) Q_EMIT systemThemeChanged(); } -void FramelessManager::addWindow(FramelessParamsConst params) +bool FramelessManager::addWindow(const QWindow *window) { - Q_ASSERT(params); - if (!params) { - return; + Q_ASSERT(window); + if (!window) { + return false; } - const WId windowId = params->getWindowId(); - if (g_framelessManagerData()->contains(windowId)) { - return; + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); + if (data->isFrameless) { + return false; } - g_framelessManagerData()->append(windowId); - static const bool pureQt = usePureQtImplementation(); + data->isFrameless = true; + const bool pureQt = usePureQtImplementation(); if (pureQt) { - FramelessHelperQt::addWindow(params); + FramelessHelperQt::addWindow(window); } #ifdef Q_OS_WINDOWS if (!pureQt) { - FramelessHelperWin::addWindow(params); + FramelessHelperWin::addWindow(window); } - std::ignore = Utils::installWindowProcHook(windowId, params); + std::ignore = Utils::installWindowProcHook(window); #endif - connect(params->getWindowHandle(), &QWindow::destroyed, FramelessManager::instance(), [this, windowId](){ removeWindow(windowId); }); + connect(window, &QWindow::destroyed, FramelessManager::instance(), [this, window](){ std::ignore = removeWindow(window); }); + return true; } -void FramelessManager::removeWindow(const WId windowId) +bool FramelessManager::removeWindow(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { - return; + Q_ASSERT(window); + if (!window) { + return false; } - if (!g_framelessManagerData()->contains(windowId)) { - return; + const auto it = g_internalData()->constFind(window); + if ((it == g_internalData()->constEnd()) || !it.value()->isFrameless) { + return false; } - g_framelessManagerData()->removeAll(windowId); - static const bool pureQt = usePureQtImplementation(); + const bool pureQt = usePureQtImplementation(); if (pureQt) { - FramelessHelperQt::removeWindow(windowId); + FramelessHelperQt::removeWindow(window); } #ifdef Q_OS_WINDOWS if (!pureQt) { - FramelessHelperWin::removeWindow(windowId); + FramelessHelperWin::removeWindow(window); } - std::ignore = Utils::uninstallWindowProcHook(windowId); - std::ignore = Utils::removeMicaWindow(windowId); + std::ignore = Utils::uninstallWindowProcHook(window); + std::ignore = Utils::removeMicaWindow(window); #endif + g_internalData()->erase(it); + return true; } FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/micamaterial.cpp b/src/core/micamaterial.cpp index ad9c53c..f4763a9 100644 --- a/src/core/micamaterial.cpp +++ b/src/core/micamaterial.cpp @@ -657,7 +657,7 @@ void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force) void MicaMaterialPrivate::updateMaterialBrush() { #if FRAMELESSHELPER_CONFIG(bundle_resource) - framelesshelpercore_initResource(); + FramelessHelperCoreInitResource(); static const QImage noiseTexture = QImage(FRAMELESSHELPER_STRING_LITERAL(":/org.wangwenx190.FramelessHelper/resources/images/noise.png")); #endif // FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE QImage micaTexture = QImage(QSize(64, 64), kDefaultImageFormat); diff --git a/src/core/utils.cpp b/src/core/utils.cpp index 00381e0..354a9b2 100644 --- a/src/core/utils.cpp +++ b/src/core/utils.cpp @@ -210,29 +210,35 @@ QWindow *Utils::findWindow(const WId windowId) return nullptr; } -void Utils::moveWindowToDesktopCenter(FramelessParamsConst params, const bool considerTaskBar) +bool Utils::moveWindowToDesktopCenter(const QWindow *window, const bool considerTaskBar) { - Q_ASSERT(params); - if (!params) { - return; + Q_ASSERT(window); + if (!window) { + return false; } - const QSize windowSize = params->getWindowSize(); - if (windowSize.isEmpty() || (windowSize == kDefaultWindowSize)) { - return; + const FramelessDataPtr data = FramelessHelperExtractData(window); + Q_ASSERT(data); + if (!data) { + return false; } - const QScreen *screen = params->getWindowScreen(); + const QSize windowSize = data->callbacks.getWindowSize(); + if (windowSize.isEmpty() || (windowSize <= kDefaultWindowSize)) { + return false; + } + const QScreen *screen = data->callbacks.getWindowScreen(); if (!screen) { screen = QGuiApplication::primaryScreen(); } Q_ASSERT(screen); if (!screen) { - return; + return false; } const QSize screenSize = (considerTaskBar ? screen->availableSize() : screen->size()); const QPoint offset = (considerTaskBar ? screen->availableGeometry().topLeft() : QPoint(0, 0)); const int newX = std::round(qreal(screenSize.width() - windowSize.width()) / qreal(2)); const int newY = std::round(qreal(screenSize.height() - windowSize.height()) / qreal(2)); - params->setWindowPosition(QPoint(newX + offset.x(), newY + offset.y())); + data->callbacks.setWindowPosition(QPoint(newX + offset.x(), newY + offset.y())); + return true; } Qt::WindowState Utils::windowStatesToWindowState(const Qt::WindowStates states) @@ -314,9 +320,9 @@ bool Utils::shouldAppsUseDarkMode() qreal Utils::roundScaleFactor(const qreal factor) { // Qt can't handle scale factors less than 1.0 (according to the comments in qhighdpiscaling.cpp). - Q_ASSERT((factor > 1) || qFuzzyCompare(factor, qreal(1))); - if (factor < 1) { - return 1; + Q_ASSERT((factor > qreal(1)) || qFuzzyCompare(factor, qreal(1))); + if (factor < qreal(1)) { + return qreal(1); } #if (!FRAMELESSHELPER_CONFIG(private_qt) || (QT_VERSION < QT_VERSION_CHECK(6, 2, 1))) # if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 10e078f..68ccc75 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -193,16 +193,9 @@ FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient) FRAMELESSHELPER_STRING_CONSTANT(DwmFlush) FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos) -struct Win32UtilsData -{ - SystemParameters params = {}; -}; - struct Win32UtilsInternal { - QHash data = {}; WNDPROC qtWindowProc = nullptr; - QList micaWindowIds = {}; }; Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData) @@ -583,57 +576,6 @@ static constexpr const std::array g_win32MessageMap = }; #undef DEFINE_WIN32_MESSAGE -[[nodiscard]] bool operator==(const POINT &lhs, const POINT &rhs) noexcept -{ - return ((lhs.x == rhs.x) && (lhs.y == rhs.y)); -} - -[[nodiscard]] bool operator!=(const POINT &lhs, const POINT &rhs) noexcept -{ - return !operator==(lhs, rhs); -} - -[[nodiscard]] bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept -{ - return ((lhs.cx == rhs.cx) && (lhs.cy == rhs.cy)); -} - -[[nodiscard]] bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept -{ - return !operator==(lhs, rhs); -} - -[[nodiscard]] bool operator>(const SIZE &lhs, const SIZE &rhs) noexcept -{ - return ((lhs.cx * lhs.cy) > (rhs.cx * rhs.cy)); -} - -[[nodiscard]] bool operator>=(const SIZE &lhs, const SIZE &rhs) noexcept -{ - return (operator>(lhs, rhs) || operator==(lhs, rhs)); -} - -[[nodiscard]] bool operator<(const SIZE &lhs, const SIZE &rhs) noexcept -{ - return (operator!=(lhs, rhs) && !operator>(lhs, rhs)); -} - -[[nodiscard]] bool operator<=(const SIZE &lhs, const SIZE &rhs) noexcept -{ - return (operator<(lhs, rhs) || operator==(lhs, rhs)); -} - -[[nodiscard]] bool operator==(const RECT &lhs, const RECT &rhs) noexcept -{ - return ((lhs.left == rhs.left) && (lhs.top == rhs.top) - && (lhs.right == rhs.right) && (lhs.bottom == rhs.bottom)); -} - -[[nodiscard]] bool operator!=(const RECT &lhs, const RECT &rhs) noexcept -{ - return !operator==(lhs, rhs); -} - [[nodiscard]] QPoint point2qpoint(const POINT &point) { return QPoint{ int(point.x), int(point.y) }; @@ -664,16 +606,10 @@ static constexpr const std::array g_win32MessageMap = return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) }; } -[[nodiscard]] QString hwnd2str(const WId windowId) -{ - // NULL handle is allowed here. - return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(windowId, 16).toUpper().rightJustified(8, u'0'); -} - [[nodiscard]] QString hwnd2str(const HWND hwnd) { // NULL handle is allowed here. - return hwnd2str(reinterpret_cast(hwnd)); + return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(reinterpret_cast(hwnd), 16).toUpper().rightJustified(8, u'0'); } [[nodiscard]] std::optional getMonitorForWindow(const HWND hwnd) @@ -734,8 +670,7 @@ static constexpr const std::array g_win32MessageMap = static const auto currentOsVer = []() -> std::optional { if (API_NT_AVAILABLE(RtlGetVersion)) { using RtlGetVersionPtr = _NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW); - const auto pRtlGetVersion = - reinterpret_cast(SysApiLoader::instance()->get(kntdll, kRtlGetVersion)); + const auto pRtlGetVersion = reinterpret_cast(SysApiLoader::instance()->get(kntdll, kRtlGetVersion)); RTL_OSVERSIONINFOEXW osvi; SecureZeroMemory(&osvi, sizeof(osvi)); osvi.dwOSVersionInfoSize = sizeof(osvi); @@ -785,8 +720,7 @@ static constexpr const std::array g_win32MessageMap = return kErrorMessageTemplate.arg(function, QString::number(code), errorText); #else // !FRAMELESSHELPER_CONFIG(private_qt) LPWSTR buf = nullptr; - if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&buf), 0, nullptr) == 0) { + if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&buf), 0, nullptr) == 0) { return FRAMELESSHELPER_STRING_LITERAL("FormatMessageW() returned empty string."); } const QString errorText = QString::fromWCharArray(buf).trimmed(); @@ -839,16 +773,14 @@ static constexpr const std::array g_win32MessageMap = const int newWindowY = (activeMonitorRect.top + currentWindowOffsetY); static constexpr const UINT flags = (SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER); - if (::SetWindowPos(hwnd, nullptr, newWindowX, newWindowY, - currentWindowWidth, currentWindowHeight, flags) == FALSE) { + if (::SetWindowPos(hwnd, nullptr, newWindowX, newWindowY, currentWindowWidth, currentWindowHeight, flags) == FALSE) { WARNING << Utils::getSystemErrorMessage(kSetWindowPos); return false; } return true; } -[[nodiscard]] static inline int getSystemMetrics2(const int index, const bool horizontal, - const quint32 dpi) +[[nodiscard]] static inline int getSystemMetrics2(const int index, const bool horizontal, const quint32 dpi) { Q_ASSERT(dpi != 0); if (dpi == 0) { @@ -863,14 +795,13 @@ static constexpr const std::array g_win32MessageMap = return std::round(qreal(::GetSystemMetrics(index)) / currentDpr * requestedDpr); } -[[nodiscard]] static inline int getSystemMetrics2(const WId windowId, const int index, - const bool horizontal, const bool scaled) +[[nodiscard]] static inline int getSystemMetrics2(const QWindow *window, const int index, const bool horizontal, const bool scaled) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return 0; } - const UINT realDpi = Utils::getWindowDpi(windowId, horizontal); + const UINT realDpi = Utils::getWindowDpi(window, horizontal); { const UINT dpi = (scaled ? realDpi : USER_DEFAULT_SCREEN_DPI); if (const int result = _GetSystemMetricsForDpi2(index, dpi); result > 0) { @@ -981,9 +912,13 @@ static constexpr const std::array g_win32MessageMap = Utils::printWin32Message(&message); } #endif - const auto windowId = reinterpret_cast(hWnd); - const auto it = g_win32UtilsData()->data.constFind(windowId); - if (it == g_win32UtilsData()->data.constEnd()) { + const QWindow *window = Utils::findWindow(reinterpret_cast(hWnd)); + if (!window || !FramelessManager::instance()->isFramelessWindow(window)) { + return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + const FramelessDataPtr data = FramelessHelperExtractData(window); + Q_ASSERT(data); + if (!data) { return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); } // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025 @@ -1034,26 +969,25 @@ static constexpr const std::array g_win32MessageMap = return LRESULT(filterResult); } } - const Win32UtilsData &data = it.value(); const auto getNativePosFromMouse = [lParam]() -> QPoint { return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; }; - const auto getNativeGlobalPosFromKeyboard = [hWnd, windowId]() -> QPoint { + const auto getNativeGlobalPosFromKeyboard = [hWnd, window]() -> QPoint { RECT windowPos = {}; if (::GetWindowRect(hWnd, &windowPos) == FALSE) { WARNING << Utils::getSystemErrorMessage(kGetWindowRect); return {}; } - const bool maxOrFull = (IsMaximized(hWnd) || Utils::isFullScreen(windowId)); - const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true); + const bool maxOrFull = (IsMaximized(hWnd) || Utils::isFullScreen(window)); + const int frameSizeX = Utils::getResizeBorderThickness(window, true, true); const bool frameBorderVisible = Utils::isWindowFrameBorderVisible(); const int horizontalOffset = ((maxOrFull || !frameBorderVisible) ? 0 : frameSizeX); - const auto verticalOffset = [windowId, frameBorderVisible, maxOrFull]() -> int { - const int titleBarHeight = Utils::getTitleBarHeight(windowId, true); + const auto verticalOffset = [window, frameBorderVisible, maxOrFull]() -> int { + const int titleBarHeight = Utils::getTitleBarHeight(window, true); if (!frameBorderVisible) { return titleBarHeight; } - const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); + const int frameSizeY = Utils::getResizeBorderThickness(window, false, true); if (WindowsVersionHelper::isWin11OrGreater()) { if (maxOrFull) { return (titleBarHeight + frameSizeY); @@ -1073,8 +1007,8 @@ static constexpr const std::array g_win32MessageMap = switch (uMsg) { case WM_RBUTTONUP: { const QPoint nativeLocalPos = getNativePosFromMouse(); - const QPoint qtScenePos = Utils::fromNativeLocalPosition(data.params.getWindowHandle(), nativeLocalPos); - if (data.params.isInsideTitleBarDraggableArea(qtScenePos)) { + const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, nativeLocalPos); + if (data->callbacks.isInsideTitleBarDraggableArea(qtScenePos)) { POINT pos = {nativeLocalPos.x(), nativeLocalPos.y()}; if (::ClientToScreen(hWnd, &pos) == FALSE) { WARNING << Utils::getSystemErrorMessage(kClientToScreen); @@ -1084,12 +1018,12 @@ static constexpr const std::array g_win32MessageMap = nativeGlobalPos = {pos.x, pos.y}; } } break; - case WM_NCRBUTTONUP: { + case WM_NCRBUTTONUP: if (wParam == HTCAPTION) { shouldShowSystemMenu = true; nativeGlobalPos = getNativePosFromMouse(); } - } break; + break; case WM_SYSCOMMAND: { const WPARAM filteredWParam = (wParam & 0xFFF0); if ((filteredWParam == SC_KEYMENU) && (lParam == VK_SPACE)) { @@ -1112,7 +1046,7 @@ static constexpr const std::array g_win32MessageMap = break; } if (shouldShowSystemMenu) { - std::ignore = Utils::showSystemMenu(windowId, nativeGlobalPos, broughtByKeyboard, &data.params); + std::ignore = Utils::showSystemMenu(window, nativeGlobalPos, broughtByKeyboard); // QPA's internal code will handle system menu events separately, and its // behavior is not what we would want to see because it doesn't know our // window doesn't have any window frame now, so return early here to avoid @@ -1160,23 +1094,19 @@ bool Utils::isDwmCompositionEnabled() return (enabled != FALSE); } -bool Utils::triggerFrameChange(const WId windowId) +bool Utils::triggerFrameChange(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - const auto hwnd = reinterpret_cast(windowId); - static constexpr const UINT swpFlags = - (SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE - | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); + const auto hwnd = qWindowId(window); + static constexpr const UINT swpFlags = (SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); if (::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, swpFlags) == FALSE) { WARNING << getSystemErrorMessage(kSetWindowPos); return false; } - static constexpr const UINT rdwFlags = - (RDW_ERASE | RDW_FRAME | RDW_INVALIDATE - | RDW_UPDATENOW | RDW_ALLCHILDREN); + static constexpr const UINT rdwFlags = (RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); if (::RedrawWindow(hwnd, nullptr, nullptr, rdwFlags) == FALSE) { WARNING << getSystemErrorMessage(kRedrawWindow); return false; @@ -1184,10 +1114,10 @@ bool Utils::triggerFrameChange(const WId windowId) return true; } -bool Utils::updateWindowFrameMargins(const WId windowId, const bool reset) +bool Utils::updateWindowFrameMargins(const QWindow *window, const bool reset) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) { @@ -1198,7 +1128,8 @@ bool Utils::updateWindowFrameMargins(const WId windowId, const bool reset) if (!isDwmCompositionEnabled()) { return false; } - const bool micaEnabled = g_win32UtilsData()->micaWindowIds.contains(windowId); + const FramelessDataPtr data = FramelessHelperExtractData(window); + const bool micaEnabled = (data && data->micaEnabled); const auto margins = [micaEnabled, reset]() -> MARGINS { // To make Mica/Mica Alt work for normal Win32 windows, we have to // let the window frame extend to the whole window (or disable the @@ -1213,13 +1144,13 @@ bool Utils::updateWindowFrameMargins(const WId windowId, const bool reset) } return {1, 1, 1, 1}; }(); - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmExtendFrameIntoClientArea, hwnd, &margins); if (FAILED(hr)) { WARNING << getSystemErrorMessageImpl(kDwmExtendFrameIntoClientArea, hr); return false; } - return triggerFrameChange(windowId); + return triggerFrameChange(window); } bool Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable) @@ -1228,17 +1159,16 @@ bool Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable) if (!window) { return false; } - const WId windowId = window->winId(); - const auto margins = [enable, windowId]() -> QMargins { + const auto margins = [enable, window]() -> QMargins { if (!enable) { return {}; } - const int titleBarHeight = getTitleBarHeight(windowId, true); + const int titleBarHeight = getTitleBarHeight(window, true); if (isWindowFrameBorderVisible()) { return {0, -titleBarHeight, 0, 0}; } else { - const int frameSizeX = getResizeBorderThickness(windowId, true, true); - const int frameSizeY = getResizeBorderThickness(windowId, false, true); + const int frameSizeX = getResizeBorderThickness(window, true, true); + const int frameSizeY = getResizeBorderThickness(window, false, true); return {-frameSizeX, -titleBarHeight, -frameSizeX, -frameSizeY}; } }(); @@ -1266,7 +1196,7 @@ bool Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable) } # endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #endif // FRAMELESSHELPER_CONFIG(private_qt) - return triggerFrameChange(windowId); + return triggerFrameChange(window); } QString Utils::getSystemErrorMessage(const QString &function) @@ -1342,16 +1272,23 @@ DwmColorizationArea Utils::getDwmColorizationArea() return DwmColorizationArea::None; } -bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool selectFirstEntry, - FramelessParamsConst params) +bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool selectFirstEntry) { - Q_ASSERT(windowId); - Q_ASSERT(params); - if (!windowId || !params) { + Q_ASSERT(window); + if (!window) { return false; } - const auto hWnd = reinterpret_cast(windowId); + if (!FramelessManager::instance()->isFramelessWindow(window)) { + return false; + } + const FramelessDataPtr data = FramelessHelperExtractData(window); + Q_ASSERT(data); + if (!data) { + return false; + } + + const auto hWnd = qWindowId(window); const HMENU hMenu = ::GetSystemMenu(hWnd, FALSE); if (!hMenu) { // The corresponding window doesn't have a system menu, most likely due to the @@ -1361,11 +1298,11 @@ bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool sel } // Tweak the menu items according to the current window status and user settings. - const bool disableRestore = params->getProperty(kSysMenuDisableRestoreVar, false).toBool(); - const bool disableMinimize = params->getProperty(kSysMenuDisableMinimizeVar, false).toBool(); - const bool disableMaximize = params->getProperty(kSysMenuDisableMaximizeVar, false).toBool(); - const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(windowId)); - const bool fixedSize = params->isWindowFixedSize(); + const bool disableRestore = data->callbacks.getProperty(kSysMenuDisableRestoreVar, false).toBool(); + const bool disableMinimize = data->callbacks.getProperty(kSysMenuDisableMinimizeVar, false).toBool(); + const bool disableMaximize = data->callbacks.getProperty(kSysMenuDisableMaximizeVar, false).toBool(); + const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(window)); + const bool fixedSize = data->callbacks.isWindowFixedSize(); ::EnableMenuItem(hMenu, SC_RESTORE, (MF_BYCOMMAND | ((maxOrFull && !fixedSize && !disableRestore) ? MFS_ENABLED : MFS_DISABLED))); // The first menu item should be selected by default if the menu is brought // up by keyboard. I don't know how to pre-select a menu item but it seems @@ -1399,8 +1336,7 @@ bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool sel ::SetMenuDefaultItem(hMenu, defaultItemId, FALSE); // Popup the system menu at the required position. - const int result = ::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() - ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), pos.x(), pos.y(), 0, hWnd, nullptr); + const int result = ::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), pos.x(), pos.y(), 0, hWnd, nullptr); // Unhighlight the first menu item after the popup menu is closed, otherwise it will keep // highlighting until we unhighlight it manually. @@ -1420,13 +1356,13 @@ bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool sel return true; } -bool Utils::isFullScreen(const WId windowId) +bool Utils::isFullScreen(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); RECT windowRect = {}; if (::GetWindowRect(hwnd, &windowRect) == FALSE) { WARNING << getSystemErrorMessage(kGetWindowRect); @@ -1441,13 +1377,13 @@ bool Utils::isFullScreen(const WId windowId) return (windowRect == mi.value().rcMonitor); } -bool Utils::isWindowNoState(const WId windowId) +bool Utils::isWindowNoState(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); #if 0 WINDOWPLACEMENT wp; SecureZeroMemory(&wp, sizeof(wp)); @@ -1614,13 +1550,10 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal) // Using Direct2D to get the primary monitor's DPI is only available on Windows 7 // and onwards, but it has been marked as deprecated by Microsoft. if (API_D2D_AVAILABLE(D2D1CreateFactory)) { - using D2D1CreateFactoryPtr = - HRESULT(WINAPI *)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS *, void **); - const auto pD2D1CreateFactory = - reinterpret_cast(SysApiLoader::instance()->get(kd2d1, kD2D1CreateFactory)); + using D2D1CreateFactoryPtr = HRESULT(WINAPI *)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS *, void **); + const auto pD2D1CreateFactory = reinterpret_cast(SysApiLoader::instance()->get(kd2d1, kD2D1CreateFactory)); ID2D1Factory *d2dFactory = nullptr; - HRESULT hr = pD2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), - nullptr, reinterpret_cast(&d2dFactory)); + HRESULT hr = pD2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), nullptr, reinterpret_cast(&d2dFactory)); if (SUCCEEDED(hr)) { // We want to get the newest system DPI, so refresh the system metrics // manually to ensure that. @@ -1674,13 +1607,13 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal) return USER_DEFAULT_SCREEN_DPI; } -quint32 Utils::getWindowDpi(const WId windowId, const bool horizontal) +quint32 Utils::getWindowDpi(const QWindow *window, const bool horizontal) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return USER_DEFAULT_SCREEN_DPI; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); { if (const UINT dpi = _GetDpiForWindow2(hwnd)) { return dpi; @@ -1740,26 +1673,22 @@ quint32 Utils::getResizeBorderThicknessForDpi(const bool horizontal, const quint return 0; } if (horizontal) { - return (getSystemMetrics2(SM_CXSIZEFRAME, true, dpi) - + getSystemMetrics2(SM_CXPADDEDBORDER, true, dpi)); + return (getSystemMetrics2(SM_CXSIZEFRAME, true, dpi) + getSystemMetrics2(SM_CXPADDEDBORDER, true, dpi)); } else { - return (getSystemMetrics2(SM_CYSIZEFRAME, false, dpi) - + getSystemMetrics2(SM_CYPADDEDBORDER, false, dpi)); + return (getSystemMetrics2(SM_CYSIZEFRAME, false, dpi) + getSystemMetrics2(SM_CYPADDEDBORDER, false, dpi)); } } -quint32 Utils::getResizeBorderThickness(const WId windowId, const bool horizontal, const bool scaled) +quint32 Utils::getResizeBorderThickness(const QWindow *window, const bool horizontal, const bool scaled) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return 0; } if (horizontal) { - return (getSystemMetrics2(windowId, SM_CXSIZEFRAME, true, scaled) - + getSystemMetrics2(windowId, SM_CXPADDEDBORDER, true, scaled)); + return (getSystemMetrics2(window, SM_CXSIZEFRAME, true, scaled) + getSystemMetrics2(window, SM_CXPADDEDBORDER, true, scaled)); } else { - return (getSystemMetrics2(windowId, SM_CYSIZEFRAME, false, scaled) - + getSystemMetrics2(windowId, SM_CYPADDEDBORDER, false, scaled)); + return (getSystemMetrics2(window, SM_CYSIZEFRAME, false, scaled) + getSystemMetrics2(window, SM_CYPADDEDBORDER, false, scaled)); } } @@ -1772,13 +1701,13 @@ quint32 Utils::getCaptionBarHeightForDpi(const quint32 dpi) return getSystemMetrics2(SM_CYCAPTION, false, dpi); } -quint32 Utils::getCaptionBarHeight(const WId windowId, const bool scaled) +quint32 Utils::getCaptionBarHeight(const QWindow *window, const bool scaled) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return 0; } - return getSystemMetrics2(windowId, SM_CYCAPTION, false, scaled); + return getSystemMetrics2(window, SM_CYCAPTION, false, scaled); } quint32 Utils::getTitleBarHeightForDpi(const quint32 dpi) @@ -1790,13 +1719,13 @@ quint32 Utils::getTitleBarHeightForDpi(const quint32 dpi) return (getCaptionBarHeightForDpi(dpi) + getResizeBorderThicknessForDpi(false, dpi)); } -quint32 Utils::getTitleBarHeight(const WId windowId, const bool scaled) +quint32 Utils::getTitleBarHeight(const QWindow *window, const bool scaled) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return 0; } - return (getCaptionBarHeight(windowId, scaled) + getResizeBorderThickness(windowId, false, scaled)); + return (getCaptionBarHeight(window, scaled) + getResizeBorderThickness(window, false, scaled)); } quint32 Utils::getFrameBorderThicknessForDpi(const quint32 dpi) @@ -1813,10 +1742,10 @@ quint32 Utils::getFrameBorderThicknessForDpi(const quint32 dpi) return std::round(qreal(kDefaultWindowFrameBorderThickness) * dpr); } -quint32 Utils::getFrameBorderThickness(const WId windowId, const bool scaled) +quint32 Utils::getFrameBorderThickness(const QWindow *window, const bool scaled) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return 0; } // There's no window frame border before Windows 10. @@ -1826,17 +1755,16 @@ quint32 Utils::getFrameBorderThickness(const WId windowId, const bool scaled) if (!API_DWM_AVAILABLE(DwmGetWindowAttribute)) { return 0; } - const UINT dpi = getWindowDpi(windowId, true); + const UINT dpi = getWindowDpi(window, true); const qreal scaleFactor = (qreal(dpi) / qreal(USER_DEFAULT_SCREEN_DPI)); - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); UINT value = 0; - const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetWindowAttribute, hwnd, - _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value)); + const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetWindowAttribute, hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value)); if (SUCCEEDED(hr)) { - const qreal dpr = (scaled ? 1.0 : scaleFactor); + const qreal dpr = (scaled ? qreal(1) : scaleFactor); return std::round(qreal(value) / dpr); } else { - const qreal dpr = (scaled ? scaleFactor : 1.0); + const qreal dpr = (scaled ? scaleFactor : qreal(1)); return std::round(qreal(kDefaultWindowFrameBorderThickness) * dpr); } } @@ -1859,17 +1787,17 @@ QColor Utils::getFrameBorderColor(const bool active) } } -bool Utils::maybeFixupQtInternals(const WId windowId) +bool Utils::maybeFixupQtInternals(const QWindow *window) { - Q_ASSERT(windowId); - if (!windowId) { + Q_ASSERT(window); + if (!window) { return false; } static const bool dont = (qEnvironmentVariableIntValue("FRAMELESSHELPER_WINDOWS_DONT_FIX_QT") != 0); if (dont) { return true; } - const auto hwnd = reinterpret_cast(windowId); + const auto hwnd = qWindowId(window); #if 0 ::SetLastError(ERROR_SUCCESS); const auto classStyle = static_cast(::GetClassLongPtrW(hwnd, GCL_STYLE)); @@ -1931,7 +1859,7 @@ bool Utils::maybeFixupQtInternals(const WId windowId) } } } - return triggerFrameChange(windowId); + return triggerFrameChange(window); } bool Utils::startSystemMove(QWindow *window, const QPoint &globalPos) @@ -1948,7 +1876,7 @@ bool Utils::startSystemMove(QWindow *window, const QPoint &globalPos) WARNING << getSystemErrorMessage(kReleaseCapture); return false; } - const auto hwnd = reinterpret_cast(window->winId()); + const auto hwnd = qWindowId(window); if (::PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) { WARNING << getSystemErrorMessage(kPostMessageW); return false; @@ -1974,7 +1902,7 @@ bool Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi WARNING << getSystemErrorMessage(kReleaseCapture); return false; } - const auto hwnd = reinterpret_cast(window->winId()); + const auto hwnd = qWindowId(windowId); + const auto hwnd = qWindowId(window); if (!g_win32UtilsData()->qtWindowProc) { ::SetLastError(ERROR_SUCCESS); const auto qtWindowProc = reinterpret_cast(::GetWindowLongPtrW(hwnd, GWLP_WNDPROC)); @@ -2034,16 +1961,18 @@ bool Utils::installWindowProcHook(const WId windowId, FramelessParamsConst param } g_win32UtilsData()->qtWindowProc = qtWindowProc; } - const auto it = g_win32UtilsData()->data.constFind(windowId); - if (it == g_win32UtilsData()->data.constEnd()) { - Win32UtilsData data = {}; - data.params = *params; - g_win32UtilsData()->data.insert(windowId, data); + FramelessDataPtr data = FramelessHelperExtractData(window); + if (!data) { + data.reset(new FramelessData); + FramelessHelperSetData(const_cast(window), data); + } + if (!data->windowProcHooked) { ::SetLastError(ERROR_SUCCESS); if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast(FramelessHelperHookWindowProc)) == 0) { WARNING << getSystemErrorMessage(kSetWindowLongPtrW); return false; } + data->windowProcHooked = true; } return true; }