This commit is contained in:
Yuhang Zhao 2023-09-14 17:58:50 +08:00
parent 26b9996ec6
commit 146384f9b0
15 changed files with 541 additions and 518 deletions

View File

@ -31,6 +31,7 @@ project(FramelessHelper
) )
include(CMakeDependentOption) include(CMakeDependentOption)
include(cmake/utils.cmake)
# TODO: Use add_feature_info() for every option below? Is it worth doing? # TODO: Use add_feature_info() for every option below? Is it worth doing?
option(FRAMELESSHELPER_BUILD_STATIC "Build FramelessHelper as a static library." OFF) 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_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_BORDER_PAINTER "Disable the cross-platform window frame border painter." OFF)
option(FRAMELESSHELPER_NO_SYSTEM_BUTTON "Disable the pre-defined StandardSystemButton control." OFF) option(FRAMELESSHELPER_NO_SYSTEM_BUTTON "Disable the pre-defined StandardSystemButton control." OFF)
cmake_dependent_option(FRAMELESSHELPER_NATIVE_IMPL "Use platform native implementation instead of Qt to get best experience." ON WIN32 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()
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui)
find_package(Qt${QT_VERSION_MAJOR} 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 NAMES Qt6 Qt5 QUIET COMPONENTS Widgets Quick)
find_package(Qt${QT_VERSION_MAJOR} 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) if(FRAMELESSHELPER_NO_WINDOW AND FRAMELESSHELPER_BUILD_EXAMPLES)
message(WARNING "Current OS is not macOS, universal build will be disabled.") 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) 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"))) 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.") 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) if(FRAMELESSHELPER_ENABLE_VCLTL AND NOT MSVC)
message(WARNING "VC-LTL is only available for the MSVC toolchain.") 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() endif()
set(FRAMELESSHELPER_LICENSE_HEADER "/* set(FRAMELESSHELPER_LICENSE_HEADER "/*
@ -144,8 +167,7 @@ if(MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(FRAMELESSHELPER_ENABLE_CFGUARD OFF) set(FRAMELESSHELPER_ENABLE_CFGUARD OFF)
endif() endif()
if(MSVC) if(FRAMELESSHELPER_ENABLE_VCLTL)
if(FRAMELESSHELPER_ENABLE_VCLTL)
include(cmake/VC-LTL.cmake) include(cmake/VC-LTL.cmake)
if("x${SupportLTL}" STREQUAL "xtrue") if("x${SupportLTL}" STREQUAL "xtrue")
# Make sure we will always overwrite the previous settings. # Make sure we will always overwrite the previous settings.
@ -154,14 +176,13 @@ if(MSVC)
#unset(CMAKE_MSVC_RUNTIME_LIBRARY PARENT_SCOPE) #unset(CMAKE_MSVC_RUNTIME_LIBRARY PARENT_SCOPE)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>" CACHE STRING "" FORCE) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>" CACHE STRING "" FORCE)
endif() endif()
endif() endif()
if(FRAMELESSHELPER_ENABLE_YYTHUNKS) if(FRAMELESSHELPER_ENABLE_YYTHUNKS)
unset(YYTHUNKS_TARGET_OS) unset(YYTHUNKS_TARGET_OS)
unset(YYTHUNKS_TARGET_OS CACHE) unset(YYTHUNKS_TARGET_OS CACHE)
#unset(YYTHUNKS_TARGET_OS PARENT_SCOPE) #unset(YYTHUNKS_TARGET_OS PARENT_SCOPE)
set(YYTHUNKS_TARGET_OS "WinXP" CACHE STRING "" FORCE) set(YYTHUNKS_TARGET_OS "WinXP" CACHE STRING "" FORCE)
include(cmake/YY-Thunks.cmake) include(cmake/YY-Thunks.cmake)
endif()
endif() endif()
set(__extra_flags "") set(__extra_flags "")
@ -175,11 +196,6 @@ prepare_package_export(
) )
unset(__extra_flags) 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") set(FRAMELESSHELPER_VERSION_FILE "${PROJECT_BINARY_DIR}/framelesshelper.version")
generate_project_version( generate_project_version(
PATH "${FRAMELESSHELPER_VERSION_FILE}" 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 "mica_material" CONDITION NOT FRAMELESSHELPER_NO_MICA_MATERIAL)
add_project_config(KEY "border_painter" CONDITION NOT FRAMELESSHELPER_NO_BORDER_PAINTER) 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 "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}") 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) 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() endif()
if(FRAMELESSHELPER_BUILD_EXAMPLES) if(FRAMELESSHELPER_BUILD_EXAMPLES)

View File

@ -26,9 +26,9 @@
#include <FramelessHelper/Core/framelesshelpercore_global.h> #include <FramelessHelper/Core/framelesshelpercore_global.h>
FRAMELESSHELPER_BEGIN_NAMESPACE #if !FRAMELESSHELPER_CONFIG(native_impl)
struct SystemParameters; FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_CORE_API FramelessHelperQt : public QObject class FRAMELESSHELPER_CORE_API FramelessHelperQt : public QObject
{ {
@ -40,11 +40,13 @@ public:
explicit FramelessHelperQt(QObject *parent = nullptr); explicit FramelessHelperQt(QObject *parent = nullptr);
~FramelessHelperQt() override; ~FramelessHelperQt() override;
static void addWindow(const SystemParameters *params); static void addWindow(const QWindow *window);
static void removeWindow(const WId windowId); static void removeWindow(const QWindow *window);
protected: protected:
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override; Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE
#endif // !native_impl

View File

@ -29,9 +29,9 @@
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
FRAMELESSHELPER_BEGIN_NAMESPACE #if FRAMELESSHELPER_CONFIG(native_impl)
struct SystemParameters; FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_CORE_API FramelessHelperWin : public QAbstractNativeEventFilter class FRAMELESSHELPER_CORE_API FramelessHelperWin : public QAbstractNativeEventFilter
{ {
@ -41,12 +41,14 @@ public:
explicit FramelessHelperWin(); explicit FramelessHelperWin();
~FramelessHelperWin() override; ~FramelessHelperWin() override;
static void addWindow(const SystemParameters *params); static void addWindow(const QWindow *window);
static void removeWindow(const WId windowId); static void removeWindow(const QWindow *window);
Q_NODISCARD bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override; Q_NODISCARD bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE
#endif // native_impl
#endif // Q_OS_WINDOWS #endif // Q_OS_WINDOWS

View File

@ -1107,7 +1107,7 @@ _AdjustWindowRectExForDpi2(
EXTERN_C_END 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 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 kPersonalizeRegistryKey[] = LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)";
[[maybe_unused]] inline constexpr const wchar_t kThemeSettingChangeEventName[] = L"ImmersiveColorSet"; [[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 kSystemLightThemeResourceName[] = L"Explorer";
[[maybe_unused]] inline constexpr const wchar_t kDesktopRegistryKey[] = LR"(Control Panel\Desktop)"; [[maybe_unused]] inline constexpr const wchar_t kDesktopRegistryKey[] = LR"(Control Panel\Desktop)";
[[maybe_unused]] inline constexpr const wchar_t kDarkModePropertyName[] = L"UseImmersiveDarkModeColors"; [[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);
}

View File

@ -28,7 +28,6 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
struct SystemParameters;
class FramelessManagerPrivate; class FramelessManagerPrivate;
class FRAMELESSHELPER_CORE_API FramelessManager : public QObject class FRAMELESSHELPER_CORE_API FramelessManager : public QObject
@ -45,14 +44,15 @@ class FRAMELESSHELPER_CORE_API FramelessManager : public QObject
public: public:
Q_NODISCARD static FramelessManager *instance(); Q_NODISCARD static FramelessManager *instance();
Q_NODISCARD bool isFramelessWindow(const QWindow *window) const;
Q_NODISCARD Global::SystemTheme systemTheme() const; Q_NODISCARD Global::SystemTheme systemTheme() const;
Q_NODISCARD QColor systemAccentColor() const; Q_NODISCARD QColor systemAccentColor() const;
Q_NODISCARD QString wallpaper() const; Q_NODISCARD QString wallpaper() const;
Q_NODISCARD Global::WallpaperAspectStyle wallpaperAspectStyle() const; Q_NODISCARD Global::WallpaperAspectStyle wallpaperAspectStyle() const;
public Q_SLOTS: public Q_SLOTS:
void addWindow(const SystemParameters *params); Q_NODISCARD bool addWindow(const QWindow *window);
void removeWindow(const WId windowId); Q_NODISCARD bool removeWindow(const QWindow *window);
void setOverrideTheme(const Global::SystemTheme theme); void setOverrideTheme(const Global::SystemTheme theme);
Q_SIGNALS: Q_SIGNALS:

View File

@ -25,7 +25,10 @@
#pragma once #pragma once
#include <FramelessHelper/Core/framelesshelpercore_global.h> #include <FramelessHelper/Core/framelesshelpercore_global.h>
#include <QtCore/qhash.h>
#include <QtGui/qwindow.h>
#include <functional> #include <functional>
#include <memory>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QScreen; class QScreen;
@ -62,7 +65,7 @@ using GetWidgetHandleCallback = std::function<QObject *()>;
using ForceChildrenRepaintCallback = std::function<void(const int)>; using ForceChildrenRepaintCallback = std::function<void(const int)>;
using ResetQtGrabbedControlCallback = std::function<bool()>; using ResetQtGrabbedControlCallback = std::function<bool()>;
struct SystemParameters struct FramelessCallbacks
{ {
GetWindowFlagsCallback getWindowFlags = nullptr; GetWindowFlagsCallback getWindowFlags = nullptr;
SetWindowFlagsCallback setWindowFlags = nullptr; SetWindowFlagsCallback setWindowFlags = nullptr;
@ -92,29 +95,61 @@ struct SystemParameters
GetWidgetHandleCallback getWidgetHandle = nullptr; GetWidgetHandleCallback getWidgetHandle = nullptr;
ForceChildrenRepaintCallback forceChildrenRepaint = nullptr; ForceChildrenRepaintCallback forceChildrenRepaint = nullptr;
ResetQtGrabbedControlCallback resetQtGrabbedControl = nullptr; ResetQtGrabbedControlCallback resetQtGrabbedControl = nullptr;
private:
Q_DISABLE_COPY_MOVE(FramelessCallbacks)
};
using FramelessCallbacksPtr = std::shared_ptr<FramelessCallbacks>;
#define CreateFramelessCallbacks(...) std::make_shared<FramelessCallbacks>(__VA_ARGS__)
struct FramelessData;
using FramelessDataPtr = std::shared_ptr<FramelessData>;
#define CreateFramelessData(...) std::make_shared<FramelessData>(__VA_ARGS__)
struct FramelessData
{
bool frameless = false;
FramelessCallbacksPtr callbacks = nullptr;
[[nodiscard]] static FramelessDataPtr create();
private:
Q_DISABLE_COPY_MOVE(FramelessData)
}; };
using FramelessParams = SystemParameters *; using FramelessDataHash = QHash<const QWindow *, FramelessDataPtr>;
using FramelessParamsConst = const SystemParameters *;
using FramelessParamsRef = SystemParameters &; template<typename T>
using FramelessParamsConstRef = const SystemParameters &; [[nodiscard]] T qWindowId(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return reinterpret_cast<T>(nullptr);
}
return reinterpret_cast<T>(window->winId());
}
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE
#define DECLARE_SIZE_COMPARE_OPERATORS(Type1, Type2) \ #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())); \ 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)); \ 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)); \ 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)); \ 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)

View File

@ -30,9 +30,10 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
struct SystemParameters; struct FramelessData;
class FramelessManager; using FramelessDataPtr = std::shared_ptr<FramelessData>;
class FramelessManager;
class FRAMELESSHELPER_CORE_API FramelessManagerPrivate : public QObject class FRAMELESSHELPER_CORE_API FramelessManagerPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -60,6 +61,8 @@ public:
void doNotifySystemThemeHasChangedOrNot(); void doNotifySystemThemeHasChangedOrNot();
void doNotifyWallpaperHasChangedOrNot(); void doNotifyWallpaperHasChangedOrNot();
Q_NODISCARD static FramelessDataPtr getData(const QWindow *window);
FramelessManager *q_ptr = nullptr; FramelessManager *q_ptr = nullptr;
Global::SystemTheme systemTheme = Global::SystemTheme::Unknown; Global::SystemTheme systemTheme = Global::SystemTheme::Unknown;
std::optional<Global::SystemTheme> overrideTheme = std::nullopt; std::optional<Global::SystemTheme> overrideTheme = std::nullopt;

View File

@ -42,25 +42,19 @@ struct SystemParameters;
namespace Utils namespace Utils
{ {
[[nodiscard]] FRAMELESSHELPER_CORE_API [[nodiscard]] FRAMELESSHELPER_CORE_API Qt::CursorShape calculateCursorShape(const QWindow *window, const QPoint &pos);
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::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool startSystemMove(QWindow *window, const QPoint &globalPos); [[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 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 QString getSystemButtonGlyph(const Global::SystemButtonType button);
[[nodiscard]] FRAMELESSHELPER_CORE_API QWindow *findWindow(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API QWindow *findWindow(const WId windowId);
FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter( [[nodiscard]] FRAMELESSHELPER_CORE_API bool moveWindowToDesktopCenter(const QWindow *window, const bool considerTaskBar);
const SystemParameters *params, const bool considerTaskBar); [[nodiscard]] FRAMELESSHELPER_CORE_API Qt::WindowState windowStatesToWindowState(const Qt::WindowStates states);
[[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 bool isThemeChangeEvent(const QEvent * const event);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor calculateSystemButtonBackgroundColor( [[nodiscard]] FRAMELESSHELPER_CORE_API QColor calculateSystemButtonBackgroundColor(const Global::SystemButtonType button, const Global::ButtonState state);
const Global::SystemButtonType button, const Global::ButtonState state);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool [[nodiscard]] FRAMELESSHELPER_CORE_API bool setBlurBehindWindowEnabled(const QWindow *window, const Global::BlurMode mode, const QColor &color);
setBlurBehindWindowEnabled(const WId windowId, const Global::BlurMode mode, const QColor &color);
[[nodiscard]] FRAMELESSHELPER_CORE_API QString getWallpaperFilePath(); [[nodiscard]] FRAMELESSHELPER_CORE_API QString getWallpaperFilePath();
[[nodiscard]] FRAMELESSHELPER_CORE_API Global::WallpaperAspectStyle getWallpaperAspectStyle(); [[nodiscard]] FRAMELESSHELPER_CORE_API Global::WallpaperAspectStyle getWallpaperAspectStyle();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isBlurBehindWindowSupported(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isBlurBehindWindowSupported();
@ -93,71 +87,61 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isDwmCompositionEnabled(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isDwmCompositionEnabled();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool triggerFrameChange(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool triggerFrameChange(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateWindowFrameMargins(const WId windowId, const bool reset); [[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 bool updateInternalWindowFrameMargins(QWindow *window, const bool enable);
[[nodiscard]] FRAMELESSHELPER_CORE_API QString getSystemErrorMessage(const QString &function); [[nodiscard]] FRAMELESSHELPER_CORE_API QString getSystemErrorMessage(const QString &function);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool syncWmPaintWithDwm(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool syncWmPaintWithDwm();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool showSystemMenu( [[nodiscard]] FRAMELESSHELPER_CORE_API bool showSystemMenu(const QWindow *window, const QPoint &pos, const bool selectFirstEntry);
const WId windowId, const QPoint &pos,
const bool selectFirstEntry, const SystemParameters *params);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmColorizationColor(bool *opaque = nullptr, bool *ok = nullptr); [[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmColorizationColor(bool *opaque = nullptr, bool *ok = nullptr);
[[nodiscard]] FRAMELESSHELPER_CORE_API Global::DwmColorizationArea getDwmColorizationArea(); [[nodiscard]] FRAMELESSHELPER_CORE_API Global::DwmColorizationArea getDwmColorizationArea();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isHighContrastModeEnabled(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isHighContrastModeEnabled();
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getPrimaryScreenDpi(const bool horizontal); [[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 getWindowDpi(const QWindow *window, const bool horizontal);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThicknessForDpi [[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThicknessForDpi(const bool horizontal, const quint32 dpi);
(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 getResizeBorderThickness(const WId windowId,
const bool horizontal,
const bool scaled);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getCaptionBarHeightForDpi(const quint32 dpi); [[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 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 getFrameBorderThicknessForDpi(const quint32 dpi);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const WId windowId, [[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const QWindow *window, const bool scaled);
const bool scaled); [[nodiscard]] FRAMELESSHELPER_CORE_API bool maybeFixupQtInternals(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool maybeFixupQtInternals(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFrameBorderVisible(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFrameBorderVisible();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool installWindowProcHook( [[nodiscard]] FRAMELESSHELPER_CORE_API bool installWindowProcHook(const QWindow *window);
const WId windowId, const SystemParameters *params); [[nodiscard]] FRAMELESSHELPER_CORE_API bool uninstallWindowProcHook(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool uninstallWindowProcHook(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool setAeroSnappingEnabled(const QWindow *window, const bool enable);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool setAeroSnappingEnabled(const WId windowId, const bool enable);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool tryToEnableHighestDpiAwarenessLevel(); [[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 bool shouldAppsUseDarkMode_windows();
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_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 setCornerStyleForWindow(const QWindow *window, const Global::WindowCornerStyle style);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool hideOriginalTitleBarElements [[nodiscard]] FRAMELESSHELPER_CORE_API bool hideOriginalTitleBarElements(const QWindow *window, const bool disable = true);
(const WId windowId, const bool disable = true);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool setQtDarkModeAwareEnabled(const bool enable); [[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 refreshWin32ThemeResources(const QWindow *window, const bool dark);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool enableNonClientAreaDpiScalingForWindow(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool enableNonClientAreaDpiScalingForWindow(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API [[nodiscard]] FRAMELESSHELPER_CORE_API Global::DpiAwareness getDpiAwarenessForCurrentProcess(bool *highest = nullptr);
Global::DpiAwareness getDpiAwarenessForCurrentProcess(bool *highest = nullptr); [[nodiscard]] FRAMELESSHELPER_CORE_API bool fixupChildWindowsDpiMessage(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool fixupChildWindowsDpiMessage(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool fixupDialogsDpiScaling(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool fixupDialogsDpiScaling();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool setDarkModeAllowedForApp(const bool allow = true); [[nodiscard]] FRAMELESSHELPER_CORE_API bool setDarkModeAllowedForApp(const bool allow = true);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool bringWindowToFront(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool bringWindowToFront(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool removeMicaWindow(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool removeMicaWindow(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint64 getKeyState(); [[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 isValidWindow(const QWindow *window, const bool checkVisible, const bool checkTopLevel);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API QMargins getWindowSystemFrameMargins(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API QMargins getWindowSystemFrameMargins(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API QMargins getWindowCustomFrameMargins(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_CORE_API QMargins getWindowCustomFrameMargins(const QWindow *window);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateAllDirectXSurfaces(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool updateAllDirectXSurfaces();
FRAMELESSHELPER_CORE_API void printWin32Message(void *msg); FRAMELESSHELPER_CORE_API void printWin32Message(void *msg);
#endif // Q_OS_WINDOWS #endif // Q_OS_WINDOWS
#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) #if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
[[nodiscard]] FRAMELESSHELPER_CORE_API QScreen *x11_findScreenForVirtualDesktop [[nodiscard]] FRAMELESSHELPER_CORE_API QScreen *x11_findScreenForVirtualDesktop(const int virtualDesktopNumber);
(const int virtualDesktopNumber);
[[nodiscard]] FRAMELESSHELPER_CORE_API x11_return_type x11_appRootWindow(const int screen); [[nodiscard]] FRAMELESSHELPER_CORE_API x11_return_type x11_appRootWindow(const int screen);
[[nodiscard]] FRAMELESSHELPER_CORE_API int x11_appScreen(); [[nodiscard]] FRAMELESSHELPER_CORE_API int x11_appScreen();
[[nodiscard]] FRAMELESSHELPER_CORE_API x11_return_type x11_appTime(); [[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 QByteArray x11_nextStartupId();
[[nodiscard]] FRAMELESSHELPER_CORE_API Display *x11_display(); [[nodiscard]] FRAMELESSHELPER_CORE_API Display *x11_display();
[[nodiscard]] FRAMELESSHELPER_CORE_API xcb_connection_t *x11_connection(); [[nodiscard]] FRAMELESSHELPER_CORE_API xcb_connection_t *x11_connection();
[[nodiscard]] FRAMELESSHELPER_CORE_API QByteArray getWindowProperty [[nodiscard]] FRAMELESSHELPER_CORE_API QByteArray getWindowProperty(const QWindow *window, const xcb_atom_t prop, const xcb_atom_t type, const quint32 data_len);
(const WId windowId, 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 setWindowProperty FRAMELESSHELPER_CORE_API void clearWindowProperty(const QWindow *window, const xcb_atom_t prop);
(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 xcb_atom_t internAtom(const char *name); [[nodiscard]] FRAMELESSHELPER_CORE_API xcb_atom_t internAtom(const char *name);
[[nodiscard]] FRAMELESSHELPER_CORE_API QString getWindowManagerName(); [[nodiscard]] FRAMELESSHELPER_CORE_API QString getWindowManagerName();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isSupportedByWindowManager(const xcb_atom_t atom); [[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 isSupportedByRootWindow(const xcb_atom_t atom);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool tryHideSystemTitleBar(const WId windowId, const bool hide = true); [[nodiscard]] FRAMELESSHELPER_CORE_API bool tryHideSystemTitleBar(const QWindow *window, const bool hide = true);
FRAMELESSHELPER_CORE_API void openSystemMenu(const WId windowId, const QPoint &globalPos); FRAMELESSHELPER_CORE_API void openSystemMenu(const QWindow *window, const QPoint &globalPos);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_linux(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_linux();
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_linux(); [[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_linux();
FRAMELESSHELPER_CORE_API void sendMoveResizeMessage FRAMELESSHELPER_CORE_API void sendMoveResizeMessage(const QWindow *window, const uint32_t action, const QPoint &globalPos, const Qt::MouseButton button = Qt::LeftButton);
(const WId windowId, const uint32_t action, const QPoint &globalPos, const Qt::MouseButton button = Qt::LeftButton);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isCustomDecorationSupported(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isCustomDecorationSupported();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool [[nodiscard]] FRAMELESSHELPER_CORE_API bool setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &props);
setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &props);
#endif // Q_OS_LINUX #endif // Q_OS_LINUX
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_macos(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_macos();
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_macos(); [[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_macos();
FRAMELESSHELPER_CORE_API void setSystemTitleBarVisible(const WId windowId, const bool visible); FRAMELESSHELPER_CORE_API void setSystemTitleBarVisible(const QWindow *window, const bool visible);
FRAMELESSHELPER_CORE_API void removeWindowProxy(const WId windowId); FRAMELESSHELPER_CORE_API void removeWindowProxy(const QWindow *window);
#endif // Q_OS_MACOS #endif // Q_OS_MACOS
} // namespace Utils } // namespace Utils

View File

@ -35,18 +35,18 @@ if(UNIX AND NOT APPLE)
endif() endif()
find_package(X11 QUIET COMPONENTS xcb) find_package(X11 QUIET COMPONENTS xcb)
if(TARGET X11::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() 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() endif()
find_package(PkgConfig QUIET) find_package(PkgConfig QUIET)
if(PkgConfig_FOUND) if(PkgConfig_FOUND)
pkg_check_modules(GTK3 QUIET IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GTK3 QUIET IMPORTED_TARGET gtk+-3.0)
endif() endif()
if(TARGET PkgConfig::GTK3) 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() 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()
endif() endif()
@ -61,14 +61,12 @@ set(PUBLIC_HEADERS
${FRAMELESSHELPER_VERSION_FILE} ${FRAMELESSHELPER_VERSION_FILE}
${FRAMELESSHELPER_CONFIG_FILE} ${FRAMELESSHELPER_CONFIG_FILE}
${INCLUDE_PREFIX}/framelesshelpercore_global.h ${INCLUDE_PREFIX}/framelesshelpercore_global.h
${INCLUDE_PREFIX}/framelesshelper_qt.h
${INCLUDE_PREFIX}/framelessmanager.h ${INCLUDE_PREFIX}/framelessmanager.h
${INCLUDE_PREFIX}/utils.h ${INCLUDE_PREFIX}/utils.h
) )
set(PUBLIC_HEADERS_ALIAS set(PUBLIC_HEADERS_ALIAS
${INCLUDE_PREFIX}/Global ${INCLUDE_PREFIX}/Global
${INCLUDE_PREFIX}/FramelessHelper_Qt
${INCLUDE_PREFIX}/FramelessManager ${INCLUDE_PREFIX}/FramelessManager
${INCLUDE_PREFIX}/Utils ${INCLUDE_PREFIX}/Utils
) )
@ -84,7 +82,6 @@ set(PRIVATE_HEADERS
set(SOURCES set(SOURCES
utils.cpp utils.cpp
framelesshelper_qt.cpp
framelessmanager.cpp framelessmanager.cpp
framelessconfig.cpp framelessconfig.cpp
sysapiloader.cpp sysapiloader.cpp
@ -92,14 +89,8 @@ set(SOURCES
) )
if(WIN32) if(WIN32)
list(APPEND PUBLIC_HEADERS list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_windows.h)
${INCLUDE_PREFIX}/framelesshelper_windows.h list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Windows)
${INCLUDE_PREFIX}/framelesshelper_win.h
)
list(APPEND PUBLIC_HEADERS_ALIAS
${INCLUDE_PREFIX}/FramelessHelper_Windows
${INCLUDE_PREFIX}/FramelessHelper_Win
)
list(APPEND PRIVATE_HEADERS list(APPEND PRIVATE_HEADERS
${INCLUDE_PREFIX}/private/registrykey_p.h ${INCLUDE_PREFIX}/private/registrykey_p.h
${INCLUDE_PREFIX}/private/winverhelper_p.h ${INCLUDE_PREFIX}/private/winverhelper_p.h
@ -107,25 +98,35 @@ if(WIN32)
list(APPEND SOURCES list(APPEND SOURCES
registrykey.cpp registrykey.cpp
utils_win.cpp utils_win.cpp
framelesshelper_win.cpp
winverhelper.cpp winverhelper.cpp
platformsupport_win.cpp platformsupport_win.cpp
) )
elseif(APPLE) elseif(APPLE)
list(APPEND SOURCES utils_mac.mm) list(APPEND SOURCES utils_mac.mm)
elseif(UNIX) elseif(UNIX)
list(APPEND PUBLIC_HEADERS list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_linux.h)
${INCLUDE_PREFIX}/framelesshelper_linux.h list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Linux)
)
list(APPEND PUBLIC_HEADERS_ALIAS
${INCLUDE_PREFIX}/FramelessHelper_Linux
)
list(APPEND SOURCES list(APPEND SOURCES
utils_linux.cpp utils_linux.cpp
platformsupport_linux.cpp platformsupport_linux.cpp
) )
endif() 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) if(NOT FRAMELESSHELPER_NO_TITLEBAR)
list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/chromepalette.h) list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/chromepalette.h)
list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/ChromePalette) list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/ChromePalette)

View File

@ -23,6 +23,9 @@
*/ */
#include "framelesshelper_qt.h" #include "framelesshelper_qt.h"
#if !FRAMELESSHELPER_CONFIG(native_impl)
#include "framelessmanager.h" #include "framelessmanager.h"
#include "framelessmanager_p.h" #include "framelessmanager_p.h"
#include "framelessconfig_p.h" #include "framelessconfig_p.h"
@ -49,39 +52,36 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
struct FramelessQtHelperData using FramelessHelperQtPtr = std::shared_ptr<FramelessHelperQt>;
#define CreateFramelessHelperQt(...) std::make_shared<FramelessHelperQt>(__VA_ARGS__)
struct FramelessDataQt : public FramelessData
{ {
SystemParameters params = {}; FramelessHelperQtPtr eventFilter = nullptr;
FramelessHelperQt *eventFilter = nullptr;
bool cursorShapeChanged = false; bool cursorShapeChanged = false;
bool leftButtonPressed = false; bool leftButtonPressed = false;
}; };
using FramelessDataQtPtr = std::shared_ptr<FramelessDataQt>;
#define CreateFramelessDataQt(...) std::make_shared<FramelessDataQt>(__VA_ARGS__)
using FramelessQtHelperInternal = QHash<WId, FramelessQtHelperData>; [[nodiscard]] FramelessDataQtPtr CreateEmptyDataQt() { return CreateFramelessDataQt(); }
Q_GLOBAL_STATIC(FramelessQtHelperInternal, g_framelessQtHelperData)
FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent) {} FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent) {}
FramelessHelperQt::~FramelessHelperQt() = default; FramelessHelperQt::~FramelessHelperQt() = default;
void FramelessHelperQt::addWindow(FramelessParamsConst params) void FramelessHelperQt::addWindow(const QWindow *window)
{ {
Q_ASSERT(params); Q_ASSERT(window);
if (!params) { if (!window) {
return; return;
} }
const WId windowId = params->getWindowId(); const auto data = std::dynamic_pointer_cast<FramelessDataQt>(FramelessManagerPrivate::getData(window));
const auto it = g_framelessQtHelperData()->constFind(windowId); Q_ASSERT(data->callbacks);
if (it != g_framelessQtHelperData()->constEnd()) { if (!data->callbacks) {
return; return;
} }
FramelessQtHelperData data = {}; data->eventFilter = CreateFramelessHelperQt();
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);
const auto shouldApplyFramelessFlag = []() -> bool { const auto shouldApplyFramelessFlag = []() -> bool {
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
return false; return false;
@ -95,31 +95,32 @@ void FramelessHelperQt::addWindow(FramelessParamsConst params)
window->setProperty("_q_mac_wantsLayer", 1); window->setProperty("_q_mac_wantsLayer", 1);
#endif // (defined(Q_OS_MACOS) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))) #endif // (defined(Q_OS_MACOS) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)))
if (shouldApplyFramelessFlag) { if (shouldApplyFramelessFlag) {
params->setWindowFlags(params->getWindowFlags() | Qt::FramelessWindowHint); data->callbacks->setWindowFlags(data->callbacks->getWindowFlags() | Qt::FramelessWindowHint);
} else { } else {
#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) #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) #elif defined(Q_OS_MACOS)
Utils::setSystemTitleBarVisible(windowId, false); Utils::setSystemTitleBarVisible(window, false);
#endif // Q_OS_LINUX #endif // Q_OS_LINUX
} }
window->installEventFilter(data.eventFilter); const_cast<QWindow *>(window)->installEventFilter(data->eventFilter.get());
FramelessHelperEnableThemeAware(); FramelessHelperEnableThemeAware();
} }
void FramelessHelperQt::removeWindow(const WId windowId) void FramelessHelperQt::removeWindow(const QWindow *window)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
if (!windowId) { if (!window) {
return; return;
} }
const auto it = g_framelessQtHelperData()->constFind(windowId); const auto data = std::dynamic_pointer_cast<FramelessDataQt>(FramelessManagerPrivate::getData(window));
if (it == g_framelessQtHelperData()->constEnd()) { Q_ASSERT(data->eventFilter);
return; if (data->eventFilter) {
const_cast<QWindow *>(window)->removeEventFilter(data->eventFilter.get());
data->eventFilter = nullptr;
} }
g_framelessQtHelperData()->erase(it);
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
Utils::removeWindowProxy(windowId); Utils::removeWindowProxy(window);
#endif #endif
} }
@ -159,21 +160,15 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
) { ) {
return QObject::eventFilter(object, event); return QObject::eventFilter(object, event);
} }
const auto window = qobject_cast<QWindow *>(object); const auto window = qobject_cast<const QWindow *>(object);
const WId windowId = window->winId(); const auto data = std::dynamic_pointer_cast<FramelessDataQt>(FramelessManagerPrivate::getData(window));
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();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
if (type == QEvent::DevicePixelRatioChange) if (type == QEvent::DevicePixelRatioChange)
#else // QT_VERSION < QT_VERSION_CHECK(6, 6, 0) #else // QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
if (type == QEvent::ScreenChangeInternal) if (type == QEvent::ScreenChangeInternal)
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) #endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
{ {
data.params.forceChildrenRepaint(500); data->callbacks->forceChildrenRepaint(500);
return QObject::eventFilter(object, event); return QObject::eventFilter(object, event);
} }
const auto mouseEvent = static_cast<QMouseEvent *>(event); const auto mouseEvent = static_cast<QMouseEvent *>(event);
@ -185,64 +180,63 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
const QPoint scenePos = mouseEvent->windowPos().toPoint(); const QPoint scenePos = mouseEvent->windowPos().toPoint();
const QPoint globalPos = mouseEvent->screenPos().toPoint(); const QPoint globalPos = mouseEvent->screenPos().toPoint();
#endif #endif
const bool windowFixedSize = data.params.isWindowFixedSize(); const bool windowFixedSize = data->callbacks->isWindowFixedSize();
const bool ignoreThisEvent = data.params.shouldIgnoreMouseEvents(scenePos); const bool ignoreThisEvent = data->callbacks->shouldIgnoreMouseEvents(scenePos);
const bool insideTitleBar = data.params.isInsideTitleBarDraggableArea(scenePos); const bool insideTitleBar = data->callbacks->isInsideTitleBarDraggableArea(scenePos);
const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool(); const bool dontOverrideCursor = data->callbacks->getProperty(kDontOverrideCursorVar, false).toBool();
const bool dontToggleMaximize = data.params.getProperty(kDontToggleMaximizeVar, false).toBool(); const bool dontToggleMaximize = data->callbacks->getProperty(kDontToggleMaximizeVar, false).toBool();
switch (type) { switch (type) {
case QEvent::MouseButtonPress: { case QEvent::MouseButtonPress:
if (button == Qt::LeftButton) { if (button == Qt::LeftButton) {
muData.leftButtonPressed = true; data->leftButtonPressed = true;
if (!windowFixedSize) { if (!windowFixedSize) {
const Qt::Edges edges = Utils::calculateWindowEdges(window, scenePos); const Qt::Edges edges = Utils::calculateWindowEdges(window, scenePos);
if (edges != Qt::Edges{}) { if (edges != Qt::Edges{}) {
std::ignore = Utils::startSystemResize(window, edges, globalPos); std::ignore = Utils::startSystemResize(const_cast<QWindow *>(window), edges, globalPos);
event->accept(); event->accept();
return true; return true;
} }
} }
} }
} break; break;
case QEvent::MouseButtonRelease: { case QEvent::MouseButtonRelease:
if (button == Qt::LeftButton) { if (button == Qt::LeftButton) {
muData.leftButtonPressed = false; data->leftButtonPressed = false;
} } else if (button == Qt::RightButton) {
if (button == Qt::RightButton) {
if (!ignoreThisEvent && insideTitleBar) { if (!ignoreThisEvent && insideTitleBar) {
data.params.showSystemMenu(globalPos); data->callbacks->showSystemMenu(globalPos);
event->accept(); event->accept();
return true; return true;
} }
} }
} break; break;
case QEvent::MouseButtonDblClick: { case QEvent::MouseButtonDblClick:
if (!dontToggleMaximize && (button == Qt::LeftButton) && !windowFixedSize && !ignoreThisEvent && insideTitleBar) { if (!dontToggleMaximize && (button == Qt::LeftButton) && !windowFixedSize && !ignoreThisEvent && insideTitleBar) {
Qt::WindowState newWindowState = Qt::WindowNoState; Qt::WindowState newWindowState = Qt::WindowNoState;
if (data.params.getWindowState() != Qt::WindowMaximized) { if (data->callbacks->getWindowState() != Qt::WindowMaximized) {
newWindowState = Qt::WindowMaximized; newWindowState = Qt::WindowMaximized;
} }
data.params.setWindowState(newWindowState); data->callbacks->setWindowState(newWindowState);
event->accept(); event->accept();
return true; return true;
} }
} break; break;
case QEvent::MouseMove: { case QEvent::MouseMove: {
if (!dontOverrideCursor && !windowFixedSize) { if (!dontOverrideCursor && !windowFixedSize) {
const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos); const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos);
if (cs == Qt::ArrowCursor) { if (cs == Qt::ArrowCursor) {
if (data.cursorShapeChanged) { if (data->cursorShapeChanged) {
data.params.unsetCursor(); data->callbacks->unsetCursor();
muData.cursorShapeChanged = false; data->cursorShapeChanged = false;
} }
} else { } else {
data.params.setCursor(cs); data->callbacks->setCursor(cs);
muData.cursorShapeChanged = true; data->cursorShapeChanged = true;
} }
} }
if (data.leftButtonPressed) { if (data->leftButtonPressed) {
if (!ignoreThisEvent && insideTitleBar) { if (!ignoreThisEvent && insideTitleBar) {
std::ignore = Utils::startSystemMove(window, globalPos); std::ignore = Utils::startSystemMove(const_cast<QWindow *>(window), globalPos);
event->accept(); event->accept();
return true; return true;
} }
@ -255,3 +249,5 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
} }
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE
#endif // !native_impl

View File

@ -26,6 +26,8 @@
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
#if FRAMELESSHELPER_CONFIG(native_impl)
#include "framelessmanager.h" #include "framelessmanager.h"
#include "framelessmanager_p.h" #include "framelessmanager_p.h"
#include "framelessconfig_p.h" #include "framelessconfig_p.h"
@ -100,9 +102,8 @@ enum class WindowPart : quint8
TitleBar 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. // Store the last hit test result, it's helpful to handle WM_MOUSEMOVE and WM_NCMOUSELEAVE.
WindowPart lastHitTestResult = WindowPart::Outside; WindowPart lastHitTestResult = WindowPart::Outside;
// True if we blocked a WM_MOUSELEAVE when mouse moves on chrome button, false when a // True if we blocked a WM_MOUSELEAVE when mouse moves on chrome button, false when a
@ -113,23 +114,16 @@ struct FramelessWin32HelperData
QRect restoreGeometry = {}; QRect restoreGeometry = {};
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
}; };
#define CreateFramelessDataWin(...) std::make_shared<FramelessDataWin>(__VA_ARGS__)
struct FramelessWin32HelperInternal #define GetFramelessDataWin(Window) std::dynamic_pointer_cast<FramelessDataWin>(FramelessManagerPrivate::getData(Window))
[[nodiscard]] FramelessDataPtr FramelessData::create()
{ {
std::unique_ptr<FramelessHelperWin> nativeEventFilter = nullptr; return CreateFramelessDataWin();
QHash<WId, FramelessWin32HelperData> data = {}; }
};
Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData) static std::unique_ptr<FramelessHelperWin> g_framelessHelperWin = nullptr;
[[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;
[[nodiscard]] extern QPoint point2qpoint(const POINT &point); [[nodiscard]] extern QPoint point2qpoint(const POINT &point);
[[nodiscard]] extern POINT qpoint2point(const QPoint &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 QRect rect2qrect(const RECT &rect);
[[nodiscard]] extern RECT qrect2rect(const QRect &qrect); [[nodiscard]] extern RECT qrect2rect(const QRect &qrect);
[[nodiscard]] extern QString hwnd2str(const WId windowId);
[[nodiscard]] extern QString hwnd2str(const HWND hwnd); [[nodiscard]] extern QString hwnd2str(const HWND hwnd);
[[nodiscard]] extern std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd); [[nodiscard]] extern std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd);
@ -212,31 +205,28 @@ FramelessHelperWin::FramelessHelperWin() : QAbstractNativeEventFilter() {}
FramelessHelperWin::~FramelessHelperWin() = default; FramelessHelperWin::~FramelessHelperWin() = default;
void FramelessHelperWin::addWindow(FramelessParamsConst params) void FramelessHelperWin::addWindow(const QWindow *window)
{ {
Q_ASSERT(params); Q_ASSERT(window);
if (!params) { if (!window) {
return; return;
} }
const WId windowId = params->getWindowId(); const auto data = GetFramelessDataWin(window);
const auto it = g_framelessWin32HelperData()->data.constFind(windowId); Q_ASSERT(data);
if (it != g_framelessWin32HelperData()->data.constEnd()) { if (!data || data->frameless) {
return; return;
} }
FramelessWin32HelperData data = {}; data->frameless = true;
data.params = *params; data->dpi = Dpi{ Utils::getWindowDpi(window, true), Utils::getWindowDpi(window, false) };
data.dpi = {Utils::getWindowDpi(windowId, true), Utils::getWindowDpi(windowId, false)}; if (!g_framelessHelperWin) {
g_framelessWin32HelperData()->data.insert(windowId, data); g_framelessHelperWin = std::make_unique<FramelessHelperWin>();
if (!g_framelessWin32HelperData()->nativeEventFilter) { qApp->installNativeEventFilter(g_framelessHelperWin.get());
g_framelessWin32HelperData()->nativeEventFilter = std::make_unique<FramelessHelperWin>();
qApp->installNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get());
} }
DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data.dpi; DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data->dpi;
const QWindow *window = params->getWindowHandle();
// Remove the bad window styles added by Qt (it's not that "bad" though). // 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 #if 0
params->setWindowFlags(params->getWindowFlags() | Qt::FramelessWindowHint); data->callbacks->setWindowFlags(data->callbacks->getWindowFlags() | Qt::FramelessWindowHint);
#else #else
// Qt maintains a frame margin internally, we need to update it accordingly // 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 // 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<QWindow *>(window), true); std::ignore = Utils::updateInternalWindowFrameMargins(const_cast<QWindow *>(window), true);
#endif #endif
// Tell DWM our preferred frame margin. // 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. // 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 // 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 // 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. // 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)) { if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) {
std::ignore = Utils::updateFramebufferTransparency(windowId); std::ignore = Utils::updateFramebufferTransparency(window);
} }
if (WindowsVersionHelper::isWin10RS1OrGreater()) { if (WindowsVersionHelper::isWin10RS1OrGreater()) {
// Tell DWM we may need dark theme non-client area (title bar & frame border). // Tell DWM we may need dark theme non-client area (title bar & frame border).
FramelessHelperEnableThemeAware(); FramelessHelperEnableThemeAware();
if (WindowsVersionHelper::isWin10RS5OrGreater()) { if (WindowsVersionHelper::isWin10RS5OrGreater()) {
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark); const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
const auto isWidget = [params]() -> bool { const auto isWidget = [data]() -> bool {
const QObject *widget = params->getWidgetHandle(); const QObject *widget = data->callbacks->getWidgetHandle();
return (widget && widget->isWidgetType()); return (widget && widget->isWidgetType());
}(); }();
if (!isWidget) { if (!isWidget) {
// Tell UXTheme we may need dark theme controls. // Tell UXTheme we may need dark theme controls.
// Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications. // 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 (WindowsVersionHelper::isWin11OrGreater()) {
if (FramelessConfig::instance()->isSet(Option::WindowUseSquareCorners)) { 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); Q_ASSERT(window);
if (!windowId) { if (!window) {
return; return;
} }
const auto it = g_framelessWin32HelperData()->data.constFind(windowId); const auto data = GetFramelessDataWin(window);
if (it == g_framelessWin32HelperData()->data.constEnd()) { if (!data || !data->frameless) {
return; return;
} }
g_framelessWin32HelperData()->data.erase(it); data->frameless = false;
if (g_framelessWin32HelperData()->data.isEmpty()) {
if (g_framelessWin32HelperData()->nativeEventFilter) {
qApp->removeNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get());
g_framelessWin32HelperData()->nativeEventFilter.reset();
}
}
} }
bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) 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. // Anyway, we should skip the entire processing in this case.
return false; return false;
} }
const auto windowId = reinterpret_cast<WId>(hWnd); const QWindow *window = Utils::findWindow(reinterpret_cast<WId>(hWnd));
const auto data = GetFramelessDataWin(window);
Q_ASSERT(data);
if (!data || !data->frameless) {
return false;
}
// Let's be extra safe. // Let's be extra safe.
if (!Utils::isValidWindow(windowId, false, true)) { if (!Utils::isValidWindow(window, false, true)) {
return false; return false;
} }
const UINT uMsg = msg->message; const UINT uMsg = msg->message;
// We should skip these messages otherwise we will get crashes. // 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) { switch (uMsg) {
case WM_CLOSE: case WM_CLOSE:
case WM_DESTROY: case WM_DESTROY:
@ -338,23 +327,16 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break; 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 bool frameBorderVisible = Utils::isWindowFrameBorderVisible();
const WPARAM wParam = msg->wParam; const WPARAM wParam = msg->wParam;
const LPARAM lParam = msg->lParam; const LPARAM lParam = msg->lParam;
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
const auto updateRestoreGeometry = [windowId, &data, &muData](const bool ignoreWindowState) -> void { const auto updateRestoreGeometry = [window](const bool ignoreWindowState) -> void {
if (!ignoreWindowState && !Utils::isWindowNoState(windowId)) { if (!ignoreWindowState && !Utils::isWindowNoState(window)) {
return; return;
} }
const QRect rect = Utils::getWindowRestoreGeometry(windowId); const QRect rect = Utils::getWindowRestoreGeometry(window);
if (!Utils::isValidGeometry(rect)) { if (!Utils::isValidGeometry(rect)) {
WARNING << "The calculated restore geometry is invalid."; WARNING << "The calculated restore geometry is invalid.";
return; return;
@ -1315,4 +1297,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE
#endif // native_impl
#endif // Q_OS_WINDOWS #endif // Q_OS_WINDOWS

View File

@ -59,9 +59,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
using FramelessManagerData = QList<WId>; Q_GLOBAL_STATIC(FramelessDataHash, g_internalData)
Q_GLOBAL_STATIC(FramelessManagerData, g_framelessManagerData)
static constexpr const int kEventDelayInterval = 1000; static constexpr const int kEventDelayInterval = 1000;
@ -133,7 +131,7 @@ void FramelessManagerPrivate::initializeIconFont()
return; return;
} }
inited = true; inited = true;
framelesshelpercore_initResource(); FramelessHelperCoreInitResource();
// We always register this font because it's our only fallback. // 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")); const int id = QFontDatabase::addApplicationFont(FRAMELESSHELPER_STRING_LITERAL(":/org.wangwenx190.FramelessHelper/resources/fonts/iconfont.ttf"));
if (id < 0) { 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 bool FramelessManagerPrivate::isThemeOverrided() const
{ {
return (overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown); return (overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown);
@ -299,6 +310,15 @@ FramelessManager *FramelessManager::instance()
return &manager; 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 SystemTheme FramelessManager::systemTheme() const
{ {
Q_D(const FramelessManager); Q_D(const FramelessManager);
@ -342,51 +362,54 @@ void FramelessManager::setOverrideTheme(const SystemTheme theme)
Q_EMIT systemThemeChanged(); Q_EMIT systemThemeChanged();
} }
void FramelessManager::addWindow(FramelessParamsConst params) bool FramelessManager::addWindow(const QWindow *window)
{ {
Q_ASSERT(params); Q_ASSERT(window);
if (!params) { if (!window) {
return; return false;
} }
const WId windowId = params->getWindowId(); const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (g_framelessManagerData()->contains(windowId)) { if (data->isFrameless) {
return; return false;
} }
g_framelessManagerData()->append(windowId); data->isFrameless = true;
static const bool pureQt = usePureQtImplementation(); const bool pureQt = usePureQtImplementation();
if (pureQt) { if (pureQt) {
FramelessHelperQt::addWindow(params); FramelessHelperQt::addWindow(window);
} }
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
if (!pureQt) { if (!pureQt) {
FramelessHelperWin::addWindow(params); FramelessHelperWin::addWindow(window);
} }
std::ignore = Utils::installWindowProcHook(windowId, params); std::ignore = Utils::installWindowProcHook(window);
#endif #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); Q_ASSERT(window);
if (!windowId) { if (!window) {
return; return false;
} }
if (!g_framelessManagerData()->contains(windowId)) { const auto it = g_internalData()->constFind(window);
return; if ((it == g_internalData()->constEnd()) || !it.value()->isFrameless) {
return false;
} }
g_framelessManagerData()->removeAll(windowId); const bool pureQt = usePureQtImplementation();
static const bool pureQt = usePureQtImplementation();
if (pureQt) { if (pureQt) {
FramelessHelperQt::removeWindow(windowId); FramelessHelperQt::removeWindow(window);
} }
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
if (!pureQt) { if (!pureQt) {
FramelessHelperWin::removeWindow(windowId); FramelessHelperWin::removeWindow(window);
} }
std::ignore = Utils::uninstallWindowProcHook(windowId); std::ignore = Utils::uninstallWindowProcHook(window);
std::ignore = Utils::removeMicaWindow(windowId); std::ignore = Utils::removeMicaWindow(window);
#endif #endif
g_internalData()->erase(it);
return true;
} }
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -657,7 +657,7 @@ void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force)
void MicaMaterialPrivate::updateMaterialBrush() void MicaMaterialPrivate::updateMaterialBrush()
{ {
#if FRAMELESSHELPER_CONFIG(bundle_resource) #if FRAMELESSHELPER_CONFIG(bundle_resource)
framelesshelpercore_initResource(); FramelessHelperCoreInitResource();
static const QImage noiseTexture = QImage(FRAMELESSHELPER_STRING_LITERAL(":/org.wangwenx190.FramelessHelper/resources/images/noise.png")); static const QImage noiseTexture = QImage(FRAMELESSHELPER_STRING_LITERAL(":/org.wangwenx190.FramelessHelper/resources/images/noise.png"));
#endif // FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE #endif // FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE
QImage micaTexture = QImage(QSize(64, 64), kDefaultImageFormat); QImage micaTexture = QImage(QSize(64, 64), kDefaultImageFormat);

View File

@ -210,29 +210,35 @@ QWindow *Utils::findWindow(const WId windowId)
return nullptr; return nullptr;
} }
void Utils::moveWindowToDesktopCenter(FramelessParamsConst params, const bool considerTaskBar) bool Utils::moveWindowToDesktopCenter(const QWindow *window, const bool considerTaskBar)
{ {
Q_ASSERT(params); Q_ASSERT(window);
if (!params) { if (!window) {
return; return false;
} }
const QSize windowSize = params->getWindowSize(); const FramelessDataPtr data = FramelessHelperExtractData(window);
if (windowSize.isEmpty() || (windowSize == kDefaultWindowSize)) { Q_ASSERT(data);
return; 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) { if (!screen) {
screen = QGuiApplication::primaryScreen(); screen = QGuiApplication::primaryScreen();
} }
Q_ASSERT(screen); Q_ASSERT(screen);
if (!screen) { if (!screen) {
return; return false;
} }
const QSize screenSize = (considerTaskBar ? screen->availableSize() : screen->size()); const QSize screenSize = (considerTaskBar ? screen->availableSize() : screen->size());
const QPoint offset = (considerTaskBar ? screen->availableGeometry().topLeft() : QPoint(0, 0)); const QPoint offset = (considerTaskBar ? screen->availableGeometry().topLeft() : QPoint(0, 0));
const int newX = std::round(qreal(screenSize.width() - windowSize.width()) / qreal(2)); const int newX = std::round(qreal(screenSize.width() - windowSize.width()) / qreal(2));
const int newY = std::round(qreal(screenSize.height() - windowSize.height()) / 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) Qt::WindowState Utils::windowStatesToWindowState(const Qt::WindowStates states)
@ -314,9 +320,9 @@ bool Utils::shouldAppsUseDarkMode()
qreal Utils::roundScaleFactor(const qreal factor) qreal Utils::roundScaleFactor(const qreal factor)
{ {
// Qt can't handle scale factors less than 1.0 (according to the comments in qhighdpiscaling.cpp). // 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))); Q_ASSERT((factor > qreal(1)) || qFuzzyCompare(factor, qreal(1)));
if (factor < 1) { if (factor < qreal(1)) {
return 1; return qreal(1);
} }
#if (!FRAMELESSHELPER_CONFIG(private_qt) || (QT_VERSION < QT_VERSION_CHECK(6, 2, 1))) #if (!FRAMELESSHELPER_CONFIG(private_qt) || (QT_VERSION < QT_VERSION_CHECK(6, 2, 1)))
# if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) # if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))

View File

@ -193,16 +193,9 @@ FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient)
FRAMELESSHELPER_STRING_CONSTANT(DwmFlush) FRAMELESSHELPER_STRING_CONSTANT(DwmFlush)
FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos) FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos)
struct Win32UtilsData
{
SystemParameters params = {};
};
struct Win32UtilsInternal struct Win32UtilsInternal
{ {
QHash<WId, Win32UtilsData> data = {};
WNDPROC qtWindowProc = nullptr; WNDPROC qtWindowProc = nullptr;
QList<WId> micaWindowIds = {};
}; };
Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData) Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData)
@ -583,57 +576,6 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
}; };
#undef DEFINE_WIN32_MESSAGE #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) [[nodiscard]] QPoint point2qpoint(const POINT &point)
{ {
return QPoint{ int(point.x), int(point.y) }; return QPoint{ int(point.x), int(point.y) };
@ -664,16 +606,10 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) }; 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) [[nodiscard]] QString hwnd2str(const HWND hwnd)
{ {
// NULL handle is allowed here. // NULL handle is allowed here.
return hwnd2str(reinterpret_cast<WId>(hwnd)); return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(reinterpret_cast<WId>(hwnd), 16).toUpper().rightJustified(8, u'0');
} }
[[nodiscard]] std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd) [[nodiscard]] std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd)
@ -734,8 +670,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
static const auto currentOsVer = []() -> std::optional<VersionNumber> { static const auto currentOsVer = []() -> std::optional<VersionNumber> {
if (API_NT_AVAILABLE(RtlGetVersion)) { if (API_NT_AVAILABLE(RtlGetVersion)) {
using RtlGetVersionPtr = _NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW); using RtlGetVersionPtr = _NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
const auto pRtlGetVersion = const auto pRtlGetVersion = reinterpret_cast<RtlGetVersionPtr>(SysApiLoader::instance()->get(kntdll, kRtlGetVersion));
reinterpret_cast<RtlGetVersionPtr>(SysApiLoader::instance()->get(kntdll, kRtlGetVersion));
RTL_OSVERSIONINFOEXW osvi; RTL_OSVERSIONINFOEXW osvi;
SecureZeroMemory(&osvi, sizeof(osvi)); SecureZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi); osvi.dwOSVersionInfoSize = sizeof(osvi);
@ -785,8 +720,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return kErrorMessageTemplate.arg(function, QString::number(code), errorText); return kErrorMessageTemplate.arg(function, QString::number(code), errorText);
#else // !FRAMELESSHELPER_CONFIG(private_qt) #else // !FRAMELESSHELPER_CONFIG(private_qt)
LPWSTR buf = nullptr; LPWSTR buf = nullptr;
if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&buf), 0, nullptr) == 0) {
nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&buf), 0, nullptr) == 0) {
return FRAMELESSHELPER_STRING_LITERAL("FormatMessageW() returned empty string."); return FRAMELESSHELPER_STRING_LITERAL("FormatMessageW() returned empty string.");
} }
const QString errorText = QString::fromWCharArray(buf).trimmed(); const QString errorText = QString::fromWCharArray(buf).trimmed();
@ -839,16 +773,14 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
const int newWindowY = (activeMonitorRect.top + currentWindowOffsetY); const int newWindowY = (activeMonitorRect.top + currentWindowOffsetY);
static constexpr const UINT flags = static constexpr const UINT flags =
(SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER); (SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
if (::SetWindowPos(hwnd, nullptr, newWindowX, newWindowY, if (::SetWindowPos(hwnd, nullptr, newWindowX, newWindowY, currentWindowWidth, currentWindowHeight, flags) == FALSE) {
currentWindowWidth, currentWindowHeight, flags) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kSetWindowPos); WARNING << Utils::getSystemErrorMessage(kSetWindowPos);
return false; return false;
} }
return true; return true;
} }
[[nodiscard]] static inline int getSystemMetrics2(const int index, const bool horizontal, [[nodiscard]] static inline int getSystemMetrics2(const int index, const bool horizontal, const quint32 dpi)
const quint32 dpi)
{ {
Q_ASSERT(dpi != 0); Q_ASSERT(dpi != 0);
if (dpi == 0) { if (dpi == 0) {
@ -863,14 +795,13 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return std::round(qreal(::GetSystemMetrics(index)) / currentDpr * requestedDpr); return std::round(qreal(::GetSystemMetrics(index)) / currentDpr * requestedDpr);
} }
[[nodiscard]] static inline int getSystemMetrics2(const WId windowId, const int index, [[nodiscard]] static inline int getSystemMetrics2(const QWindow *window, const int index, const bool horizontal, const bool scaled)
const bool horizontal, const bool scaled)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
if (!windowId) { if (!window) {
return 0; 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); const UINT dpi = (scaled ? realDpi : USER_DEFAULT_SCREEN_DPI);
if (const int result = _GetSystemMetricsForDpi2(index, dpi); result > 0) { if (const int result = _GetSystemMetricsForDpi2(index, dpi); result > 0) {
@ -981,9 +912,13 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
Utils::printWin32Message(&message); Utils::printWin32Message(&message);
} }
#endif #endif
const auto windowId = reinterpret_cast<WId>(hWnd); const QWindow *window = Utils::findWindow(reinterpret_cast<WId>(hWnd));
const auto it = g_win32UtilsData()->data.constFind(windowId); if (!window || !FramelessManager::instance()->isFramelessWindow(window)) {
if (it == g_win32UtilsData()->data.constEnd()) { return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
const FramelessDataPtr data = FramelessHelperExtractData(window);
Q_ASSERT(data);
if (!data) {
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
} }
// https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025 // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025
@ -1034,26 +969,25 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return LRESULT(filterResult); return LRESULT(filterResult);
} }
} }
const Win32UtilsData &data = it.value();
const auto getNativePosFromMouse = [lParam]() -> QPoint { const auto getNativePosFromMouse = [lParam]() -> QPoint {
return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
}; };
const auto getNativeGlobalPosFromKeyboard = [hWnd, windowId]() -> QPoint { const auto getNativeGlobalPosFromKeyboard = [hWnd, window]() -> QPoint {
RECT windowPos = {}; RECT windowPos = {};
if (::GetWindowRect(hWnd, &windowPos) == FALSE) { if (::GetWindowRect(hWnd, &windowPos) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kGetWindowRect); WARNING << Utils::getSystemErrorMessage(kGetWindowRect);
return {}; return {};
} }
const bool maxOrFull = (IsMaximized(hWnd) || Utils::isFullScreen(windowId)); const bool maxOrFull = (IsMaximized(hWnd) || Utils::isFullScreen(window));
const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true); const int frameSizeX = Utils::getResizeBorderThickness(window, true, true);
const bool frameBorderVisible = Utils::isWindowFrameBorderVisible(); const bool frameBorderVisible = Utils::isWindowFrameBorderVisible();
const int horizontalOffset = ((maxOrFull || !frameBorderVisible) ? 0 : frameSizeX); const int horizontalOffset = ((maxOrFull || !frameBorderVisible) ? 0 : frameSizeX);
const auto verticalOffset = [windowId, frameBorderVisible, maxOrFull]() -> int { const auto verticalOffset = [window, frameBorderVisible, maxOrFull]() -> int {
const int titleBarHeight = Utils::getTitleBarHeight(windowId, true); const int titleBarHeight = Utils::getTitleBarHeight(window, true);
if (!frameBorderVisible) { if (!frameBorderVisible) {
return titleBarHeight; return titleBarHeight;
} }
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); const int frameSizeY = Utils::getResizeBorderThickness(window, false, true);
if (WindowsVersionHelper::isWin11OrGreater()) { if (WindowsVersionHelper::isWin11OrGreater()) {
if (maxOrFull) { if (maxOrFull) {
return (titleBarHeight + frameSizeY); return (titleBarHeight + frameSizeY);
@ -1073,8 +1007,8 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
switch (uMsg) { switch (uMsg) {
case WM_RBUTTONUP: { case WM_RBUTTONUP: {
const QPoint nativeLocalPos = getNativePosFromMouse(); const QPoint nativeLocalPos = getNativePosFromMouse();
const QPoint qtScenePos = Utils::fromNativeLocalPosition(data.params.getWindowHandle(), nativeLocalPos); const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, nativeLocalPos);
if (data.params.isInsideTitleBarDraggableArea(qtScenePos)) { if (data->callbacks.isInsideTitleBarDraggableArea(qtScenePos)) {
POINT pos = {nativeLocalPos.x(), nativeLocalPos.y()}; POINT pos = {nativeLocalPos.x(), nativeLocalPos.y()};
if (::ClientToScreen(hWnd, &pos) == FALSE) { if (::ClientToScreen(hWnd, &pos) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kClientToScreen); WARNING << Utils::getSystemErrorMessage(kClientToScreen);
@ -1084,12 +1018,12 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
nativeGlobalPos = {pos.x, pos.y}; nativeGlobalPos = {pos.x, pos.y};
} }
} break; } break;
case WM_NCRBUTTONUP: { case WM_NCRBUTTONUP:
if (wParam == HTCAPTION) { if (wParam == HTCAPTION) {
shouldShowSystemMenu = true; shouldShowSystemMenu = true;
nativeGlobalPos = getNativePosFromMouse(); nativeGlobalPos = getNativePosFromMouse();
} }
} break; break;
case WM_SYSCOMMAND: { case WM_SYSCOMMAND: {
const WPARAM filteredWParam = (wParam & 0xFFF0); const WPARAM filteredWParam = (wParam & 0xFFF0);
if ((filteredWParam == SC_KEYMENU) && (lParam == VK_SPACE)) { if ((filteredWParam == SC_KEYMENU) && (lParam == VK_SPACE)) {
@ -1112,7 +1046,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
break; break;
} }
if (shouldShowSystemMenu) { 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 // 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 // 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 // window doesn't have any window frame now, so return early here to avoid
@ -1160,23 +1094,19 @@ bool Utils::isDwmCompositionEnabled()
return (enabled != FALSE); return (enabled != FALSE);
} }
bool Utils::triggerFrameChange(const WId windowId) bool Utils::triggerFrameChange(const QWindow *window)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
if (!windowId) { if (!window) {
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = qWindowId<HWND>(window);
static constexpr const UINT swpFlags = static constexpr const UINT swpFlags = (SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
(SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE
| SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
if (::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, swpFlags) == FALSE) { if (::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, swpFlags) == FALSE) {
WARNING << getSystemErrorMessage(kSetWindowPos); WARNING << getSystemErrorMessage(kSetWindowPos);
return false; return false;
} }
static constexpr const UINT rdwFlags = static constexpr const UINT rdwFlags = (RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
(RDW_ERASE | RDW_FRAME | RDW_INVALIDATE
| RDW_UPDATENOW | RDW_ALLCHILDREN);
if (::RedrawWindow(hwnd, nullptr, nullptr, rdwFlags) == FALSE) { if (::RedrawWindow(hwnd, nullptr, nullptr, rdwFlags) == FALSE) {
WARNING << getSystemErrorMessage(kRedrawWindow); WARNING << getSystemErrorMessage(kRedrawWindow);
return false; return false;
@ -1184,10 +1114,10 @@ bool Utils::triggerFrameChange(const WId windowId)
return true; return true;
} }
bool Utils::updateWindowFrameMargins(const WId windowId, const bool reset) bool Utils::updateWindowFrameMargins(const QWindow *window, const bool reset)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
if (!windowId) { if (!window) {
return false; return false;
} }
if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) { if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) {
@ -1198,7 +1128,8 @@ bool Utils::updateWindowFrameMargins(const WId windowId, const bool reset)
if (!isDwmCompositionEnabled()) { if (!isDwmCompositionEnabled()) {
return false; 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 { const auto margins = [micaEnabled, reset]() -> MARGINS {
// To make Mica/Mica Alt work for normal Win32 windows, we have to // 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 // 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}; return {1, 1, 1, 1};
}(); }();
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = qWindowId<HWND>(window);
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmExtendFrameIntoClientArea, hwnd, &margins); const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmExtendFrameIntoClientArea, hwnd, &margins);
if (FAILED(hr)) { if (FAILED(hr)) {
WARNING << getSystemErrorMessageImpl(kDwmExtendFrameIntoClientArea, hr); WARNING << getSystemErrorMessageImpl(kDwmExtendFrameIntoClientArea, hr);
return false; return false;
} }
return triggerFrameChange(windowId); return triggerFrameChange(window);
} }
bool Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable) bool Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable)
@ -1228,17 +1159,16 @@ bool Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable)
if (!window) { if (!window) {
return false; return false;
} }
const WId windowId = window->winId(); const auto margins = [enable, window]() -> QMargins {
const auto margins = [enable, windowId]() -> QMargins {
if (!enable) { if (!enable) {
return {}; return {};
} }
const int titleBarHeight = getTitleBarHeight(windowId, true); const int titleBarHeight = getTitleBarHeight(window, true);
if (isWindowFrameBorderVisible()) { if (isWindowFrameBorderVisible()) {
return {0, -titleBarHeight, 0, 0}; return {0, -titleBarHeight, 0, 0};
} else { } else {
const int frameSizeX = getResizeBorderThickness(windowId, true, true); const int frameSizeX = getResizeBorderThickness(window, true, true);
const int frameSizeY = getResizeBorderThickness(windowId, false, true); const int frameSizeY = getResizeBorderThickness(window, false, true);
return {-frameSizeX, -titleBarHeight, -frameSizeX, -frameSizeY}; 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 // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
#endif // FRAMELESSHELPER_CONFIG(private_qt) #endif // FRAMELESSHELPER_CONFIG(private_qt)
return triggerFrameChange(windowId); return triggerFrameChange(window);
} }
QString Utils::getSystemErrorMessage(const QString &function) QString Utils::getSystemErrorMessage(const QString &function)
@ -1342,16 +1272,23 @@ DwmColorizationArea Utils::getDwmColorizationArea()
return DwmColorizationArea::None; return DwmColorizationArea::None;
} }
bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool selectFirstEntry, bool Utils::showSystemMenu(const QWindow *window, const QPoint &pos, const bool selectFirstEntry)
FramelessParamsConst params)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
Q_ASSERT(params); if (!window) {
if (!windowId || !params) {
return false; return false;
} }
const auto hWnd = reinterpret_cast<HWND>(windowId); if (!FramelessManager::instance()->isFramelessWindow(window)) {
return false;
}
const FramelessDataPtr data = FramelessHelperExtractData(window);
Q_ASSERT(data);
if (!data) {
return false;
}
const auto hWnd = qWindowId<HWND>(window);
const HMENU hMenu = ::GetSystemMenu(hWnd, FALSE); const HMENU hMenu = ::GetSystemMenu(hWnd, FALSE);
if (!hMenu) { if (!hMenu) {
// The corresponding window doesn't have a system menu, most likely due to the // 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. // Tweak the menu items according to the current window status and user settings.
const bool disableRestore = params->getProperty(kSysMenuDisableRestoreVar, false).toBool(); const bool disableRestore = data->callbacks.getProperty(kSysMenuDisableRestoreVar, false).toBool();
const bool disableMinimize = params->getProperty(kSysMenuDisableMinimizeVar, false).toBool(); const bool disableMinimize = data->callbacks.getProperty(kSysMenuDisableMinimizeVar, false).toBool();
const bool disableMaximize = params->getProperty(kSysMenuDisableMaximizeVar, false).toBool(); const bool disableMaximize = data->callbacks.getProperty(kSysMenuDisableMaximizeVar, false).toBool();
const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(windowId)); const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(window));
const bool fixedSize = params->isWindowFixedSize(); const bool fixedSize = data->callbacks.isWindowFixedSize();
::EnableMenuItem(hMenu, SC_RESTORE, (MF_BYCOMMAND | ((maxOrFull && !fixedSize && !disableRestore) ? MFS_ENABLED : MFS_DISABLED))); ::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 // 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 // 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); ::SetMenuDefaultItem(hMenu, defaultItemId, FALSE);
// Popup the system menu at the required position. // Popup the system menu at the required position.
const int result = ::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() const int result = ::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), pos.x(), pos.y(), 0, hWnd, nullptr);
? 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 // Unhighlight the first menu item after the popup menu is closed, otherwise it will keep
// highlighting until we unhighlight it manually. // highlighting until we unhighlight it manually.
@ -1420,13 +1356,13 @@ bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool sel
return true; return true;
} }
bool Utils::isFullScreen(const WId windowId) bool Utils::isFullScreen(const QWindow *window)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
if (!windowId) { if (!window) {
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = qWindowId<HWND>(window);
RECT windowRect = {}; RECT windowRect = {};
if (::GetWindowRect(hwnd, &windowRect) == FALSE) { if (::GetWindowRect(hwnd, &windowRect) == FALSE) {
WARNING << getSystemErrorMessage(kGetWindowRect); WARNING << getSystemErrorMessage(kGetWindowRect);
@ -1441,13 +1377,13 @@ bool Utils::isFullScreen(const WId windowId)
return (windowRect == mi.value().rcMonitor); return (windowRect == mi.value().rcMonitor);
} }
bool Utils::isWindowNoState(const WId windowId) bool Utils::isWindowNoState(const QWindow *window)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
if (!windowId) { if (!window) {
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = qWindowId<HWND>(window);
#if 0 #if 0
WINDOWPLACEMENT wp; WINDOWPLACEMENT wp;
SecureZeroMemory(&wp, sizeof(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 // 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. // and onwards, but it has been marked as deprecated by Microsoft.
if (API_D2D_AVAILABLE(D2D1CreateFactory)) { if (API_D2D_AVAILABLE(D2D1CreateFactory)) {
using D2D1CreateFactoryPtr = using D2D1CreateFactoryPtr = HRESULT(WINAPI *)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS *, void **);
HRESULT(WINAPI *)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS *, void **); const auto pD2D1CreateFactory = reinterpret_cast<D2D1CreateFactoryPtr>(SysApiLoader::instance()->get(kd2d1, kD2D1CreateFactory));
const auto pD2D1CreateFactory =
reinterpret_cast<D2D1CreateFactoryPtr>(SysApiLoader::instance()->get(kd2d1, kD2D1CreateFactory));
ID2D1Factory *d2dFactory = nullptr; ID2D1Factory *d2dFactory = nullptr;
HRESULT hr = pD2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), HRESULT hr = pD2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), nullptr, reinterpret_cast<void **>(&d2dFactory));
nullptr, reinterpret_cast<void **>(&d2dFactory));
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
// We want to get the newest system DPI, so refresh the system metrics // We want to get the newest system DPI, so refresh the system metrics
// manually to ensure that. // manually to ensure that.
@ -1674,13 +1607,13 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal)
return USER_DEFAULT_SCREEN_DPI; 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); Q_ASSERT(window);
if (!windowId) { if (!window) {
return USER_DEFAULT_SCREEN_DPI; return USER_DEFAULT_SCREEN_DPI;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = qWindowId<HWND>(window);
{ {
if (const UINT dpi = _GetDpiForWindow2(hwnd)) { if (const UINT dpi = _GetDpiForWindow2(hwnd)) {
return dpi; return dpi;
@ -1740,26 +1673,22 @@ quint32 Utils::getResizeBorderThicknessForDpi(const bool horizontal, const quint
return 0; return 0;
} }
if (horizontal) { if (horizontal) {
return (getSystemMetrics2(SM_CXSIZEFRAME, true, dpi) return (getSystemMetrics2(SM_CXSIZEFRAME, true, dpi) + getSystemMetrics2(SM_CXPADDEDBORDER, true, dpi));
+ getSystemMetrics2(SM_CXPADDEDBORDER, true, dpi));
} else { } else {
return (getSystemMetrics2(SM_CYSIZEFRAME, false, dpi) return (getSystemMetrics2(SM_CYSIZEFRAME, false, dpi) + getSystemMetrics2(SM_CYPADDEDBORDER, 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); Q_ASSERT(window);
if (!windowId) { if (!window) {
return 0; return 0;
} }
if (horizontal) { if (horizontal) {
return (getSystemMetrics2(windowId, SM_CXSIZEFRAME, true, scaled) return (getSystemMetrics2(window, SM_CXSIZEFRAME, true, scaled) + getSystemMetrics2(window, SM_CXPADDEDBORDER, true, scaled));
+ getSystemMetrics2(windowId, SM_CXPADDEDBORDER, true, scaled));
} else { } else {
return (getSystemMetrics2(windowId, SM_CYSIZEFRAME, false, scaled) return (getSystemMetrics2(window, SM_CYSIZEFRAME, false, scaled) + getSystemMetrics2(window, SM_CYPADDEDBORDER, false, scaled));
+ getSystemMetrics2(windowId, SM_CYPADDEDBORDER, false, scaled));
} }
} }
@ -1772,13 +1701,13 @@ quint32 Utils::getCaptionBarHeightForDpi(const quint32 dpi)
return getSystemMetrics2(SM_CYCAPTION, false, 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); Q_ASSERT(window);
if (!windowId) { if (!window) {
return 0; return 0;
} }
return getSystemMetrics2(windowId, SM_CYCAPTION, false, scaled); return getSystemMetrics2(window, SM_CYCAPTION, false, scaled);
} }
quint32 Utils::getTitleBarHeightForDpi(const quint32 dpi) quint32 Utils::getTitleBarHeightForDpi(const quint32 dpi)
@ -1790,13 +1719,13 @@ quint32 Utils::getTitleBarHeightForDpi(const quint32 dpi)
return (getCaptionBarHeightForDpi(dpi) + getResizeBorderThicknessForDpi(false, 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); Q_ASSERT(window);
if (!windowId) { if (!window) {
return 0; return 0;
} }
return (getCaptionBarHeight(windowId, scaled) + getResizeBorderThickness(windowId, false, scaled)); return (getCaptionBarHeight(window, scaled) + getResizeBorderThickness(window, false, scaled));
} }
quint32 Utils::getFrameBorderThicknessForDpi(const quint32 dpi) quint32 Utils::getFrameBorderThicknessForDpi(const quint32 dpi)
@ -1813,10 +1742,10 @@ quint32 Utils::getFrameBorderThicknessForDpi(const quint32 dpi)
return std::round(qreal(kDefaultWindowFrameBorderThickness) * dpr); 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); Q_ASSERT(window);
if (!windowId) { if (!window) {
return 0; return 0;
} }
// There's no window frame border before Windows 10. // 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)) { if (!API_DWM_AVAILABLE(DwmGetWindowAttribute)) {
return 0; 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 qreal scaleFactor = (qreal(dpi) / qreal(USER_DEFAULT_SCREEN_DPI));
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = qWindowId<HWND>(window);
UINT value = 0; UINT value = 0;
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetWindowAttribute, hwnd, const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetWindowAttribute, hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value));
_DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value));
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
const qreal dpr = (scaled ? 1.0 : scaleFactor); const qreal dpr = (scaled ? qreal(1) : scaleFactor);
return std::round(qreal(value) / dpr); return std::round(qreal(value) / dpr);
} else { } else {
const qreal dpr = (scaled ? scaleFactor : 1.0); const qreal dpr = (scaled ? scaleFactor : qreal(1));
return std::round(qreal(kDefaultWindowFrameBorderThickness) * dpr); 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); Q_ASSERT(window);
if (!windowId) { if (!window) {
return false; return false;
} }
static const bool dont = (qEnvironmentVariableIntValue("FRAMELESSHELPER_WINDOWS_DONT_FIX_QT") != 0); static const bool dont = (qEnvironmentVariableIntValue("FRAMELESSHELPER_WINDOWS_DONT_FIX_QT") != 0);
if (dont) { if (dont) {
return true; return true;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = qWindowId<HWND>(window);
#if 0 #if 0
::SetLastError(ERROR_SUCCESS); ::SetLastError(ERROR_SUCCESS);
const auto classStyle = static_cast<DWORD>(::GetClassLongPtrW(hwnd, GCL_STYLE)); const auto classStyle = static_cast<DWORD>(::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) bool Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
@ -1948,7 +1876,7 @@ bool Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
WARNING << getSystemErrorMessage(kReleaseCapture); WARNING << getSystemErrorMessage(kReleaseCapture);
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(window->winId()); const auto hwnd = qWindowId<HWND>(window);
if (::PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) { if (::PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) {
WARNING << getSystemErrorMessage(kPostMessageW); WARNING << getSystemErrorMessage(kPostMessageW);
return false; return false;
@ -1974,7 +1902,7 @@ bool Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
WARNING << getSystemErrorMessage(kReleaseCapture); WARNING << getSystemErrorMessage(kReleaseCapture);
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(window->winId()); const auto hwnd = qWindowId<HWND<(window);
if (::PostMessageW(hwnd, WM_SYSCOMMAND, qtEdgesToWin32Orientation(edges), 0) == FALSE) { if (::PostMessageW(hwnd, WM_SYSCOMMAND, qtEdgesToWin32Orientation(edges), 0) == FALSE) {
WARNING << getSystemErrorMessage(kPostMessageW); WARNING << getSystemErrorMessage(kPostMessageW);
return false; return false;
@ -2016,14 +1944,13 @@ bool Utils::isFrameBorderColorized()
return isTitleBarColorized(); return isTitleBarColorized();
} }
bool Utils::installWindowProcHook(const WId windowId, FramelessParamsConst params) bool Utils::installWindowProcHook(const QWindow *window)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
Q_ASSERT(params); if (!window) {
if (!windowId || !params) {
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = qWindowId<HWND>(window);
if (!g_win32UtilsData()->qtWindowProc) { if (!g_win32UtilsData()->qtWindowProc) {
::SetLastError(ERROR_SUCCESS); ::SetLastError(ERROR_SUCCESS);
const auto qtWindowProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hwnd, GWLP_WNDPROC)); const auto qtWindowProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hwnd, GWLP_WNDPROC));
@ -2034,16 +1961,18 @@ bool Utils::installWindowProcHook(const WId windowId, FramelessParamsConst param
} }
g_win32UtilsData()->qtWindowProc = qtWindowProc; g_win32UtilsData()->qtWindowProc = qtWindowProc;
} }
const auto it = g_win32UtilsData()->data.constFind(windowId); FramelessDataPtr data = FramelessHelperExtractData(window);
if (it == g_win32UtilsData()->data.constEnd()) { if (!data) {
Win32UtilsData data = {}; data.reset(new FramelessData);
data.params = *params; FramelessHelperSetData(const_cast<QWindow *>(window), data);
g_win32UtilsData()->data.insert(windowId, data); }
if (!data->windowProcHooked) {
::SetLastError(ERROR_SUCCESS); ::SetLastError(ERROR_SUCCESS);
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(FramelessHelperHookWindowProc)) == 0) { if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(FramelessHelperHookWindowProc)) == 0) {
WARNING << getSystemErrorMessage(kSetWindowLongPtrW); WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
return false; return false;
} }
data->windowProcHooked = true;
} }
return true; return true;
} }