This commit is contained in:
Yuhang Zhao 2023-09-14 17:58:50 +08:00 committed by Zhao Yuhang
parent b946809927
commit d86f55832f
67 changed files with 1703 additions and 1304 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,25 +167,23 @@ 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. unset(CMAKE_MSVC_RUNTIME_LIBRARY)
unset(CMAKE_MSVC_RUNTIME_LIBRARY) unset(CMAKE_MSVC_RUNTIME_LIBRARY CACHE)
unset(CMAKE_MSVC_RUNTIME_LIBRARY CACHE) #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()
if(FRAMELESSHELPER_ENABLE_YYTHUNKS)
unset(YYTHUNKS_TARGET_OS)
unset(YYTHUNKS_TARGET_OS CACHE)
#unset(YYTHUNKS_TARGET_OS PARENT_SCOPE)
set(YYTHUNKS_TARGET_OS "WinXP" CACHE STRING "" FORCE)
include(cmake/YY-Thunks.cmake)
endif() endif()
endif() endif()
if(FRAMELESSHELPER_ENABLE_YYTHUNKS)
unset(YYTHUNKS_TARGET_OS)
unset(YYTHUNKS_TARGET_OS CACHE)
#unset(YYTHUNKS_TARGET_OS PARENT_SCOPE)
set(YYTHUNKS_TARGET_OS "WinXP" CACHE STRING "" FORCE)
include(cmake/YY-Thunks.cmake)
endif()
set(__extra_flags "") set(__extra_flags "")
if(FRAMELESSHELPER_NO_INSTALL) if(FRAMELESSHELPER_NO_INSTALL)
@ -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)

47
build.bat Normal file
View File

@ -0,0 +1,47 @@
@echo off
title Building FramelessHelper ...
setlocal
cls
set __vs_bat=%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat
if not exist "%__vs_bat%" set __vs_bat=%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat
if not exist "%__vs_bat%" set __vs_bat=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat
if not exist "%__vs_bat%" set __vs_bat=%ProgramFiles(x86)%\Microsoft Visual Studio\2015\Community\VC\Auxiliary\Build\vcvars64.bat
if not exist "%__vs_bat%" (
echo Cannot find a valid Visual Studio toolchain!
echo Please install at least Visual Studio 2015 to the default location
echo and install the English language pack at the same time.
echo If you want to use clang-cl or MinGW to build this project, please
echo make sure you have added their directory to your PATH environment
echo variable.
echo Press the ENTER key to continue, or close this window directly.
pause
) else (
call "%__vs_bat%"
)
cmake --version
echo ninja build
ninja --version
cd /d "%~dp0"
if exist build.user.bat call build.user.bat
if not defined CC set CC=cl.exe
if not defined CXX set CXX=cl.exe
if not defined QTDIR set QTDIR=%SystemDrive%\Qt\6.6.0\msvc2019_64
echo CC=%CC%
echo CXX=%CXX%
echo QTDIR=%QTDIR%
if exist build rd /s /q build
md build
cd build
md cmake
cd cmake
cmake -DCMAKE_C_COMPILER="%CC%" -DCMAKE_CXX_COMPILER="%CXX%" -DCMAKE_PREFIX_PATH="%QTDIR%" -DCMAKE_INSTALL_PREFIX="%~dp0build\install" -DCMAKE_CONFIGURATION_TYPES=Release;Debug -G"Ninja Multi-Config" -DFRAMELESSHELPER_ENABLE_VCLTL=ON -DFRAMELESSHELPER_ENABLE_YYTHUNKS=ON -DFRAMELESSHELPER_ENABLE_SPECTRE=ON -DFRAMELESSHELPER_ENABLE_EHCONTGUARD=ON -DFRAMELESSHELPER_ENABLE_INTELCET=ON -DFRAMELESSHELPER_ENABLE_INTELJCC=ON -DFRAMELESSHELPER_ENABLE_CFGUARD=ON -DFRAMELESSHELPER_FORCE_LTO=ON "%~dp0"
cmake --build . --target all --config Release --parallel
cmake --build . --target all --config Debug --parallel
cmake --install . --config Release --strip
cmake --install . --config Debug
goto fin
:fin
endlocal
cd /d "%~dp0"
pause
exit /b 0

View File

@ -1,37 +0,0 @@
@echo off
title Building FramelessHelper ...
setlocal
cls
set __vs_bat=%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat
if not exist "%__vs_bat%" set __vs_bat=%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat
if not exist "%__vs_bat%" set __vs_bat=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat
if not exist "%__vs_bat%" set __vs_bat=%ProgramFiles(x86)%\Microsoft Visual Studio\2015\Community\VC\Auxiliary\Build\vcvars64.bat
if not exist "%__vs_bat%" (
echo Cannot find a valid Visual Studio toolchain!
echo Please install at least Visual Studio 2015 to the default location!
goto fin
)
call "%__vs_bat%"
cmake --version
echo ninja build
ninja --version
cd /d "%~dp0"
if exist "%~dp0build.user.bat" call "%~dp0build.user.bat"
if not defined QTDIR set QTDIR=C:\Qt\6.6.0\msvc2019_64
echo QTDIR=%QTDIR%
if exist cmake rd /s /q cmake
md cmake
cd cmake
md build
cd build
cmake -DCMAKE_PREFIX_PATH="%QTDIR%" -DCMAKE_INSTALL_PREFIX="%~dp0cmake\install" -DCMAKE_CONFIGURATION_TYPES=Release;Debug -G"Ninja Multi-Config" -DFRAMELESSHELPER_ENABLE_VCLTL=ON -DFRAMELESSHELPER_ENABLE_YYTHUNKS=ON -DFRAMELESSHELPER_ENABLE_SPECTRE=ON -DFRAMELESSHELPER_ENABLE_EHCONTGUARD=ON -DFRAMELESSHELPER_ENABLE_INTELCET=ON -DFRAMELESSHELPER_ENABLE_INTELJCC=ON -DFRAMELESSHELPER_ENABLE_CFGUARD=ON -DFRAMELESSHELPER_FORCE_LTO=ON "%~dp0.."
cmake --build . --target all --config Release --parallel
cmake --build . --target all --config Debug --parallel
cmake --install . --config Release --strip
cmake --install . --config Debug
goto fin
:fin
endlocal
cd /d "%~dp0"
pause
exit /b 0

View File

@ -31,13 +31,10 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class ChromePalettePrivate; class ChromePalettePrivate;
class FRAMELESSHELPER_CORE_API ChromePalette : public QObject class FRAMELESSHELPER_CORE_API ChromePalette : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(ChromePalette)
Q_DECLARE_PRIVATE(ChromePalette)
Q_DISABLE_COPY_MOVE(ChromePalette)
Q_PROPERTY(QColor titleBarActiveBackgroundColor READ titleBarActiveBackgroundColor Q_PROPERTY(QColor titleBarActiveBackgroundColor READ titleBarActiveBackgroundColor
WRITE setTitleBarActiveBackgroundColor RESET resetTitleBarActiveBackgroundColor WRITE setTitleBarActiveBackgroundColor RESET resetTitleBarActiveBackgroundColor
@ -120,9 +117,6 @@ Q_SIGNALS:
void closeButtonPressColorChanged(); void closeButtonPressColorChanged();
void titleBarColorChanged(); void titleBarColorChanged();
void chromeButtonColorChanged(); void chromeButtonColorChanged();
private:
QScopedPointer<ChromePalettePrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -26,25 +26,27 @@
#include <FramelessHelper/Core/framelesshelpercore_global.h> #include <FramelessHelper/Core/framelesshelpercore_global.h>
#if !FRAMELESSHELPER_CONFIG(native_impl)
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
struct SystemParameters; class FramelessHelperQtPrivate;
class FRAMELESSHELPER_CORE_API FramelessHelperQt : public QObject class FRAMELESSHELPER_CORE_API FramelessHelperQt : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessHelperQt)
Q_DISABLE_COPY_MOVE(FramelessHelperQt)
public: 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 QObject *window);
static void removeWindow(const WId windowId); static void removeWindow(const QObject *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,24 +29,26 @@
#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
{ {
Q_DISABLE_COPY_MOVE(FramelessHelperWin) FRAMELESSHELPER_CLASS(FramelessHelperWin)
public: public:
explicit FramelessHelperWin(); explicit FramelessHelperWin();
~FramelessHelperWin() override; ~FramelessHelperWin() override;
static void addWindow(const SystemParameters *params); static void addWindow(const QObject *window);
static void removeWindow(const WId windowId); static void removeWindow(const QObject *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

@ -86,6 +86,46 @@
#include <FramelessHelper/Core/framelesshelpercore_global.h> #include <FramelessHelper/Core/framelesshelpercore_global.h>
#ifndef SC_SIZE
# define SC_SIZE (0xF000)
#endif
#ifndef SC_SIZELEFT
# define SC_SIZELEFT (0xF001)
#endif
#ifndef SC_SIZERIGHT
# define SC_SIZERIGHT (0xF002)
#endif
#ifndef SC_SIZETOP
# define SC_SIZETOP (0xF003)
#endif
#ifndef SC_SIZETOPLEFT
# define SC_SIZETOPLEFT (0xF004)
#endif
#ifndef SC_SIZETOPRIGHT
# define SC_SIZETOPRIGHT (0xF005)
#endif
#ifndef SC_SIZEBOTTOM
# define SC_SIZEBOTTOM (0xF006)
#endif
#ifndef SC_SIZEBOTTOMLEFT
# define SC_SIZEBOTTOMLEFT (0xF007)
#endif
#ifndef SC_SIZEBOTTOMRIGHT
# define SC_SIZEBOTTOMRIGHT (0xF008)
#endif
#ifndef SC_DRAGMOVE
# define SC_DRAGMOVE (0xF012)
#endif
#ifndef WM_SIZEWAIT #ifndef WM_SIZEWAIT
# define WM_SIZEWAIT (0x0004) # define WM_SIZEWAIT (0x0004)
#endif #endif
@ -1102,7 +1142,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";
@ -1111,3 +1151,95 @@ 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);
}
[[nodiscard]] inline constexpr QPoint point2qpoint(const POINT &point)
{
return QPoint{ int(point.x), int(point.y) };
}
[[nodiscard]] inline constexpr POINT qpoint2point(const QPoint &point)
{
return POINT{ LONG(point.x()), LONG(point.y()) };
}
[[nodiscard]] inline constexpr QSize size2qsize(const SIZE &size)
{
return QSize{ int(size.cx), int(size.cy) };
}
[[nodiscard]] inline constexpr SIZE qsize2size(const QSize &size)
{
return SIZE{ LONG(size.width()), LONG(size.height()) };
}
[[nodiscard]] inline constexpr QRect rect2qrect(const RECT &rect)
{
return QRect{ QPoint{ int(rect.left), int(rect.top) }, QSize{ int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect)) } };
}
[[nodiscard]] inline constexpr RECT qrect2rect(const QRect &qrect)
{
return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) };
}
[[nodiscard]] inline /*constexpr*/ 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]] inline /*constexpr*/ QString hwnd2str(const HWND hwnd)
{
// NULL handle is allowed here.
return hwnd2str(reinterpret_cast<WId>(hwnd));
}

View File

@ -67,11 +67,16 @@ QT_END_NAMESPACE
# define Q_OS_WINDOWS // Since 5.14 # define Q_OS_WINDOWS // Since 5.14
#endif #endif
#ifndef Q_DISABLE_MOVE
# define Q_DISABLE_MOVE(Class) \
Class(Class &&) = delete; \
Class &operator=(Class &&) = delete;
#endif
#ifndef Q_DISABLE_COPY_MOVE // Since 5.13 #ifndef Q_DISABLE_COPY_MOVE // Since 5.13
# define Q_DISABLE_COPY_MOVE(Class) \ # define Q_DISABLE_COPY_MOVE(Class) \
Q_DISABLE_COPY(Class) \ Q_DISABLE_COPY(Class) \
Class(Class &&) = delete; \ Q_DISABLE_MOVE(Class)
Class &operator=(Class &&) = delete;
#endif #endif
#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0)) #if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
@ -253,6 +258,83 @@ QT_END_NAMESPACE
} }
#endif #endif
#ifndef FRAMELESSHELPER_CLASS
# define FRAMELESSHELPER_CLASS(Class) \
private: \
Q_DISABLE_COPY(Class)
#endif
#ifndef FRAMELESSHELPER_CLASS_DPTR
# define FRAMELESSHELPER_CLASS_DPTR(Class) \
private: \
Q_DECLARE_PRIVATE(Class) \
const QScopedPointer<Class##Private> d_ptr;
#endif
#ifndef FRAMELESSHELPER_CLASS_QPTR
# define FRAMELESSHELPER_CLASS_QPTR(Class) \
private: \
Q_DECLARE_PUBLIC(Class) \
public: \
Class *q_ptr = nullptr;
#endif
#ifndef FRAMELESSHELPER_PRIVATE_CLASS_GETTER
# define FRAMELESSHELPER_PRIVATE_CLASS_GETTER(Class) \
public: \
Q_NODISCARD static Class##Private *get(Class *q); \
Q_NODISCARD static const Class##Private *get(const Class *q);
#endif
#ifndef FRAMELESSHELPER_PRIVATE_CLASS_GETTER_IMPL
# define FRAMELESSHELPER_PRIVATE_CLASS_GETTER_IMPL(Class) \
Class##Private *Class##Private::get(Class *q) { \
Q_ASSERT(q); \
return (q ? q->d_func() : nullptr); \
} \
const Class##Private *Class##Private::get(const Class *q) { \
Q_ASSERT(q); \
return (q ? q->d_func() : nullptr); \
}
#endif
#ifndef FRAMELESSHELPER_PUBLIC_CLASS
# define FRAMELESSHELPER_PUBLIC_CLASS(Class) \
private: \
FRAMELESSHELPER_CLASS(Class) \
FRAMELESSHELPER_CLASS_DPTR(Class)
#endif
#ifndef FRAMELESSHELPER_PRIVATE_CLASS
# define FRAMELESSHELPER_PRIVATE_CLASS(Class) \
private: \
FRAMELESSHELPER_CLASS(Class##Private) \
FRAMELESSHELPER_CLASS_QPTR(Class) \
FRAMELESSHELPER_PRIVATE_CLASS_GETTER(Class)
#endif
#ifndef FRAMELESSHELPER_QT_CLASS
# define FRAMELESSHELPER_QT_CLASS(Class) \
private: \
FRAMELESSHELPER_CLASS_INFO \
FRAMELESSHELPER_CLASS(Class)
#endif
#ifndef FRAMELESSHELPER_PUBLIC_QT_CLASS
# define FRAMELESSHELPER_PUBLIC_QT_CLASS(Class) \
private: \
FRAMELESSHELPER_QT_CLASS(Class) \
FRAMELESSHELPER_CLASS_DPTR(Class)
#endif
#ifndef FRAMELESSHELPER_PRIVATE_QT_CLASS
# define FRAMELESSHELPER_PRIVATE_QT_CLASS(Class) \
private: \
FRAMELESSHELPER_QT_CLASS(Class##Private) \
FRAMELESSHELPER_CLASS_QPTR(Class) \
FRAMELESSHELPER_PRIVATE_CLASS_GETTER(Class)
#endif
#if FRAMELESSHELPER_CONFIG(bundle_resource) #if FRAMELESSHELPER_CONFIG(bundle_resource)
// Call this function in your main() function if you are using FramelessHelper as a static library, // Call this function in your main() function if you are using FramelessHelper as a static library,
// it can make sure the resources bundled in the static library are correctly initialized. // it can make sure the resources bundled in the static library are correctly initialized.

View File

@ -28,15 +28,11 @@
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
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessManager)
Q_DECLARE_PRIVATE(FramelessManager)
Q_DISABLE_COPY_MOVE(FramelessManager)
Q_PROPERTY(Global::SystemTheme systemTheme READ systemTheme WRITE setOverrideTheme NOTIFY systemThemeChanged FINAL) Q_PROPERTY(Global::SystemTheme systemTheme READ systemTheme WRITE setOverrideTheme NOTIFY systemThemeChanged FINAL)
Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemThemeChanged FINAL) Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemThemeChanged FINAL)
Q_PROPERTY(QString wallpaper READ wallpaper NOTIFY wallpaperChanged FINAL) Q_PROPERTY(QString wallpaper READ wallpaper NOTIFY wallpaperChanged FINAL)
@ -51,8 +47,8 @@ public:
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 QObject *window, const WId windowId);
void removeWindow(const WId windowId); Q_NODISCARD bool removeWindow(const QObject *window);
void setOverrideTheme(const Global::SystemTheme theme); void setOverrideTheme(const Global::SystemTheme theme);
Q_SIGNALS: Q_SIGNALS:
@ -62,9 +58,6 @@ Q_SIGNALS:
private: private:
explicit FramelessManager(QObject *parent = nullptr); explicit FramelessManager(QObject *parent = nullptr);
~FramelessManager() override; ~FramelessManager() override;
private:
QScopedPointer<FramelessManagerPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -31,13 +31,10 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class MicaMaterialPrivate; class MicaMaterialPrivate;
class FRAMELESSHELPER_CORE_API MicaMaterial : public QObject class FRAMELESSHELPER_CORE_API MicaMaterial : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(MicaMaterial)
Q_DISABLE_COPY_MOVE(MicaMaterial)
Q_DECLARE_PRIVATE(MicaMaterial)
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged FINAL) Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged FINAL)
Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged FINAL) Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged FINAL)
@ -80,9 +77,6 @@ Q_SIGNALS:
void noiseOpacityChanged(); void noiseOpacityChanged();
void fallbackEnabledChanged(); void fallbackEnabledChanged();
void shouldRedraw(); void shouldRedraw();
private:
QScopedPointer<MicaMaterialPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -32,24 +32,17 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class ChromePalette; class ChromePalette;
class FRAMELESSHELPER_CORE_API ChromePalettePrivate : public QObject class FRAMELESSHELPER_CORE_API ChromePalettePrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(ChromePalette)
Q_DECLARE_PUBLIC(ChromePalette)
Q_DISABLE_COPY_MOVE(ChromePalettePrivate)
public: public:
explicit ChromePalettePrivate(ChromePalette *q); explicit ChromePalettePrivate(ChromePalette *q);
~ChromePalettePrivate() override; ~ChromePalettePrivate() override;
Q_NODISCARD static ChromePalettePrivate *get(ChromePalette *q);
Q_NODISCARD static const ChromePalettePrivate *get(const ChromePalette *q);
Q_SLOT void refresh(); Q_SLOT void refresh();
ChromePalette *q_ptr = nullptr;
// System-defined ones: // System-defined ones:
QColor titleBarActiveBackgroundColor_sys = {}; QColor titleBarActiveBackgroundColor_sys = {};
QColor titleBarInactiveBackgroundColor_sys = {}; QColor titleBarInactiveBackgroundColor_sys = {};

View File

@ -31,8 +31,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_CORE_API FramelessConfig : public QObject class FRAMELESSHELPER_CORE_API FramelessConfig : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(FramelessConfig)
Q_DISABLE_COPY_MOVE(FramelessConfig)
public: public:
Q_NODISCARD static FramelessConfig *instance(); Q_NODISCARD static FramelessConfig *instance();

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/qwindowdefs.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 FRAMELESSHELPER_CORE_API FramelessCallbacks
{ {
GetWindowFlagsCallback getWindowFlags = nullptr; GetWindowFlagsCallback getWindowFlags = nullptr;
SetWindowFlagsCallback setWindowFlags = nullptr; SetWindowFlagsCallback setWindowFlags = nullptr;
@ -92,29 +95,90 @@ struct SystemParameters
GetWidgetHandleCallback getWidgetHandle = nullptr; GetWidgetHandleCallback getWidgetHandle = nullptr;
ForceChildrenRepaintCallback forceChildrenRepaint = nullptr; ForceChildrenRepaintCallback forceChildrenRepaint = nullptr;
ResetQtGrabbedControlCallback resetQtGrabbedControl = nullptr; ResetQtGrabbedControlCallback resetQtGrabbedControl = nullptr;
FramelessCallbacks();
virtual ~FramelessCallbacks();
using PtrType = std::shared_ptr<FramelessCallbacks>;
[[nodiscard]] static PtrType create();
private:
FRAMELESSHELPER_CLASS(FramelessCallbacks)
};
using FramelessCallbacksPtr = FramelessCallbacks::PtrType;
enum class ExtraDataType : quint8
{
WindowsUtilities,
LinuxUtilities,
MacOSUtilities,
FramelessWidgetsHelper,
FramelessQuickHelper
}; };
using FramelessParams = SystemParameters *; #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
using FramelessParamsConst = const SystemParameters *; inline uint qHash(const ExtraDataType key, const uint seed = 0) noexcept {
using FramelessParamsRef = SystemParameters &; return ::qHash(static_cast<quint8>(key), seed);
using FramelessParamsConstRef = const SystemParameters &; }
#endif
struct FRAMELESSHELPER_CORE_API FramelessExtraData
{
FramelessExtraData();
virtual ~FramelessExtraData();
using PtrType = std::shared_ptr<FramelessExtraData>;
private:
FRAMELESSHELPER_CLASS(FramelessExtraData)
};
using FramelessExtraDataPtr = FramelessExtraData::PtrType;
using FramelessExtraDataPtrs = QList<FramelessExtraDataPtr>;
using FramelessExtraDataHash = QHash<ExtraDataType, FramelessExtraDataPtr>;
struct FRAMELESSHELPER_CORE_API FramelessData
{
QObject *window = nullptr;
WId windowId = 0;
QObject *internalEventHandler = nullptr;
bool frameless = false;
FramelessCallbacksPtr callbacks = nullptr;
FramelessExtraDataHash extraData = {};
FramelessData();
virtual ~FramelessData();
using PtrType = std::shared_ptr<FramelessData>;
[[nodiscard]] static PtrType create();
private:
FRAMELESSHELPER_CLASS(FramelessData)
};
using FramelessDataPtr = FramelessData::PtrType;
using FramelessDataPtrs = QList<FramelessDataPtr>;
using FramelessDataHash = QHash<QObject *, FramelessDataPtr>;
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,23 +30,19 @@
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
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessManager)
Q_DECLARE_PUBLIC(FramelessManager)
Q_DISABLE_COPY_MOVE(FramelessManagerPrivate)
public: public:
explicit FramelessManagerPrivate(FramelessManager *q); explicit FramelessManagerPrivate(FramelessManager *q);
~FramelessManagerPrivate() override; ~FramelessManagerPrivate() override;
Q_NODISCARD static FramelessManagerPrivate *get(FramelessManager *pub);
Q_NODISCARD static const FramelessManagerPrivate *get(const FramelessManager *pub);
static void initializeIconFont(); static void initializeIconFont();
Q_NODISCARD static QFont getIconFont(); Q_NODISCARD static QFont getIconFont();
@ -60,7 +56,12 @@ public:
void doNotifySystemThemeHasChangedOrNot(); void doNotifySystemThemeHasChangedOrNot();
void doNotifyWallpaperHasChangedOrNot(); void doNotifyWallpaperHasChangedOrNot();
FramelessManager *q_ptr = nullptr; Q_NODISCARD static FramelessDataPtr getData(const QObject *window);
Q_NODISCARD static FramelessDataPtr createData(const QObject *window, const WId windowId);
Q_NODISCARD static WId getWindowId(const QObject *window);
Q_NODISCARD static QObject *getWindow(const WId windowId);
static void updateWindowId(const QObject *window, const WId newWindowId);
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;
QColor accentColor = {}; QColor accentColor = {};

View File

@ -32,21 +32,15 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class MicaMaterial; class MicaMaterial;
class FRAMELESSHELPER_CORE_API MicaMaterialPrivate : public QObject class FRAMELESSHELPER_CORE_API MicaMaterialPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(MicaMaterial)
Q_DISABLE_COPY_MOVE(MicaMaterialPrivate)
Q_DECLARE_PUBLIC(MicaMaterial)
public: public:
explicit MicaMaterialPrivate(MicaMaterial *q); explicit MicaMaterialPrivate(MicaMaterial *q);
~MicaMaterialPrivate() override; ~MicaMaterialPrivate() override;
Q_NODISCARD static MicaMaterialPrivate *get(MicaMaterial *q);
Q_NODISCARD static const MicaMaterialPrivate *get(const MicaMaterial *q);
Q_NODISCARD static QColor systemFallbackColor(); Q_NODISCARD static QColor systemFallbackColor();
Q_NODISCARD QPoint mapToWallpaper(const QPoint &pos) const; Q_NODISCARD QPoint mapToWallpaper(const QPoint &pos) const;
@ -60,7 +54,6 @@ public:
void initialize(); void initialize();
void prepareGraphicsResources(); void prepareGraphicsResources();
MicaMaterial *q_ptr = nullptr;
QColor tintColor = {}; QColor tintColor = {};
qreal tintOpacity = qreal(0); qreal tintOpacity = qreal(0);
QColor fallbackColor = {}; QColor fallbackColor = {};

View File

@ -60,8 +60,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_CORE_API RegistryKey : public QObject class FRAMELESSHELPER_CORE_API RegistryKey : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(RegistryKey)
Q_DISABLE_COPY_MOVE(RegistryKey)
public: public:
explicit RegistryKey(const Global::RegistryRootKey root, const QString &key, QObject *parent = nullptr); explicit RegistryKey(const Global::RegistryRootKey root, const QString &key, QObject *parent = nullptr);

View File

@ -37,7 +37,7 @@ using ScopeGuardCallback = std::function<void()>;
class [[nodiscard]] ScopeGuard class [[nodiscard]] ScopeGuard
{ {
Q_DISABLE_COPY(ScopeGuard) FRAMELESSHELPER_CLASS(ScopeGuard)
public: public:
ScopeGuard() ScopeGuard()

View File

@ -31,8 +31,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_CORE_API SysApiLoader : public QObject class FRAMELESSHELPER_CORE_API SysApiLoader : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(SysApiLoader)
Q_DISABLE_COPY_MOVE(SysApiLoader)
public: public:
Q_NODISCARD static SysApiLoader *instance(); Q_NODISCARD static SysApiLoader *instance();

View File

@ -32,22 +32,15 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class WindowBorderPainter; class WindowBorderPainter;
class FRAMELESSHELPER_CORE_API WindowBorderPainterPrivate : public QObject class FRAMELESSHELPER_CORE_API WindowBorderPainterPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(WindowBorderPainter)
Q_DECLARE_PUBLIC(WindowBorderPainter)
Q_DISABLE_COPY_MOVE(WindowBorderPainterPrivate)
public: public:
explicit WindowBorderPainterPrivate(WindowBorderPainter *q); explicit WindowBorderPainterPrivate(WindowBorderPainter *q);
~WindowBorderPainterPrivate() override; ~WindowBorderPainterPrivate() override;
Q_NODISCARD static WindowBorderPainterPrivate *get(WindowBorderPainter *q);
Q_NODISCARD static const WindowBorderPainterPrivate *get(const WindowBorderPainter *q);
WindowBorderPainter *q_ptr = nullptr;
std::optional<int> thickness = std::nullopt; std::optional<int> thickness = std::nullopt;
std::optional<Global::WindowEdges> edges = std::nullopt; std::optional<Global::WindowEdges> edges = std::nullopt;
std::optional<QColor> activeColor = std::nullopt; std::optional<QColor> activeColor = std::nullopt;

View File

@ -37,30 +37,22 @@ QT_END_NAMESPACE
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
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 WId windowId, 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 WId windowId, 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();
@ -100,31 +92,24 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId windowId);
[[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 WId windowId, 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 WId windowId, 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 WId windowId, 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 WId windowId, 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 WId windowId, 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 WId windowId, const bool scaled);
const bool scaled);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool maybeFixupQtInternals(const WId windowId); [[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 WId windowId);
const WId windowId, const SystemParameters *params);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool uninstallWindowProcHook(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool uninstallWindowProcHook(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool setAeroSnappingEnabled(const WId windowId, const bool enable); [[nodiscard]] FRAMELESSHELPER_CORE_API bool setAeroSnappingEnabled(const WId windowId, const bool enable);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool tryToEnableHighestDpiAwarenessLevel(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool tryToEnableHighestDpiAwarenessLevel();
@ -132,20 +117,17 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
[[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 WId windowId, const Global::WindowCornerStyle style);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool hideOriginalTitleBarElements [[nodiscard]] FRAMELESSHELPER_CORE_API bool hideOriginalTitleBarElements(const WId windowId, 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 WId windowId, const bool dark);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool enableNonClientAreaDpiScalingForWindow(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool enableNonClientAreaDpiScalingForWindow(const WId windowId);
[[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 WId windowId); [[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 WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool removeMicaWindow(const WId windowId);
[[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 WId windowId, const bool checkVisible, const bool checkTopLevel);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const WId windowId); [[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const WId windowId);
@ -156,8 +138,7 @@ 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,11 +147,8 @@ 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 WId windowId, 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 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 setWindowProperty
(const WId windowId, const xcb_atom_t prop, const xcb_atom_t type,
const void *data, const quint32 data_len, const uint8_t format);
FRAMELESSHELPER_CORE_API void clearWindowProperty(const WId windowId, const xcb_atom_t prop); 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();
@ -180,11 +158,9 @@ FRAMELESSHELPER_CORE_API void clearWindowProperty(const WId windowId, const xcb_
FRAMELESSHELPER_CORE_API void openSystemMenu(const WId windowId, const QPoint &globalPos); FRAMELESSHELPER_CORE_API void openSystemMenu(const WId windowId, 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 WId windowId, 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

View File

@ -31,13 +31,10 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class WindowBorderPainterPrivate; class WindowBorderPainterPrivate;
class FRAMELESSHELPER_CORE_API WindowBorderPainter : public QObject class FRAMELESSHELPER_CORE_API WindowBorderPainter : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(WindowBorderPainter)
Q_DISABLE_COPY_MOVE(WindowBorderPainter)
Q_DECLARE_PRIVATE(WindowBorderPainter)
Q_PROPERTY(int thickness READ thickness WRITE setThickness NOTIFY thicknessChanged FINAL) Q_PROPERTY(int thickness READ thickness WRITE setThickness NOTIFY thicknessChanged FINAL)
Q_PROPERTY(Global::WindowEdges edges READ edges WRITE setEdges NOTIFY edgesChanged FINAL) Q_PROPERTY(Global::WindowEdges edges READ edges WRITE setEdges NOTIFY edgesChanged FINAL)
@ -77,9 +74,6 @@ Q_SIGNALS:
void inactiveColorChanged(); void inactiveColorChanged();
void nativeBorderChanged(); void nativeBorderChanged();
void shouldRepaint(); void shouldRepaint();
private:
QScopedPointer<WindowBorderPainterPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -84,8 +84,7 @@ FRAMELESSHELPER_QUICK_API void FramelessHelperQuickRegisterTypes(QQmlEngine *);
class FRAMELESSHELPER_QUICK_API QuickGlobal : public QObject class FRAMELESSHELPER_QUICK_API QuickGlobal : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(QuickGlobal)
Q_DISABLE_COPY_MOVE(QuickGlobal)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(FramelessHelperConstants) QML_NAMED_ELEMENT(FramelessHelperConstants)
#endif #endif

View File

@ -36,20 +36,18 @@ class QuickMicaMaterial;
#if FRAMELESSHELPER_CONFIG(border_painter) #if FRAMELESSHELPER_CONFIG(border_painter)
class QuickWindowBorder; class QuickWindowBorder;
#endif #endif
class FramelessQuickHelperPrivate;
class FramelessQuickHelperPrivate;
class FRAMELESSHELPER_QUICK_API FramelessQuickHelper : public QQuickItem class FRAMELESSHELPER_QUICK_API FramelessQuickHelper : public QQuickItem
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessQuickHelper)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(FramelessHelper) QML_NAMED_ELEMENT(FramelessHelper)
#endif #endif
#ifdef QML_ATTACHED #ifdef QML_ATTACHED
QML_ATTACHED(FramelessQuickHelper) QML_ATTACHED(FramelessQuickHelper)
#endif #endif
Q_DECLARE_PRIVATE(FramelessQuickHelper)
Q_DISABLE_COPY_MOVE(FramelessQuickHelper)
Q_PROPERTY(QQuickItem* titleBarItem READ titleBarItem WRITE setTitleBarItem NOTIFY titleBarItemChanged FINAL) Q_PROPERTY(QQuickItem* titleBarItem READ titleBarItem WRITE setTitleBarItem NOTIFY titleBarItemChanged FINAL)
Q_PROPERTY(bool windowFixedSize READ isWindowFixedSize WRITE setWindowFixedSize NOTIFY windowFixedSizeChanged FINAL) Q_PROPERTY(bool windowFixedSize READ isWindowFixedSize WRITE setWindowFixedSize NOTIFY windowFixedSizeChanged FINAL)
Q_PROPERTY(bool blurBehindWindowEnabled READ isBlurBehindWindowEnabled WRITE setBlurBehindWindowEnabled NOTIFY blurBehindWindowEnabledChanged FINAL) Q_PROPERTY(bool blurBehindWindowEnabled READ isBlurBehindWindowEnabled WRITE setBlurBehindWindowEnabled NOTIFY blurBehindWindowEnabledChanged FINAL)
@ -109,9 +107,6 @@ Q_SIGNALS:
void blurBehindWindowEnabledChanged(); void blurBehindWindowEnabledChanged();
void windowChanged2(); void windowChanged2();
void ready(); void ready();
private:
QScopedPointer<FramelessQuickHelperPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -36,8 +36,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_QUICK_API FramelessQuickUtils : public QObject, public QQmlParserStatus class FRAMELESSHELPER_QUICK_API FramelessQuickUtils : public QObject, public QQmlParserStatus
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(FramelessQuickUtils)
Q_DISABLE_COPY_MOVE(FramelessQuickUtils)
Q_INTERFACES(QQmlParserStatus) Q_INTERFACES(QQmlParserStatus)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(FramelessUtils) QML_NAMED_ELEMENT(FramelessUtils)

View File

@ -33,16 +33,13 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessQuickApplicationWindowPrivate; class FramelessQuickApplicationWindowPrivate;
class FRAMELESSHELPER_QUICK_API FramelessQuickApplicationWindow : public QQuickApplicationWindow class FRAMELESSHELPER_QUICK_API FramelessQuickApplicationWindow : public QQuickApplicationWindow
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessQuickApplicationWindow)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(FramelessApplicationWindow) QML_NAMED_ELEMENT(FramelessApplicationWindow)
#endif #endif
Q_DECLARE_PRIVATE(FramelessQuickApplicationWindow)
Q_DISABLE_COPY_MOVE(FramelessQuickApplicationWindow)
Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL) Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL)
Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL) Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL)
Q_PROPERTY(bool minimized READ isMinimized NOTIFY minimizedChanged FINAL) Q_PROPERTY(bool minimized READ isMinimized NOTIFY minimizedChanged FINAL)
@ -77,9 +74,6 @@ Q_SIGNALS:
void maximizedChanged(); void maximizedChanged();
void zoomedChanged(); void zoomedChanged();
void fullScreenChanged(); void fullScreenChanged();
private:
QScopedPointer<FramelessQuickApplicationWindowPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -35,23 +35,17 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
#if FRAMELESSHELPER_CONFIG(border_painter) #if FRAMELESSHELPER_CONFIG(border_painter)
class QuickWindowBorder; class QuickWindowBorder;
#endif #endif
class FramelessQuickApplicationWindow;
class FramelessQuickApplicationWindow;
class FRAMELESSHELPER_QUICK_API FramelessQuickApplicationWindowPrivate : public QObject class FRAMELESSHELPER_QUICK_API FramelessQuickApplicationWindowPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessQuickApplicationWindow)
Q_DECLARE_PUBLIC(FramelessQuickApplicationWindow)
Q_DISABLE_COPY_MOVE(FramelessQuickApplicationWindowPrivate)
public: public:
explicit FramelessQuickApplicationWindowPrivate(FramelessQuickApplicationWindow *q); explicit FramelessQuickApplicationWindowPrivate(FramelessQuickApplicationWindow *q);
~FramelessQuickApplicationWindowPrivate() override; ~FramelessQuickApplicationWindowPrivate() override;
Q_NODISCARD static FramelessQuickApplicationWindowPrivate *get(FramelessQuickApplicationWindow *pub);
Q_NODISCARD static const FramelessQuickApplicationWindowPrivate *get(const FramelessQuickApplicationWindow *pub);
FramelessQuickApplicationWindow *q_ptr = nullptr;
QQuickWindow::Visibility savedVisibility = QQuickWindow::Windowed; QQuickWindow::Visibility savedVisibility = QQuickWindow::Windowed;
#if FRAMELESSHELPER_CONFIG(border_painter) #if FRAMELESSHELPER_CONFIG(border_painter)
QuickWindowBorder *windowBorder = nullptr; QuickWindowBorder *windowBorder = nullptr;

View File

@ -39,23 +39,17 @@ class QuickMicaMaterial;
#if FRAMELESSHELPER_CONFIG(border_painter) #if FRAMELESSHELPER_CONFIG(border_painter)
class QuickWindowBorder; class QuickWindowBorder;
#endif #endif
class FramelessQuickHelper;
struct FramelessQuickHelperData;
class FramelessQuickHelper;
class FRAMELESSHELPER_QUICK_API FramelessQuickHelperPrivate : public QObject class FRAMELESSHELPER_QUICK_API FramelessQuickHelperPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessQuickHelper)
Q_DECLARE_PUBLIC(FramelessQuickHelper)
Q_DISABLE_COPY_MOVE(FramelessQuickHelperPrivate)
public: public:
explicit FramelessQuickHelperPrivate(FramelessQuickHelper *q); explicit FramelessQuickHelperPrivate(FramelessQuickHelper *q);
~FramelessQuickHelperPrivate() override; ~FramelessQuickHelperPrivate() override;
Q_NODISCARD static FramelessQuickHelperPrivate *get(FramelessQuickHelper *pub);
Q_NODISCARD static const FramelessQuickHelperPrivate *get(const FramelessQuickHelper *pub);
void attach(); void attach();
void detach(); void detach();
@ -83,11 +77,8 @@ public:
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const; Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const; Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const;
void setSystemButtonState(const QuickGlobal::SystemButtonType button, const QuickGlobal::ButtonState state); void setSystemButtonState(const QuickGlobal::SystemButtonType button, const QuickGlobal::ButtonState state);
Q_NODISCARD const FramelessQuickHelperData *getWindowData() const;
Q_NODISCARD FramelessQuickHelperData *getWindowDataMutable() const;
void rebindWindow(); void rebindWindow();
FramelessQuickHelper *q_ptr = nullptr;
QColor savedWindowBackgroundColor = {}; QColor savedWindowBackgroundColor = {};
bool blurBehindWindowEnabled = false; bool blurBehindWindowEnabled = false;
std::optional<bool> extendIntoTitleBar = std::nullopt; std::optional<bool> extendIntoTitleBar = std::nullopt;

View File

@ -33,16 +33,13 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessQuickWindowPrivate; class FramelessQuickWindowPrivate;
class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindowQmlImpl class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindowQmlImpl
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessQuickWindow)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(FramelessWindow) QML_NAMED_ELEMENT(FramelessWindow)
#endif #endif
Q_DECLARE_PRIVATE(FramelessQuickWindow)
Q_DISABLE_COPY_MOVE(FramelessQuickWindow)
Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL) Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL)
Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL) Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL)
Q_PROPERTY(bool minimized READ isMinimized NOTIFY minimizedChanged FINAL) Q_PROPERTY(bool minimized READ isMinimized NOTIFY minimizedChanged FINAL)
@ -77,9 +74,6 @@ Q_SIGNALS:
void maximizedChanged(); void maximizedChanged();
void zoomedChanged(); void zoomedChanged();
void fullScreenChanged(); void fullScreenChanged();
private:
QScopedPointer<FramelessQuickWindowPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -35,23 +35,17 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
#if FRAMELESSHELPER_CONFIG(border_painter) #if FRAMELESSHELPER_CONFIG(border_painter)
class QuickWindowBorder; class QuickWindowBorder;
#endif #endif
class FramelessQuickWindow;
class FramelessQuickWindow;
class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessQuickWindow)
Q_DECLARE_PUBLIC(FramelessQuickWindow)
Q_DISABLE_COPY_MOVE(FramelessQuickWindowPrivate)
public: public:
explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q); explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q);
~FramelessQuickWindowPrivate() override; ~FramelessQuickWindowPrivate() override;
Q_NODISCARD static FramelessQuickWindowPrivate *get(FramelessQuickWindow *pub);
Q_NODISCARD static const FramelessQuickWindowPrivate *get(const FramelessQuickWindow *pub);
FramelessQuickWindow *q_ptr = nullptr;
QQuickWindow::Visibility savedVisibility = QQuickWindow::Windowed; QQuickWindow::Visibility savedVisibility = QQuickWindow::Windowed;
#if FRAMELESSHELPER_CONFIG(border_painter) #if FRAMELESSHELPER_CONFIG(border_painter)
QuickWindowBorder *windowBorder = nullptr; QuickWindowBorder *windowBorder = nullptr;

View File

@ -33,11 +33,10 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_QUICK_API QuickImageItem : public QQuickPaintedItem class FRAMELESSHELPER_QUICK_API QuickImageItem : public QQuickPaintedItem
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(QuickImageItem)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(ImageItem) QML_NAMED_ELEMENT(ImageItem)
#endif #endif
Q_DISABLE_COPY_MOVE(QuickImageItem)
Q_PROPERTY(QVariant source READ source WRITE setSource NOTIFY sourceChanged FINAL) Q_PROPERTY(QVariant source READ source WRITE setSource NOTIFY sourceChanged FINAL)

View File

@ -31,27 +31,21 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class MicaMaterial; class MicaMaterial;
class QuickMicaMaterial;
class QuickMicaMaterial;
class FRAMELESSHELPER_QUICK_API QuickMicaMaterialPrivate : public QObject class FRAMELESSHELPER_QUICK_API QuickMicaMaterialPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(QuickMicaMaterial)
Q_DISABLE_COPY_MOVE(QuickMicaMaterialPrivate)
Q_DECLARE_PUBLIC(QuickMicaMaterial)
public: public:
explicit QuickMicaMaterialPrivate(QuickMicaMaterial *q); explicit QuickMicaMaterialPrivate(QuickMicaMaterial *q);
~QuickMicaMaterialPrivate() override; ~QuickMicaMaterialPrivate() override;
Q_NODISCARD static QuickMicaMaterialPrivate *get(QuickMicaMaterial *q);
Q_NODISCARD static const QuickMicaMaterialPrivate *get(const QuickMicaMaterial *q);
Q_SLOT void rebindWindow(); Q_SLOT void rebindWindow();
void initialize(); void initialize();
QuickMicaMaterial *q_ptr = nullptr;
QMetaObject::Connection rootWindowXChangedConnection = {}; QMetaObject::Connection rootWindowXChangedConnection = {};
QMetaObject::Connection rootWindowYChangedConnection = {}; QMetaObject::Connection rootWindowYChangedConnection = {};
QMetaObject::Connection rootWindowActiveChangedConnection = {}; QMetaObject::Connection rootWindowActiveChangedConnection = {};

View File

@ -40,11 +40,10 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_QUICK_API QuickStandardSystemButton : public QQuickButton class FRAMELESSHELPER_QUICK_API QuickStandardSystemButton : public QQuickButton
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(QuickStandardSystemButton)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(StandardSystemButton) QML_NAMED_ELEMENT(StandardSystemButton)
#endif #endif
Q_DISABLE_COPY_MOVE(QuickStandardSystemButton)
Q_PROPERTY(QuickGlobal::SystemButtonType buttonType READ buttonType WRITE setButtonType NOTIFY buttonTypeChanged FINAL) Q_PROPERTY(QuickGlobal::SystemButtonType buttonType READ buttonType WRITE setButtonType NOTIFY buttonTypeChanged FINAL)
Q_PROPERTY(QString glyph READ glyph WRITE setGlyph NOTIFY glyphChanged FINAL) Q_PROPERTY(QString glyph READ glyph WRITE setGlyph NOTIFY glyphChanged FINAL)
Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor NOTIFY hoverColorChanged FINAL) Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor NOTIFY hoverColorChanged FINAL)

View File

@ -46,11 +46,10 @@ class QuickImageItem;
class FRAMELESSHELPER_QUICK_API QuickStandardTitleBar : public QQuickRectangle class FRAMELESSHELPER_QUICK_API QuickStandardTitleBar : public QQuickRectangle
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(QuickStandardTitleBar)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(StandardTitleBar) QML_NAMED_ELEMENT(StandardTitleBar)
#endif // QML_NAMED_ELEMENT #endif // QML_NAMED_ELEMENT
Q_DISABLE_COPY_MOVE(QuickStandardTitleBar)
Q_PROPERTY(Qt::Alignment titleLabelAlignment READ titleLabelAlignment WRITE setTitleLabelAlignment NOTIFY titleLabelAlignmentChanged FINAL) Q_PROPERTY(Qt::Alignment titleLabelAlignment READ titleLabelAlignment WRITE setTitleLabelAlignment NOTIFY titleLabelAlignmentChanged FINAL)
Q_PROPERTY(QQuickLabel* titleLabel READ titleLabel CONSTANT FINAL) Q_PROPERTY(QQuickLabel* titleLabel READ titleLabel CONSTANT FINAL)
#if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button)) #if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))

View File

@ -30,29 +30,23 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class QuickWindowBorder;
class WindowBorderPainter; class WindowBorderPainter;
class QuickWindowBorder;
class FRAMELESSHELPER_QUICK_API QuickWindowBorderPrivate : public QObject class FRAMELESSHELPER_QUICK_API QuickWindowBorderPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(QuickWindowBorder)
Q_DISABLE_COPY_MOVE(QuickWindowBorderPrivate)
Q_DECLARE_PUBLIC(QuickWindowBorder)
public: public:
explicit QuickWindowBorderPrivate(QuickWindowBorder *q); explicit QuickWindowBorderPrivate(QuickWindowBorder *q);
~QuickWindowBorderPrivate() override; ~QuickWindowBorderPrivate() override;
Q_NODISCARD static QuickWindowBorderPrivate *get(QuickWindowBorder *q);
Q_NODISCARD static const QuickWindowBorderPrivate *get(const QuickWindowBorder *q);
Q_SLOT void update(); Q_SLOT void update();
void initialize(); void initialize();
void rebindWindow(); void rebindWindow();
QuickWindowBorder *q_ptr = nullptr;
WindowBorderPainter *borderPainter = nullptr; WindowBorderPainter *borderPainter = nullptr;
QMetaObject::Connection activeChangeConnection = {}; QMetaObject::Connection activeChangeConnection = {};
QMetaObject::Connection visibilityChangeConnection = {}; QMetaObject::Connection visibilityChangeConnection = {};

View File

@ -35,12 +35,11 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_QUICK_API QuickChromePalette : public ChromePalette, public QQmlParserStatus class FRAMELESSHELPER_QUICK_API QuickChromePalette : public ChromePalette, public QQmlParserStatus
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(QuickChromePalette)
Q_INTERFACES(QQmlParserStatus)
#ifdef QML_ANONYMOUS #ifdef QML_ANONYMOUS
QML_ANONYMOUS QML_ANONYMOUS
#endif #endif
Q_DISABLE_COPY_MOVE(QuickChromePalette)
Q_INTERFACES(QQmlParserStatus)
public: public:
explicit QuickChromePalette(QObject *parent = nullptr); explicit QuickChromePalette(QObject *parent = nullptr);

View File

@ -32,16 +32,13 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class QuickMicaMaterialPrivate; class QuickMicaMaterialPrivate;
class FRAMELESSHELPER_QUICK_API QuickMicaMaterial : public QQuickPaintedItem class FRAMELESSHELPER_QUICK_API QuickMicaMaterial : public QQuickPaintedItem
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(QuickMicaMaterial)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(MicaMaterial) QML_NAMED_ELEMENT(MicaMaterial)
#endif #endif
Q_DISABLE_COPY_MOVE(QuickMicaMaterial)
Q_DECLARE_PRIVATE(QuickMicaMaterial)
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged FINAL) Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged FINAL)
Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged FINAL) Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged FINAL)
@ -81,9 +78,6 @@ protected:
void itemChange(const ItemChange change, const ItemChangeData &value) override; void itemChange(const ItemChange change, const ItemChangeData &value) override;
void classBegin() override; void classBegin() override;
void componentComplete() override; void componentComplete() override;
private:
QScopedPointer<QuickMicaMaterialPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -32,16 +32,13 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class QuickWindowBorderPrivate; class QuickWindowBorderPrivate;
class FRAMELESSHELPER_QUICK_API QuickWindowBorder : public QQuickPaintedItem class FRAMELESSHELPER_QUICK_API QuickWindowBorder : public QQuickPaintedItem
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(QuickWindowBorder)
#ifdef QML_NAMED_ELEMENT #ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(WindowBorder) QML_NAMED_ELEMENT(WindowBorder)
#endif #endif
Q_DISABLE_COPY_MOVE(QuickWindowBorder)
Q_DECLARE_PRIVATE(QuickWindowBorder)
Q_PROPERTY(qreal thickness READ thickness WRITE setThickness NOTIFY thicknessChanged FINAL) Q_PROPERTY(qreal thickness READ thickness WRITE setThickness NOTIFY thicknessChanged FINAL)
Q_PROPERTY(QuickGlobal::WindowEdges edges READ edges WRITE setEdges NOTIFY edgesChanged FINAL) Q_PROPERTY(QuickGlobal::WindowEdges edges READ edges WRITE setEdges NOTIFY edgesChanged FINAL)
@ -86,9 +83,6 @@ Q_SIGNALS:
void activeColorChanged(); void activeColorChanged();
void inactiveColorChanged(); void inactiveColorChanged();
void nativeBorderChanged(); void nativeBorderChanged();
private:
QScopedPointer<QuickWindowBorderPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -32,20 +32,14 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessDialogPrivate; class FramelessDialogPrivate;
class FRAMELESSHELPER_WIDGETS_API FramelessDialog : public QDialog class FRAMELESSHELPER_WIDGETS_API FramelessDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessDialog)
Q_DECLARE_PRIVATE(FramelessDialog)
Q_DISABLE_COPY_MOVE(FramelessDialog)
public: public:
explicit FramelessDialog(QWidget *parent = nullptr); explicit FramelessDialog(QWidget *parent = nullptr);
~FramelessDialog() override; ~FramelessDialog() override;
private:
QScopedPointer<FramelessDialogPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -32,13 +32,10 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessMainWindowPrivate; class FramelessMainWindowPrivate;
class FRAMELESSHELPER_WIDGETS_API FramelessMainWindow : public QMainWindow class FRAMELESSHELPER_WIDGETS_API FramelessMainWindow : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessMainWindow)
Q_DECLARE_PRIVATE(FramelessMainWindow)
Q_DISABLE_COPY_MOVE(FramelessMainWindow)
Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL) Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL)
Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL) Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL)
Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL) Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL)
@ -58,9 +55,6 @@ Q_SIGNALS:
void hiddenChanged(); void hiddenChanged();
void normalChanged(); void normalChanged();
void zoomedChanged(); void zoomedChanged();
private:
QScopedPointer<FramelessMainWindowPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -32,13 +32,10 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessWidgetPrivate; class FramelessWidgetPrivate;
class FRAMELESSHELPER_WIDGETS_API FramelessWidget : public QWidget class FRAMELESSHELPER_WIDGETS_API FramelessWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessWidget)
Q_DECLARE_PRIVATE(FramelessWidget)
Q_DISABLE_COPY_MOVE(FramelessWidget)
Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL) Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL)
Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL) Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL)
Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL) Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL)
@ -58,9 +55,6 @@ Q_SIGNALS:
void hiddenChanged(); void hiddenChanged();
void normalChanged(); void normalChanged();
void zoomedChanged(); void zoomedChanged();
private:
QScopedPointer<FramelessWidgetPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -35,14 +35,12 @@ class MicaMaterial;
#if FRAMELESSHELPER_CONFIG(border_painter) #if FRAMELESSHELPER_CONFIG(border_painter)
class WindowBorderPainter; class WindowBorderPainter;
#endif #endif
class FramelessWidgetsHelperPrivate;
class FramelessWidgetsHelperPrivate;
class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelper : public QObject class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelper : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessWidgetsHelper)
Q_DECLARE_PRIVATE(FramelessWidgetsHelper)
Q_DISABLE_COPY_MOVE(FramelessWidgetsHelper)
Q_PROPERTY(QWidget* titleBarWidget READ titleBarWidget WRITE setTitleBarWidget NOTIFY titleBarWidgetChanged FINAL) Q_PROPERTY(QWidget* titleBarWidget READ titleBarWidget WRITE setTitleBarWidget NOTIFY titleBarWidgetChanged FINAL)
Q_PROPERTY(bool windowFixedSize READ isWindowFixedSize WRITE setWindowFixedSize NOTIFY windowFixedSizeChanged FINAL) Q_PROPERTY(bool windowFixedSize READ isWindowFixedSize WRITE setWindowFixedSize NOTIFY windowFixedSizeChanged FINAL)
Q_PROPERTY(bool blurBehindWindowEnabled READ isBlurBehindWindowEnabled WRITE setBlurBehindWindowEnabled NOTIFY blurBehindWindowEnabledChanged FINAL) Q_PROPERTY(bool blurBehindWindowEnabled READ isBlurBehindWindowEnabled WRITE setBlurBehindWindowEnabled NOTIFY blurBehindWindowEnabledChanged FINAL)
@ -96,9 +94,6 @@ Q_SIGNALS:
void blurBehindWindowEnabledChanged(); void blurBehindWindowEnabledChanged();
void windowChanged(); void windowChanged();
void ready(); void ready();
private:
QScopedPointer<FramelessWidgetsHelperPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -30,24 +30,18 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessDialog;
class WidgetsSharedHelper; class WidgetsSharedHelper;
class FramelessDialog;
class FRAMELESSHELPER_WIDGETS_API FramelessDialogPrivate : public QObject class FRAMELESSHELPER_WIDGETS_API FramelessDialogPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessDialog)
Q_DECLARE_PUBLIC(FramelessDialog)
Q_DISABLE_COPY_MOVE(FramelessDialogPrivate)
public: public:
explicit FramelessDialogPrivate(FramelessDialog *q); explicit FramelessDialogPrivate(FramelessDialog *q);
~FramelessDialogPrivate() override; ~FramelessDialogPrivate() override;
Q_NODISCARD static FramelessDialogPrivate *get(FramelessDialog *pub);
Q_NODISCARD static const FramelessDialogPrivate *get(const FramelessDialog *pub);
FramelessDialog *q_ptr = nullptr;
WidgetsSharedHelper *sharedHelper = nullptr; WidgetsSharedHelper *sharedHelper = nullptr;
}; };

View File

@ -30,24 +30,18 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessMainWindow;
class WidgetsSharedHelper; class WidgetsSharedHelper;
class FramelessMainWindow;
class FRAMELESSHELPER_WIDGETS_API FramelessMainWindowPrivate : public QObject class FRAMELESSHELPER_WIDGETS_API FramelessMainWindowPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessMainWindow)
Q_DECLARE_PUBLIC(FramelessMainWindow)
Q_DISABLE_COPY_MOVE(FramelessMainWindowPrivate)
public: public:
explicit FramelessMainWindowPrivate(FramelessMainWindow *q); explicit FramelessMainWindowPrivate(FramelessMainWindow *q);
~FramelessMainWindowPrivate() override; ~FramelessMainWindowPrivate() override;
Q_NODISCARD static FramelessMainWindowPrivate *get(FramelessMainWindow *pub);
Q_NODISCARD static const FramelessMainWindowPrivate *get(const FramelessMainWindow *pub);
FramelessMainWindow *q_ptr = nullptr;
Qt::WindowState savedWindowState = Qt::WindowNoState; Qt::WindowState savedWindowState = Qt::WindowNoState;
WidgetsSharedHelper *sharedHelper = nullptr; WidgetsSharedHelper *sharedHelper = nullptr;
}; };

View File

@ -30,24 +30,18 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessWidget;
class WidgetsSharedHelper; class WidgetsSharedHelper;
class FramelessWidget;
class FRAMELESSHELPER_WIDGETS_API FramelessWidgetPrivate : public QObject class FRAMELESSHELPER_WIDGETS_API FramelessWidgetPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessWidget)
Q_DECLARE_PUBLIC(FramelessWidget)
Q_DISABLE_COPY_MOVE(FramelessWidgetPrivate)
public: public:
explicit FramelessWidgetPrivate(FramelessWidget *q); explicit FramelessWidgetPrivate(FramelessWidget *q);
~FramelessWidgetPrivate() override; ~FramelessWidgetPrivate() override;
Q_NODISCARD static FramelessWidgetPrivate *get(FramelessWidget *pub);
Q_NODISCARD static const FramelessWidgetPrivate *get(const FramelessWidget *pub);
FramelessWidget *q_ptr = nullptr;
Qt::WindowState savedWindowState = Qt::WindowNoState; Qt::WindowState savedWindowState = Qt::WindowNoState;
WidgetsSharedHelper *sharedHelper = nullptr; WidgetsSharedHelper *sharedHelper = nullptr;
}; };

View File

@ -36,24 +36,18 @@ class MicaMaterial;
#if FRAMELESSHELPER_CONFIG(border_painter) #if FRAMELESSHELPER_CONFIG(border_painter)
class WindowBorderPainter; class WindowBorderPainter;
#endif #endif
class FramelessWidgetsHelper;
struct FramelessWidgetsHelperData;
class WidgetsSharedHelper; class WidgetsSharedHelper;
class FramelessWidgetsHelper;
class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelperPrivate : public QObject class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelperPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessWidgetsHelper)
Q_DECLARE_PUBLIC(FramelessWidgetsHelper)
Q_DISABLE_COPY_MOVE(FramelessWidgetsHelperPrivate)
public: public:
explicit FramelessWidgetsHelperPrivate(FramelessWidgetsHelper *q); explicit FramelessWidgetsHelperPrivate(FramelessWidgetsHelper *q);
~FramelessWidgetsHelperPrivate() override; ~FramelessWidgetsHelperPrivate() override;
Q_NODISCARD static FramelessWidgetsHelperPrivate *get(FramelessWidgetsHelper *pub);
Q_NODISCARD static const FramelessWidgetsHelperPrivate *get(const FramelessWidgetsHelper *pub);
void attach(); void attach();
void detach(); void detach();
@ -83,10 +77,7 @@ public:
Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const; Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const;
void setSystemButtonState(const Global::SystemButtonType button, const Global::ButtonState state); void setSystemButtonState(const Global::SystemButtonType button, const Global::ButtonState state);
Q_NODISCARD QWidget *findTopLevelWindow() const; Q_NODISCARD QWidget *findTopLevelWindow() const;
Q_NODISCARD const FramelessWidgetsHelperData *getWindowData() const;
Q_NODISCARD FramelessWidgetsHelperData *getWindowDataMutable() const;
FramelessWidgetsHelper *q_ptr = nullptr;
QColor savedWindowBackgroundColor = {}; QColor savedWindowBackgroundColor = {};
bool blurBehindWindowEnabled = false; bool blurBehindWindowEnabled = false;
QPointer<QWidget> window = nullptr; QPointer<QWidget> window = nullptr;

View File

@ -32,24 +32,17 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class StandardSystemButton; class StandardSystemButton;
class FRAMELESSHELPER_WIDGETS_API StandardSystemButtonPrivate : public QObject class FRAMELESSHELPER_WIDGETS_API StandardSystemButtonPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(StandardSystemButton)
Q_DECLARE_PUBLIC(StandardSystemButton)
Q_DISABLE_COPY_MOVE(StandardSystemButtonPrivate)
public: public:
explicit StandardSystemButtonPrivate(StandardSystemButton *q); explicit StandardSystemButtonPrivate(StandardSystemButton *q);
~StandardSystemButtonPrivate() override; ~StandardSystemButtonPrivate() override;
Q_NODISCARD static StandardSystemButtonPrivate *get(StandardSystemButton *pub);
Q_NODISCARD static const StandardSystemButtonPrivate *get(const StandardSystemButton *pub);
Q_NODISCARD static QSize getRecommendedButtonSize(); Q_NODISCARD static QSize getRecommendedButtonSize();
StandardSystemButton *q_ptr = nullptr;
Global::SystemButtonType buttonType = Global::SystemButtonType::Unknown; Global::SystemButtonType buttonType = Global::SystemButtonType::Unknown;
QString glyph = {}; QString glyph = {};
QColor hoverColor = {}; QColor hoverColor = {};

View File

@ -40,14 +40,12 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class StandardSystemButton; class StandardSystemButton;
#endif #endif
class ChromePalette; class ChromePalette;
class StandardTitleBar;
class StandardTitleBar;
class FRAMELESSHELPER_WIDGETS_API StandardTitleBarPrivate : public QObject class FRAMELESSHELPER_WIDGETS_API StandardTitleBarPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PRIVATE_QT_CLASS(StandardTitleBar)
Q_DECLARE_PUBLIC(StandardTitleBar)
Q_DISABLE_COPY_MOVE(StandardTitleBarPrivate)
public: public:
struct FontMetrics struct FontMetrics
@ -60,9 +58,6 @@ public:
explicit StandardTitleBarPrivate(StandardTitleBar *q); explicit StandardTitleBarPrivate(StandardTitleBar *q);
~StandardTitleBarPrivate() override; ~StandardTitleBarPrivate() override;
Q_NODISCARD static StandardTitleBarPrivate *get(StandardTitleBar *pub);
Q_NODISCARD static const StandardTitleBarPrivate *get(const StandardTitleBar *pub);
Q_NODISCARD QRect windowIconRect() const; Q_NODISCARD QRect windowIconRect() const;
Q_NODISCARD bool windowIconVisible_real() const; Q_NODISCARD bool windowIconVisible_real() const;
Q_NODISCARD bool isInTitleBarIconArea(const QPoint &pos) const; Q_NODISCARD bool isInTitleBarIconArea(const QPoint &pos) const;
@ -79,7 +74,6 @@ public:
void initialize(); void initialize();
StandardTitleBar *q_ptr = nullptr;
#if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button)) #if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))
StandardSystemButton *minimizeButton = nullptr; StandardSystemButton *minimizeButton = nullptr;
StandardSystemButton *maximizeButton = nullptr; StandardSystemButton *maximizeButton = nullptr;

View File

@ -39,8 +39,7 @@ class WindowBorderPainter;
class FRAMELESSHELPER_WIDGETS_API WidgetsSharedHelper : public QObject class FRAMELESSHELPER_WIDGETS_API WidgetsSharedHelper : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(WidgetsSharedHelper)
Q_DISABLE_COPY_MOVE(WidgetsSharedHelper)
#if FRAMELESSHELPER_CONFIG(mica_material) #if FRAMELESSHELPER_CONFIG(mica_material)
Q_PROPERTY(bool micaEnabled READ isMicaEnabled WRITE setMicaEnabled NOTIFY micaEnabledChanged FINAL) Q_PROPERTY(bool micaEnabled READ isMicaEnabled WRITE setMicaEnabled NOTIFY micaEnabledChanged FINAL)
#endif #endif

View File

@ -32,13 +32,10 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class StandardSystemButtonPrivate; class StandardSystemButtonPrivate;
class FRAMELESSHELPER_WIDGETS_API StandardSystemButton : public QPushButton class FRAMELESSHELPER_WIDGETS_API StandardSystemButton : public QPushButton
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(StandardSystemButton)
Q_DECLARE_PRIVATE(StandardSystemButton)
Q_DISABLE_COPY_MOVE(StandardSystemButton)
Q_PROPERTY(Global::SystemButtonType buttonType READ buttonType WRITE setButtonType NOTIFY buttonTypeChanged FINAL) Q_PROPERTY(Global::SystemButtonType buttonType READ buttonType WRITE setButtonType NOTIFY buttonTypeChanged FINAL)
Q_PROPERTY(QString glyph READ glyph WRITE setGlyph NOTIFY glyphChanged FINAL) Q_PROPERTY(QString glyph READ glyph WRITE setGlyph NOTIFY glyphChanged FINAL)
Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor NOTIFY hoverColorChanged FINAL) Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor NOTIFY hoverColorChanged FINAL)
@ -89,9 +86,6 @@ Q_SIGNALS:
void inactiveForegroundColorChanged(); void inactiveForegroundColorChanged();
void activeChanged(); void activeChanged();
void glyphSizeChanged(); void glyphSizeChanged();
private:
QScopedPointer<StandardSystemButtonPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -37,13 +37,10 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class StandardTitleBarPrivate; class StandardTitleBarPrivate;
class FRAMELESSHELPER_WIDGETS_API StandardTitleBar : public QWidget class FRAMELESSHELPER_WIDGETS_API StandardTitleBar : public QWidget
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_PUBLIC_QT_CLASS(StandardTitleBar)
Q_DECLARE_PRIVATE(StandardTitleBar)
Q_DISABLE_COPY_MOVE(StandardTitleBar)
Q_PROPERTY(Qt::Alignment titleLabelAlignment READ titleLabelAlignment WRITE setTitleLabelAlignment NOTIFY titleLabelAlignmentChanged FINAL) Q_PROPERTY(Qt::Alignment titleLabelAlignment READ titleLabelAlignment WRITE setTitleLabelAlignment NOTIFY titleLabelAlignmentChanged FINAL)
#if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button)) #if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))
Q_PROPERTY(StandardSystemButton* minimizeButton READ minimizeButton CONSTANT FINAL) Q_PROPERTY(StandardSystemButton* minimizeButton READ minimizeButton CONSTANT FINAL)
@ -104,9 +101,6 @@ Q_SIGNALS:
void windowIconSizeChanged(); void windowIconSizeChanged();
void windowIconVisibleChanged(); void windowIconVisibleChanged();
void titleFontChanged(); void titleFontChanged();
private:
QScopedPointer<StandardTitleBarPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

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)
@ -158,7 +159,7 @@ if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
COPYRIGHT "MIT License" COPYRIGHT "MIT License"
ORIGINAL_FILENAME "${SUB_MODULE_FULL_NAME}.dll" ORIGINAL_FILENAME "${SUB_MODULE_FULL_NAME}.dll"
PRODUCT "${PROJECT_NAME}" PRODUCT "${PROJECT_NAME}"
COMMENTS "Built from commit ${PROJECT_VERSION_COMMIT} on ${PROJECT_COMPILE_DATETIME} (UTC)." COMMENTS "Who don't love Raiden Shogun ?"
LIBRARY LIBRARY
) )
endif() endif()

View File

@ -85,14 +85,14 @@ Q_GLOBAL_STATIC(FramelessConfigData, g_framelessConfigData)
static inline void warnInappropriateOptions() static inline void warnInappropriateOptions()
{ {
const FramelessConfig * const cfg = FramelessConfig::instance(); const FramelessConfig * const cfg = FramelessConfig::instance();
if (cfg->isSet(Option::UseCrossPlatformQtImplementation)) {
WARNING << "Option::UseCrossPlatformQtImplementation is deprecated and has no effect now. It will be removed in a future version.";
}
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
if (cfg->isSet(Option::DisableWindowsSnapLayout)) { if (cfg->isSet(Option::DisableWindowsSnapLayout)) {
WARNING << "Option::DisableWindowsSnapLayout is deprecated and will removed in a future version. It has not effect now."; WARNING << "Option::DisableWindowsSnapLayout is deprecated and has no effect now. It will be removed in a future version.";
} }
#else #else
if (cfg->isSet(Option::UseCrossPlatformQtImplementation)) {
WARNING << "Option::UseCrossPlatformQtImplementation is default on non-Windows platforms.";
}
if (cfg->isSet(Option::ForceHideWindowFrameBorder)) { if (cfg->isSet(Option::ForceHideWindowFrameBorder)) {
WARNING << "Option::ForceHideWindowFrameBorder is only available on Windows."; WARNING << "Option::ForceHideWindowFrameBorder is only available on Windows.";
} }

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,40 +52,80 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
struct FramelessQtHelperData struct FramelessDataQt : public FramelessData
{ {
SystemParameters params = {}; FramelessHelperQt *framelessHelperImpl = nullptr;
FramelessHelperQt *eventFilter = nullptr;
bool cursorShapeChanged = false; bool cursorShapeChanged = false;
bool leftButtonPressed = false; bool leftButtonPressed = false;
FramelessDataQt();
~FramelessDataQt() override;
};
using FramelessDataQtPtr = std::shared_ptr<FramelessDataQt>;
[[nodiscard]] static inline FramelessDataQtPtr tryGetData(const QObject *window)
{
Q_ASSERT(window);
if (!window) {
return nullptr;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data) {
return nullptr;
}
return std::dynamic_pointer_cast<FramelessDataQt>(data);
}
class FramelessHelperQtPrivate
{
FRAMELESSHELPER_PRIVATE_CLASS(FramelessHelperQt)
public:
explicit FramelessHelperQtPrivate(FramelessHelperQt *q);
~FramelessHelperQtPrivate();
const QObject *window = nullptr;
}; };
using FramelessQtHelperInternal = QHash<WId, FramelessQtHelperData>; FramelessDataQt::FramelessDataQt() = default;
Q_GLOBAL_STATIC(FramelessQtHelperInternal, g_framelessQtHelperData) FramelessDataQt::~FramelessDataQt() = default;
FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent) {} [[nodiscard]] FramelessDataPtr FramelessData::create()
{
return std::make_shared<FramelessDataQt>();
}
FramelessHelperQtPrivate::FramelessHelperQtPrivate(FramelessHelperQt *q) : q_ptr(q)
{
Q_ASSERT(q_ptr);
}
FramelessHelperQtPrivate::~FramelessHelperQtPrivate() = default;
FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent), d_ptr(new FramelessHelperQtPrivate(this))
{
}
FramelessHelperQt::~FramelessHelperQt() = default; FramelessHelperQt::~FramelessHelperQt() = default;
void FramelessHelperQt::addWindow(FramelessParamsConst params) void FramelessHelperQt::addWindow(const QObject *window)
{ {
Q_ASSERT(params); Q_ASSERT(window);
if (!params) { if (!window) {
return; return;
} }
const WId windowId = params->getWindowId(); const FramelessDataQtPtr data = tryGetData(window);
const auto it = g_framelessQtHelperData()->constFind(windowId); if (!data || data->frameless || !data->callbacks) {
if (it != g_framelessQtHelperData()->constEnd()) {
return; return;
} }
FramelessQtHelperData data = {}; QWindow *qWindow = data->callbacks->getWindowHandle();
data.params = *params; Q_ASSERT(qWindow);
QWindow *window = params->getWindowHandle(); if (!qWindow) {
// Give it a parent so that it can be automatically deleted by Qt. return;
data.eventFilter = new FramelessHelperQt(window); }
g_framelessQtHelperData()->insert(windowId, data); data->frameless = true;
const auto shouldApplyFramelessFlag = []() -> bool { static const auto shouldApplyFramelessFlag = []() -> bool {
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
return false; return false;
#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) #elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
@ -92,35 +135,47 @@ void FramelessHelperQt::addWindow(FramelessParamsConst params)
#endif // Q_OS_MACOS #endif // Q_OS_MACOS
}(); }();
#if (defined(Q_OS_MACOS) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))) #if (defined(Q_OS_MACOS) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)))
window->setProperty("_q_mac_wantsLayer", 1); qWindow->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(data->callbacks->getWindowId(), true);
#elif defined(Q_OS_MACOS) #elif defined(Q_OS_MACOS)
Utils::setSystemTitleBarVisible(windowId, false); Utils::setSystemTitleBarVisible(data->callbacks->getWindowId(), false);
#endif // Q_OS_LINUX #endif // Q_OS_LINUX
} }
window->installEventFilter(data.eventFilter); if (!data->framelessHelperImpl) {
data->framelessHelperImpl = new FramelessHelperQt(qWindow);
data->framelessHelperImpl->d_func()->window = window;
qWindow->installEventFilter(data->framelessHelperImpl);
}
FramelessHelperEnableThemeAware(); FramelessHelperEnableThemeAware();
} }
void FramelessHelperQt::removeWindow(const WId windowId) void FramelessHelperQt::removeWindow(const QObject *window)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
if (!windowId) { if (!window) {
return; return;
} }
const auto it = g_framelessQtHelperData()->constFind(windowId); const FramelessDataQtPtr data = tryGetData(window);
if (it == g_framelessQtHelperData()->constEnd()) { if (!data || !data->frameless || !data->callbacks) {
return; return;
} }
g_framelessQtHelperData()->erase(it); if (data->framelessHelperImpl) {
QWindow *qWindow = data->callbacks->getWindowHandle();
Q_ASSERT(qWindow);
if (qWindow) {
qWindow->removeEventFilter(data->framelessHelperImpl);
delete data->framelessHelperImpl;
data->framelessHelperImpl = nullptr;
}
}
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
Utils::removeWindowProxy(windowId); Utils::removeWindowProxy(data->callbacks->getWindowId());
#endif #endif // Q_OS_MACOS
} }
bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
@ -131,24 +186,22 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
return false; return false;
} }
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0))
// First detect whether we got a theme change event or not, if so,
// inform the user the system theme has changed.
if (Utils::isThemeChangeEvent(event)) { if (Utils::isThemeChangeEvent(event)) {
// Sometimes the FramelessManager instance may be destroyed already. // Sometimes the FramelessManager instance may be destroyed already.
if (FramelessManager * const manager = FramelessManager::instance()) { if (FramelessManager *manager = FramelessManager::instance()) {
if (FramelessManagerPrivate * const managerPriv = FramelessManagerPrivate::get(manager)) { if (FramelessManagerPrivate *managerPriv = FramelessManagerPrivate::get(manager)) {
managerPriv->notifySystemThemeHasChangedOrNot(); managerPriv->notifySystemThemeHasChangedOrNot();
} }
} }
return QObject::eventFilter(object, event); return false;
} }
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0))
// We are only interested in events that are dispatched to top level windows. Q_D(FramelessHelperQt);
if (!object->isWindowType()) { if (!d->window || !object->isWindowType()) {
return QObject::eventFilter(object, event); return false;
} }
const QEvent::Type type = event->type(); const QEvent::Type type = event->type();
// We are only interested in some specific mouse events (plus DPR change event). // We are only interested in some specific mouse events (plus the DPR change event).
if ((type != QEvent::MouseButtonPress) && (type != QEvent::MouseButtonRelease) if ((type != QEvent::MouseButtonPress) && (type != QEvent::MouseButtonRelease)
&& (type != QEvent::MouseButtonDblClick) && (type != QEvent::MouseMove) && (type != QEvent::MouseButtonDblClick) && (type != QEvent::MouseMove)
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
@ -157,25 +210,22 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
&& (type != QEvent::ScreenChangeInternal) // Qt's internal event to notify screen change and DPR change. && (type != QEvent::ScreenChangeInternal) // Qt's internal event to notify screen change and DPR change.
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) #endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
) { ) {
return QObject::eventFilter(object, event); return false;
} }
const auto window = qobject_cast<QWindow *>(object); const FramelessDataQtPtr data = tryGetData(d->window);
const WId windowId = window->winId(); if (!data || !data->frameless || !data->callbacks) {
const auto it = g_framelessQtHelperData()->find(windowId); return false;
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 false;
} }
const auto qWindow = qobject_cast<QWindow *>(object);
const auto mouseEvent = static_cast<QMouseEvent *>(event); const auto mouseEvent = static_cast<QMouseEvent *>(event);
const Qt::MouseButton button = mouseEvent->button(); const Qt::MouseButton button = mouseEvent->button();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
@ -185,64 +235,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(qWindow, scenePos);
if (edges != Qt::Edges{}) { if (edges != Qt::Edges{}) {
std::ignore = Utils::startSystemResize(window, edges, globalPos); std::ignore = Utils::startSystemResize(qWindow, 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(qWindow, 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(qWindow, globalPos);
event->accept(); event->accept();
return true; return true;
} }
@ -251,7 +300,9 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
default: default:
break; break;
} }
return QObject::eventFilter(object, event); return false;
} }
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"
@ -60,7 +62,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
static constexpr const auto kMessageTag = WPARAM(2546789017); static constexpr const auto kMessageTag = WPARAM(0x97CCEA99);
FRAMELESSHELPER_STRING_CONSTANT(MonitorFromWindow) FRAMELESSHELPER_STRING_CONSTANT(MonitorFromWindow)
FRAMELESSHELPER_STRING_CONSTANT(GetMonitorInfoW) FRAMELESSHELPER_STRING_CONSTANT(GetMonitorInfoW)
@ -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
@ -112,36 +113,39 @@ struct FramelessWin32HelperData
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
QRect restoreGeometry = {}; QRect restoreGeometry = {};
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
};
struct FramelessWin32HelperInternal FramelessDataWin();
~FramelessDataWin() override;
};
using FramelessDataWinPtr = std::shared_ptr<FramelessDataWin>;
FramelessDataWin::FramelessDataWin() = default;
FramelessDataWin::~FramelessDataWin() = default;
[[nodiscard]] FramelessDataPtr FramelessData::create()
{ {
std::unique_ptr<FramelessHelperWin> nativeEventFilter = nullptr; return std::make_shared<FramelessDataWin>();
QHash<WId, FramelessWin32HelperData> data = {}; }
[[nodiscard]] static inline FramelessDataWinPtr tryGetData(const QObject *window)
{
Q_ASSERT(window);
if (!window) {
return nullptr;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data) {
return nullptr;
}
return std::dynamic_pointer_cast<FramelessDataWin>(data);
}
struct FramelessHelperWinInternal
{
std::unique_ptr<FramelessHelperWin> eventFilter = nullptr;
}; };
Q_GLOBAL_STATIC(FramelessHelperWinInternal, g_internalData)
Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData)
[[nodiscard]] extern bool operator==(const POINT &lhs, const POINT &rhs) noexcept;
[[nodiscard]] extern bool operator!=(const POINT &lhs, const POINT &rhs) noexcept;
[[nodiscard]] extern bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept;
[[nodiscard]] extern bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept;
[[nodiscard]] extern bool operator==(const RECT &lhs, const RECT &rhs) noexcept;
[[nodiscard]] extern bool operator!=(const RECT &lhs, const RECT &rhs) noexcept;
[[nodiscard]] extern QPoint point2qpoint(const POINT &point);
[[nodiscard]] extern POINT qpoint2point(const QPoint &point);
[[nodiscard]] extern QSize size2qsize(const SIZE &size);
[[nodiscard]] extern SIZE qsize2size(const QSize &size);
[[nodiscard]] extern QRect rect2qrect(const RECT &rect);
[[nodiscard]] extern RECT qrect2rect(const QRect &qrect);
[[nodiscard]] extern QString hwnd2str(const WId windowId);
[[nodiscard]] extern QString hwnd2str(const HWND hwnd);
[[nodiscard]] extern std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd); [[nodiscard]] extern std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd);
@ -212,49 +216,48 @@ FramelessHelperWin::FramelessHelperWin() : QAbstractNativeEventFilter() {}
FramelessHelperWin::~FramelessHelperWin() = default; FramelessHelperWin::~FramelessHelperWin() = default;
void FramelessHelperWin::addWindow(FramelessParamsConst params) void FramelessHelperWin::addWindow(const QObject *window)
{ {
Q_ASSERT(params); Q_ASSERT(window);
if (!params) { if (!window) {
return; return;
} }
const WId windowId = params->getWindowId(); const FramelessDataWinPtr data = tryGetData(window);
const auto it = g_framelessWin32HelperData()->data.constFind(windowId); if (!data || data->frameless || !data->callbacks) {
if (it != g_framelessWin32HelperData()->data.constEnd()) {
return; return;
} }
FramelessWin32HelperData data = {}; QWindow *qWindow = data->callbacks->getWindowHandle();
data.params = *params; Q_ASSERT(qWindow);
data.dpi = {Utils::getWindowDpi(windowId, true), Utils::getWindowDpi(windowId, false)}; if (!qWindow) {
g_framelessWin32HelperData()->data.insert(windowId, data); return;
if (!g_framelessWin32HelperData()->nativeEventFilter) {
g_framelessWin32HelperData()->nativeEventFilter = std::make_unique<FramelessHelperWin>();
qApp->installNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get());
} }
DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data.dpi; data->frameless = true;
const QWindow *window = params->getWindowHandle(); data->dpi = Dpi{ Utils::getWindowDpi(data->windowId, true), Utils::getWindowDpi(data->windowId, false) };
DEBUG.noquote() << "The DPI of window" << hwnd2str(data->windowId) << "is" << data->dpi;
// 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(data->windowId);
#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
// geometry, it will also affect the final window geometry because QPA will // geometry, it will also affect the final window geometry because QPA will
// always take it into account when setting window size and position. // always take it into account when setting window size and position.
std::ignore = Utils::updateInternalWindowFrameMargins(const_cast<QWindow *>(window), true); std::ignore = Utils::updateInternalWindowFrameMargins(qWindow, 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(data->windowId, 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(data->windowId);
// 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(data->windowId);
#if 0 // Conflicts with our blur mode setting. #if 0 // Conflicts with our blur mode setting.
if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) { // If we are using 3D APIs (D3D, Vulkan, OpenGL, etc) to draw the window content,
std::ignore = Utils::updateFramebufferTransparency(windowId); // we need to setup the DWM rendering policy as well.
if (Utils::isWindowAccelerated(qWindow) && Utils::isWindowTransparent(qWindow)) {
std::ignore = Utils::updateFramebufferTransparency(data->windowId);
} }
#endif #endif
if (WindowsVersionHelper::isWin10RS1OrGreater()) { if (WindowsVersionHelper::isWin10RS1OrGreater()) {
@ -262,42 +265,33 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
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(data->windowId, dark);
} }
std::ignore = Utils::refreshWin32ThemeResources(windowId, dark); std::ignore = Utils::refreshWin32ThemeResources(data->windowId, dark);
if (WindowsVersionHelper::isWin11OrGreater()) { if (WindowsVersionHelper::isWin11OrGreater()) {
// DWM provides official API to adjust the window corner style, but only since Windows 11.
if (FramelessConfig::instance()->isSet(Option::WindowUseSquareCorners)) { if (FramelessConfig::instance()->isSet(Option::WindowUseSquareCorners)) {
std::ignore = Utils::setCornerStyleForWindow(windowId, WindowCornerStyle::Square); std::ignore = Utils::setCornerStyleForWindow(data->windowId, WindowCornerStyle::Square);
} }
} }
} }
} }
if (!g_internalData()->eventFilter) {
g_internalData()->eventFilter = std::make_unique<FramelessHelperWin>();
qApp->installNativeEventFilter(g_internalData()->eventFilter.get());
}
} }
void FramelessHelperWin::removeWindow(const WId windowId) void FramelessHelperWin::removeWindow(const QObject *window)
{ {
Q_ASSERT(windowId); Q_UNUSED(window);
if (!windowId) {
return;
}
const auto it = g_framelessWin32HelperData()->data.constFind(windowId);
if (it == g_framelessWin32HelperData()->data.constEnd()) {
return;
}
g_framelessWin32HelperData()->data.erase(it);
if (g_framelessWin32HelperData()->data.isEmpty()) {
if (g_framelessWin32HelperData()->nativeEventFilter) {
qApp->removeNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get());
g_framelessWin32HelperData()->nativeEventFilter.reset();
}
}
} }
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)
@ -319,15 +313,10 @@ 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);
// Let's be extra safe.
if (!Utils::isValidWindow(windowId, false, true)) {
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:
@ -340,19 +329,30 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break; break;
} }
const auto it = g_framelessWin32HelperData()->data.find(windowId); const auto windowId = reinterpret_cast<WId>(hWnd);
if (it == g_framelessWin32HelperData()->data.end()) { // Let's be extra safe.
if (!Utils::isValidWindow(windowId, false, true)) {
return false; return false;
} }
const FramelessWin32HelperData &data = it.value();
FramelessWin32HelperData &muData = it.value(); const QObject *window = FramelessManagerPrivate::getWindow(windowId);
const QWindow *window = data.params.getWindowHandle(); if (!window) {
return false;
}
const FramelessDataWinPtr data = tryGetData(window);
if (!data || !data->frameless || !data->callbacks) {
return false;
}
QWindow *qWindow = data->callbacks->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 = [windowId, &data](const bool ignoreWindowState) -> void {
if (!ignoreWindowState && !Utils::isWindowNoState(windowId)) { if (!ignoreWindowState && !Utils::isWindowNoState(windowId)) {
return; return;
} }
@ -361,10 +361,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
WARNING << "The calculated restore geometry is invalid."; WARNING << "The calculated restore geometry is invalid.";
return; return;
} }
if (Utils::isValidGeometry(data.restoreGeometry) && (data.restoreGeometry == rect)) { if (Utils::isValidGeometry(data->restoreGeometry) && (data->restoreGeometry == rect)) {
return; return;
} }
muData.restoreGeometry = rect; data->restoreGeometry = rect;
}; };
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
@ -372,6 +372,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const int myMsg = overrideMessage.value_or(uMsg); const int myMsg = overrideMessage.value_or(uMsg);
const auto wparam = [myMsg, wParam]() -> WPARAM { const auto wparam = [myMsg, wParam]() -> WPARAM {
if (myMsg == WM_NCMOUSELEAVE) { if (myMsg == WM_NCMOUSELEAVE) {
// wParam is always ignored in mouse leave messages, but here we
// give them a special tag to be able to distinguish which messages
// are sent by ourselves.
return kMessageTag; return kMessageTag;
} }
const quint64 keyState = Utils::getKeyState(); const quint64 keyState = Utils::getKeyState();
@ -383,6 +386,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}(); }();
const auto lparam = [myMsg, lParam, hWnd]() -> LPARAM { const auto lparam = [myMsg, lParam, hWnd]() -> LPARAM {
if (myMsg == WM_NCMOUSELEAVE) { if (myMsg == WM_NCMOUSELEAVE) {
// lParam is always ignored in mouse leave messages.
return 0; return 0;
} }
const auto screenPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; const auto screenPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
@ -439,7 +443,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
case WM_NCXBUTTONDBLCLK: case WM_NCXBUTTONDBLCLK:
SEND_MESSAGE(hWnd, WM_XBUTTONDBLCLK, wparam, lparam); SEND_MESSAGE(hWnd, WM_XBUTTONDBLCLK, wparam, lparam);
break; break;
#if 0 #if 0 // ### TODO: How to handle touch events?
case WM_NCPOINTERUPDATE: case WM_NCPOINTERUPDATE:
case WM_NCPOINTERDOWN: case WM_NCPOINTERDOWN:
case WM_NCPOINTERUP: case WM_NCPOINTERUP:
@ -465,28 +469,28 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// the reason above, and these superfluous mouse leave events cause Qt to think the // the reason above, and these superfluous mouse leave events cause Qt to think the
// mouse has left the control, and thus we actually lost the hover state. // mouse has left the control, and thus we actually lost the hover state.
// So we filter out these superfluous mouse leave events here to avoid this issue. // So we filter out these superfluous mouse leave events here to avoid this issue.
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint{ msg->pt.x, msg->pt.y }); const QPoint qtScenePos = Utils::fromNativeLocalPosition(qWindow, QPoint{ msg->pt.x, msg->pt.y });
SystemButtonType dummy = SystemButtonType::Unknown; SystemButtonType dummy = SystemButtonType::Unknown;
if (data.params.isInsideSystemButtons(qtScenePos, &dummy)) { if (data->callbacks->isInsideSystemButtons(qtScenePos, &dummy)) {
muData.mouseLeaveBlocked = true; data->mouseLeaveBlocked = true;
*result = FALSE; *result = FALSE;
return true; return true;
} }
} }
muData.mouseLeaveBlocked = false; data->mouseLeaveBlocked = false;
} }
switch (uMsg) { switch (uMsg) {
#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) // Qt has done this for us since 5.9.0 #if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) // Qt has done this for us since 5.9.0
case WM_NCCREATE: { case WM_NCCREATE:
// Enable automatic DPI scaling for the non-client area of the window, // Enable automatic DPI scaling for the non-client area of the window,
// such as the caption bar, the scrollbars, and the menu bar. We need // such as the caption bar, the scrollbars, and the menu bar. We need
// to do this explicitly and manually here (only inside WM_NCCREATE). // to do this explicitly and manually here (only inside WM_NCCREATE).
// If we are using the PMv2 DPI awareness mode, the non-client area // If we are using the PMv2 DPI awareness mode, the non-client area
// of the window will be scaled by the OS automatically, so there will // of the window will be scaled by the OS automatically, so there will
// be no need to do this in that case. // be no need to do this in that case.
Utils::enableNonClientAreaDpiScalingForWindow(windowId); std::ignore = Utils::enableNonClientAreaDpiScalingForWindow(windowId);
} break; break;
#endif #endif
case WM_NCCALCSIZE: { case WM_NCCALCSIZE: {
// Windows是根据这个消息的返回值来设置窗口的客户区窗口中真正显示的内容 // Windows是根据这个消息的返回值来设置窗口的客户区窗口中真正显示的内容
@ -811,8 +815,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// color, our homemade top border can almost have exactly the same // color, our homemade top border can almost have exactly the same
// appearance with the system's one. // appearance with the system's one.
const auto hitTestRecorder = qScopeGuard([&muData, &result](){ const auto hitTestRecorder = qScopeGuard([&data, &result](){
muData.lastHitTestResult = getHittedWindowPart(*result); data->lastHitTestResult = getHittedWindowPart(*result);
}); });
const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; const auto nativeGlobalPos = POINT{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
@ -830,9 +834,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const auto clientWidth = RECT_WIDTH(clientRect); const auto clientWidth = RECT_WIDTH(clientRect);
const auto clientHeight = RECT_HEIGHT(clientRect); const auto clientHeight = RECT_HEIGHT(clientRect);
const QPoint qtScenePos = Utils::fromNativeLocalPosition(window, QPoint(nativeLocalPos.x, nativeLocalPos.y)); const QPoint qtScenePos = Utils::fromNativeLocalPosition(qWindow, QPoint(nativeLocalPos.x, nativeLocalPos.y));
SystemButtonType sysButtonType = SystemButtonType::Unknown; SystemButtonType sysButtonType = SystemButtonType::Unknown;
if (data.params.isInsideSystemButtons(qtScenePos, &sysButtonType)) { if (data->callbacks->isInsideSystemButtons(qtScenePos, &sysButtonType)) {
// Even if the mouse is inside the chrome button area now, we should still allow the user // Even if the mouse is inside the chrome button area now, we should still allow the user
// to be able to resize the window with the top or right window border, this is also the // to be able to resize the window with the top or right window border, this is also the
// normal behavior of a native Win32 window. // normal behavior of a native Win32 window.
@ -881,10 +885,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const bool full = Utils::isFullScreen(windowId); const bool full = Utils::isFullScreen(windowId);
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
const bool isTop = (nativeLocalPos.y < frameSizeY); const bool isTop = (nativeLocalPos.y < frameSizeY);
const bool isTitleBar = data.params.isInsideTitleBarDraggableArea(qtScenePos); const bool isTitleBar = data->callbacks->isInsideTitleBarDraggableArea(qtScenePos);
const bool isFixedSize = data.params.isWindowFixedSize(); const bool isFixedSize = data->callbacks->isWindowFixedSize();
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();
if (dontToggleMaximize) { if (dontToggleMaximize) {
static bool once = false; static bool once = false;
@ -995,8 +999,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return true; return true;
} }
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
if ((data.lastHitTestResult != WindowPart::ChromeButton) && data.mouseLeaveBlocked) { if ((data->lastHitTestResult != WindowPart::ChromeButton) && data->mouseLeaveBlocked) {
muData.mouseLeaveBlocked = false; data->mouseLeaveBlocked = false;
std::ignore = requestForMouseLeaveMessage(hWnd, false); std::ignore = requestForMouseLeaveMessage(hWnd, false);
} }
break; break;
@ -1013,17 +1017,17 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
case WM_NCXBUTTONDOWN: case WM_NCXBUTTONDOWN:
case WM_NCXBUTTONUP: case WM_NCXBUTTONUP:
case WM_NCXBUTTONDBLCLK: case WM_NCXBUTTONDBLCLK:
#if 0 #if 0 // ### TODO: How to handle touch events?
case WM_NCPOINTERUPDATE: case WM_NCPOINTERUPDATE:
case WM_NCPOINTERDOWN: case WM_NCPOINTERDOWN:
case WM_NCPOINTERUP: case WM_NCPOINTERUP:
#endif #endif
case WM_NCMOUSEHOVER: { case WM_NCMOUSEHOVER: {
const WindowPart currentWindowPart = data.lastHitTestResult; const WindowPart currentWindowPart = data->lastHitTestResult;
if (uMsg == WM_NCMOUSEMOVE) { if (uMsg == WM_NCMOUSEMOVE) {
if (currentWindowPart != WindowPart::ChromeButton) { if (currentWindowPart != WindowPart::ChromeButton) {
std::ignore = data.params.resetQtGrabbedControl(); std::ignore = data->callbacks->resetQtGrabbedControl();
if (muData.mouseLeaveBlocked) { if (data->mouseLeaveBlocked) {
emulateClientAreaMessage(WM_NCMOUSELEAVE); emulateClientAreaMessage(WM_NCMOUSELEAVE);
} }
} }
@ -1034,32 +1038,38 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// If the mouse is entering the client area, there must be a WM_NCHITTEST setting // If the mouse is entering the client area, there must be a WM_NCHITTEST setting
// it to `Client` before the WM_NCMOUSELEAVE comes; // it to `Client` before the WM_NCMOUSELEAVE comes;
// If the mouse is leaving the window, current window part remains as `Outside`. // If the mouse is leaving the window, current window part remains as `Outside`.
muData.lastHitTestResult = WindowPart::Outside; data->lastHitTestResult = WindowPart::Outside;
} }
if (currentWindowPart == WindowPart::ChromeButton) { if (currentWindowPart == WindowPart::ChromeButton) {
emulateClientAreaMessage(); emulateClientAreaMessage();
if (uMsg == WM_NCMOUSEMOVE) { if (uMsg == WM_NCMOUSEMOVE) {
// ### FIXME FIXME FIXME
// ### FIXME: Calling DefWindowProc() here is really dangerous, investigate how to avoid doing this.
// ### FIXME FIXME FIXME
*result = ::DefWindowProcW(hWnd, WM_NCMOUSEMOVE, wParam, lParam); *result = ::DefWindowProcW(hWnd, WM_NCMOUSEMOVE, wParam, lParam);
} else { } else {
// According to MSDN, we should return non-zero for X button messages to indicate
// we have handled these messages (due to historical reasons), for all other messages
// we should return zero instead.
*result = (((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)) ? TRUE : FALSE); *result = (((uMsg >= WM_NCXBUTTONDOWN) && (uMsg <= WM_NCXBUTTONDBLCLK)) ? TRUE : FALSE);
} }
return true; return true;
} }
} break; } break;
case WM_NCMOUSELEAVE: { case WM_NCMOUSELEAVE: {
const WindowPart currentWindowPart = data.lastHitTestResult; const WindowPart currentWindowPart = data->lastHitTestResult;
if (currentWindowPart == WindowPart::ChromeButton) { if (currentWindowPart == WindowPart::ChromeButton) {
// If we press on the chrome button and move mouse, Windows will take the pressing area // If we press on the chrome button and move mouse, Windows will take the pressing area
// as HTCLIENT which maybe because of our former retransmission of WM_NCLBUTTONDOWN, as // as HTCLIENT which maybe because of our former retransmission of WM_NCLBUTTONDOWN, as
// a result, a WM_NCMOUSELEAVE will come immediately and a lot of WM_MOUSEMOVE will come // a result, a WM_NCMOUSELEAVE will come immediately and a lot of WM_MOUSEMOVE will come
// if we move the mouse, we should track the mouse in advance. // if we move the mouse, we should track the mouse in advance.
if (muData.mouseLeaveBlocked) { if (data->mouseLeaveBlocked) {
muData.mouseLeaveBlocked = false; data->mouseLeaveBlocked = false;
std::ignore = requestForMouseLeaveMessage(hWnd, false); std::ignore = requestForMouseLeaveMessage(hWnd, false);
} }
} else { } else {
if (data.mouseLeaveBlocked) { if (data->mouseLeaveBlocked) {
// The mouse is moving from the chrome button to other non-client area, we should // The mouse is moving from the chrome button to other non-client area, we should
// emulate a WM_MOUSELEAVE message to reset the button state. // emulate a WM_MOUSELEAVE message to reset the button state.
emulateClientAreaMessage(WM_NCMOUSELEAVE); emulateClientAreaMessage(WM_NCMOUSELEAVE);
@ -1071,7 +1081,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// the mouse leaves window from client area and enters window from non-client area, // the mouse leaves window from client area and enters window from non-client area,
// but it has no bad effect. // but it has no bad effect.
std::ignore = data.params.resetQtGrabbedControl(); std::ignore = data->callbacks->resetQtGrabbedControl();
} }
} }
} break; } break;
@ -1085,9 +1095,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// of the application a lot. // of the application a lot.
const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam); const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam);
const QRect suggestedFrameGeometry{ windowPos->x, windowPos->y, windowPos->cx, windowPos->cy }; const QRect suggestedFrameGeometry{ windowPos->x, windowPos->y, windowPos->cx, windowPos->cy };
const QMargins frameMargins = (Utils::getWindowSystemFrameMargins(windowId) + Utils::getWindowCustomFrameMargins(window)); const QMargins frameMargins = (Utils::getWindowSystemFrameMargins(windowId) + Utils::getWindowCustomFrameMargins(qWindow));
const QRect suggestedGeometry = (suggestedFrameGeometry - frameMargins); const QRect suggestedGeometry = (suggestedFrameGeometry - frameMargins);
if (Utils::toNativePixels(window, window->size()) != suggestedGeometry.size()) { if (Utils::toNativePixels(qWindow, qWindow->size()) != suggestedGeometry.size()) {
windowPos->flags |= SWP_NOCOPYBITS; windowPos->flags |= SWP_NOCOPYBITS;
} }
} break; } break;
@ -1106,7 +1116,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
} }
const auto newDpi = UINT(wParam); const auto newDpi = UINT(wParam);
const QSize oldSize = {RECT_WIDTH(clientRect), RECT_HEIGHT(clientRect)}; const QSize oldSize = {RECT_WIDTH(clientRect), RECT_HEIGHT(clientRect)};
const QSize newSize = Utils::rescaleSize(oldSize, data.dpi.x, newDpi); const QSize newSize = Utils::rescaleSize(oldSize, data->dpi.x, newDpi);
const auto suggestedSize = reinterpret_cast<LPSIZE>(lParam); const auto suggestedSize = reinterpret_cast<LPSIZE>(lParam);
suggestedSize->cx = newSize.width(); suggestedSize->cx = newSize.width();
suggestedSize->cy = newSize.height(); suggestedSize->cy = newSize.height();
@ -1127,7 +1137,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
} }
#endif // (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2)) #endif // (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
case WM_DPICHANGED: { case WM_DPICHANGED: {
const Dpi oldDpi = data.dpi; const Dpi oldDpi = data->dpi;
const Dpi newDpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))}; const Dpi newDpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))};
if (Q_UNLIKELY(newDpi == oldDpi)) { if (Q_UNLIKELY(newDpi == oldDpi)) {
WARNING << "Wrong WM_DPICHANGED received: same DPI."; WARNING << "Wrong WM_DPICHANGED received: same DPI.";
@ -1135,14 +1145,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
} }
DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd) DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd)
<< "is" << newDpi << "(was" << oldDpi << ")."; << "is" << newDpi << "(was" << oldDpi << ").";
muData.dpi = newDpi; data->dpi = newDpi;
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
if (Utils::isValidGeometry(data.restoreGeometry)) { if (Utils::isValidGeometry(data->restoreGeometry)) {
// Update the window size only. The position should not be changed. // Update the window size only. The position should not be changed.
muData.restoreGeometry.setSize(Utils::rescaleSize(data.restoreGeometry.size(), oldDpi.x, newDpi.x)); data->restoreGeometry.setSize(Utils::rescaleSize(data->restoreGeometry.size(), oldDpi.x, newDpi.x));
} }
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1)) #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
data.params.forceChildrenRepaint(500); data->callbacks->forceChildrenRepaint(500);
} break; } break;
case WM_DWMCOMPOSITIONCHANGED: case WM_DWMCOMPOSITIONCHANGED:
// Re-apply the custom window frame if recovered from the basic theme. // Re-apply the custom window frame if recovered from the basic theme.
@ -1157,7 +1167,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if (wParam != SIZE_MAXIMIZED) { if (wParam != SIZE_MAXIMIZED) {
break; break;
} }
if (!Utils::isValidGeometry(data.restoreGeometry)) { if (!Utils::isValidGeometry(data->restoreGeometry)) {
updateRestoreGeometry(true); updateRestoreGeometry(true);
break; break;
} }
@ -1169,11 +1179,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break; break;
} }
// The restore geometry is correct, no need to bother. // The restore geometry is correct, no need to bother.
if (rect2qrect(wp.rcNormalPosition) == data.restoreGeometry) { if (rect2qrect(wp.rcNormalPosition) == data->restoreGeometry) {
break; break;
} }
// OK, the restore geometry is wrong, let's correct it then :) // OK, the restore geometry is wrong, let's correct it then :)
wp.rcNormalPosition = qrect2rect(data.restoreGeometry); wp.rcNormalPosition = qrect2rect(data->restoreGeometry);
if (::SetWindowPlacement(hWnd, &wp) == FALSE) { if (::SetWindowPlacement(hWnd, &wp) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kSetWindowPlacement); WARNING << Utils::getSystemErrorMessage(kSetWindowPlacement);
} }
@ -1271,7 +1281,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
#if 0 // Conflicts with our blur mode setting. #if 0 // Conflicts with our blur mode setting.
if ((uMsg == WM_DWMCOMPOSITIONCHANGED) || (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED)) { if ((uMsg == WM_DWMCOMPOSITIONCHANGED) || (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED)) {
if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) { if (Utils::isWindowAccelerated(qWindow) && Utils::isWindowTransparent(qWindow)) {
std::ignore = Utils::updateFramebufferTransparency(windowId); std::ignore = Utils::updateFramebufferTransparency(windowId);
} }
} }
@ -1288,7 +1298,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
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 = [&data]() -> bool { const auto isWidget = [&data]() -> bool {
const auto widget = data.params.getWidgetHandle(); const auto widget = data->callbacks->getWidgetHandle();
return (widget && widget->isWidgetType()); return (widget && widget->isWidgetType());
}(); }();
if (!isWidget) { if (!isWidget) {
@ -1319,4 +1329,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

@ -114,6 +114,23 @@ using namespace Global;
static_assert(std::size(WindowsVersions) == (static_cast<int>(WindowsVersion::Latest) + 1)); static_assert(std::size(WindowsVersions) == (static_cast<int>(WindowsVersion::Latest) + 1));
#endif #endif
FramelessCallbacks::FramelessCallbacks() = default;
FramelessCallbacks::~FramelessCallbacks() = default;
FramelessCallbacksPtr FramelessCallbacks::create()
{
return std::make_shared<FramelessCallbacks>();
}
FramelessExtraData::FramelessExtraData() = default;
FramelessExtraData::~FramelessExtraData() = default;
FramelessData::FramelessData() = default;
FramelessData::~FramelessData() = default;
void FramelessHelperCoreInitialize() void FramelessHelperCoreInitialize()
{ {
static bool inited = false; static bool inited = false;

View File

@ -24,12 +24,20 @@
#include "framelessmanager.h" #include "framelessmanager.h"
#include "framelessmanager_p.h" #include "framelessmanager_p.h"
#include "framelesshelper_qt.h"
#include "framelessconfig_p.h"
#include "framelesshelpercore_global_p.h" #include "framelesshelpercore_global_p.h"
#if FRAMELESSHELPER_CONFIG(native_impl)
# ifdef Q_OS_WINDOWS
# include "framelesshelper_win.h"
# elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
# elif defined(Q_OS_MACOS)
# else
# endif
#else
# include "framelesshelper_qt.h"
#endif
#include "framelessconfig_p.h"
#include "utils.h" #include "utils.h"
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
# include "framelesshelper_win.h"
# include "winverhelper_p.h" # include "winverhelper_p.h"
#endif #endif
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
@ -37,6 +45,7 @@
#include <QtCore/qloggingcategory.h> #include <QtCore/qloggingcategory.h>
#include <QtGui/qfontdatabase.h> #include <QtGui/qfontdatabase.h>
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include <QtGui/qevent.h>
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
# include <QtGui/qguiapplication.h> # include <QtGui/qguiapplication.h>
# include <QtGui/qstylehints.h> # include <QtGui/qstylehints.h>
@ -59,12 +68,26 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
using FramelessManagerData = QList<WId>;
Q_GLOBAL_STATIC(FramelessManagerData, g_framelessManagerData)
static constexpr const int kEventDelayInterval = 1000; static constexpr const int kEventDelayInterval = 1000;
struct InternalData
{
FramelessDataHash dataMap = {};
QHash<WId, QObject *> windowMap = {};
InternalData();
~InternalData();
private:
FRAMELESSHELPER_CLASS(InternalData)
};
InternalData::InternalData() = default;
InternalData::~InternalData() = default;
Q_GLOBAL_STATIC(InternalData, g_internalData)
#if FRAMELESSHELPER_CONFIG(bundle_resource) #if FRAMELESSHELPER_CONFIG(bundle_resource)
[[nodiscard]] static inline QString iconFontFamilyName() [[nodiscard]] static inline QString iconFontFamilyName()
{ {
@ -83,16 +106,60 @@ static constexpr const int kEventDelayInterval = 1000;
} }
#endif #endif
[[nodiscard]] static inline bool usePureQtImplementation() class InternalEventFilter : public QObject
{ {
static const auto result = []() -> bool { Q_OBJECT
#ifdef Q_OS_WINDOWS FRAMELESSHELPER_QT_CLASS(InternalEventFilter)
return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
#else public:
return true; explicit InternalEventFilter(const QObject *window, QObject *parent = nullptr);
#endif ~InternalEventFilter() override;
}();
return result; protected:
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;
private:
const QObject *m_window = nullptr;
};
InternalEventFilter::InternalEventFilter(const QObject *window, QObject *parent) : QObject(parent), m_window(window)
{
Q_ASSERT(m_window);
Q_ASSERT(m_window->isWidgetType() || m_window->isWindowType());
}
InternalEventFilter::~InternalEventFilter() = default;
bool InternalEventFilter::eventFilter(QObject *object, QEvent *event)
{
Q_ASSERT(object);
Q_ASSERT(event);
Q_ASSERT(m_window);
if (!object || !event || !m_window || (object != m_window)) {
return false;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(m_window);
if (!data || !data->frameless || !data->callbacks) {
return false;
}
switch (event->type()) {
case QEvent::WinIdChange: {
const WId windowId = data->callbacks->getWindowId();
Q_ASSERT(windowId);
if (windowId) {
FramelessManagerPrivate::updateWindowId(m_window, windowId);
}
} break;
case QEvent::Close: {
const auto ce = static_cast<const QCloseEvent *>(event);
if (ce->isAccepted()) {
std::ignore = FramelessManager::instance()->removeWindow(m_window);
}
} break;
default:
break;
}
return false;
} }
FramelessManagerPrivate::FramelessManagerPrivate(FramelessManager *q) : QObject(q) FramelessManagerPrivate::FramelessManagerPrivate(FramelessManager *q) : QObject(q)
@ -133,7 +200,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 +296,80 @@ void FramelessManagerPrivate::doNotifyWallpaperHasChangedOrNot()
} }
} }
FramelessDataPtr FramelessManagerPrivate::getData(const QObject *window)
{
Q_ASSERT(window);
Q_ASSERT(window->isWidgetType() || window->isWindowType());
if (!window || !(window->isWidgetType() || window->isWindowType())) {
return nullptr;
}
return g_internalData()->dataMap.value(const_cast<QObject *>(window));
}
FramelessDataPtr FramelessManagerPrivate::createData(const QObject *window, const WId windowId)
{
Q_ASSERT(window);
Q_ASSERT(window->isWidgetType() || window->isWindowType());
Q_ASSERT(windowId);
if (!window || !(window->isWidgetType() || window->isWindowType()) || !windowId) {
return nullptr;
}
const auto win = const_cast<QObject *>(window);
auto it = g_internalData()->dataMap.find(win);
if (it == g_internalData()->dataMap.end()) {
FramelessDataPtr data = FramelessData::create();
data->window = win;
data->windowId = windowId;
it = g_internalData()->dataMap.insert(win, data);
g_internalData()->windowMap.insert(windowId, win);
}
return it.value();
}
WId FramelessManagerPrivate::getWindowId(const QObject *window)
{
Q_ASSERT(window);
Q_ASSERT(window->isWidgetType() || window->isWindowType());
if (!window || !(window->isWidgetType() || window->isWindowType())) {
return 0;
}
if (const FramelessDataPtr data = getData(window)) {
return data->windowId;
}
return 0;
}
QObject *FramelessManagerPrivate::getWindow(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return nullptr;
}
return g_internalData()->windowMap.value(windowId);
}
void FramelessManagerPrivate::updateWindowId(const QObject *window, const WId newWindowId)
{
Q_ASSERT(window);
Q_ASSERT(window->isWidgetType() || window->isWindowType());
Q_ASSERT(newWindowId);
if (!window || !(window->isWidgetType() || window->isWindowType()) || !newWindowId) {
return;
}
const auto win = const_cast<QObject *>(window);
const FramelessDataPtr data = g_internalData()->dataMap.value(win);
Q_ASSERT(data);
if (!data) {
return;
}
const WId oldWindowId = data->windowId;
data->windowId = newWindowId;
g_internalData()->windowMap.remove(oldWindowId);
g_internalData()->windowMap.insert(newWindowId, win);
data->frameless = false;
std::ignore = FramelessManager::instance()->addWindow(window, newWindowId);
}
bool FramelessManagerPrivate::isThemeOverrided() const bool FramelessManagerPrivate::isThemeOverrided() const
{ {
return (overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown); return (overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown);
@ -264,8 +405,8 @@ void FramelessManagerPrivate::initialize()
// We are doing some tricks in our Windows message handling code, so // We are doing some tricks in our Windows message handling code, so
// we don't use Qt's theme notifier on Windows. But for other platforms // we don't use Qt's theme notifier on Windows. But for other platforms
// we want to use as many Qt functionalities as possible. // we want to use as many Qt functionalities as possible.
#if ((QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) && !defined(Q_OS_WINDOWS)) #if ((QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) && !FRAMELESSHELPER_CONFIG(native_impl))
QStyleHints * const styleHints = QGuiApplication::styleHints(); QStyleHints *styleHints = QGuiApplication::styleHints();
Q_ASSERT(styleHints); Q_ASSERT(styleHints);
if (styleHints) { if (styleHints) {
connect(styleHints, &QStyleHints::colorSchemeChanged, this, [this](const Qt::ColorScheme colorScheme){ connect(styleHints, &QStyleHints::colorSchemeChanged, this, [this](const Qt::ColorScheme colorScheme){
@ -342,51 +483,81 @@ void FramelessManager::setOverrideTheme(const SystemTheme theme)
Q_EMIT systemThemeChanged(); Q_EMIT systemThemeChanged();
} }
void FramelessManager::addWindow(FramelessParamsConst params) bool FramelessManager::addWindow(const QObject *window, const WId windowId)
{ {
Q_ASSERT(params); Q_ASSERT(window);
if (!params) { Q_ASSERT(window->isWidgetType() || window->isWindowType());
return; Q_ASSERT(windowId);
if (!window || !(window->isWidgetType() || window->isWindowType()) || !windowId) {
return false;
} }
const WId windowId = params->getWindowId(); FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (g_framelessManagerData()->contains(windowId)) { if (data && data->frameless) {
return; return false;
} }
g_framelessManagerData()->append(windowId); if (!data) {
static const bool pureQt = usePureQtImplementation(); data = FramelessData::create();
if (pureQt) { data->window = const_cast<QObject *>(window);
FramelessHelperQt::addWindow(params); data->windowId = windowId;
g_internalData()->dataMap.insert(data->window, data);
g_internalData()->windowMap.insert(windowId, data->window);
} }
#ifdef Q_OS_WINDOWS #if FRAMELESSHELPER_CONFIG(native_impl)
if (!pureQt) { # ifdef Q_OS_WINDOWS
FramelessHelperWin::addWindow(params); std::ignore = Utils::installWindowProcHook(windowId);
} FramelessHelperWin::addWindow(window);
std::ignore = Utils::installWindowProcHook(windowId, params); # elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
# elif defined(Q_OS_MACOS)
# else
# endif
#else
FramelessHelperQt::addWindow(window);
#endif #endif
connect(params->getWindowHandle(), &QWindow::destroyed, FramelessManager::instance(), [this, windowId](){ removeWindow(windowId); }); if (!data->internalEventHandler) {
data->internalEventHandler = new InternalEventFilter(data->window, data->window);
data->window->installEventFilter(data->internalEventHandler);
}
return true;
} }
void FramelessManager::removeWindow(const WId windowId) bool FramelessManager::removeWindow(const QObject *window)
{ {
Q_ASSERT(windowId); Q_ASSERT(window);
if (!windowId) { if (!window) {
return; return false;
} }
if (!g_framelessManagerData()->contains(windowId)) { const auto it = g_internalData()->dataMap.constFind(const_cast<QObject *>(window));
return; if (it == g_internalData()->dataMap.constEnd()) {
return false;
} }
g_framelessManagerData()->removeAll(windowId); const FramelessDataPtr data = it.value();
static const bool pureQt = usePureQtImplementation(); Q_ASSERT(data);
if (pureQt) { Q_ASSERT(data->window);
FramelessHelperQt::removeWindow(windowId); Q_ASSERT(data->windowId);
if (!data || !data->window || !data->windowId) {
return false;
} }
#ifdef Q_OS_WINDOWS if (data->internalEventHandler) {
if (!pureQt) { data->window->removeEventFilter(data->internalEventHandler);
FramelessHelperWin::removeWindow(windowId); delete data->internalEventHandler;
data->internalEventHandler = nullptr;
} }
std::ignore = Utils::uninstallWindowProcHook(windowId); #if FRAMELESSHELPER_CONFIG(native_impl)
std::ignore = Utils::removeMicaWindow(windowId); # ifdef Q_OS_WINDOWS
FramelessHelperWin::removeWindow(window);
std::ignore = Utils::uninstallWindowProcHook(data->windowId);
# elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
# elif defined(Q_OS_MACOS)
# else
# endif
#else
FramelessHelperQt::removeWindow(window);
#endif #endif
g_internalData()->dataMap.erase(it);
g_internalData()->windowMap.remove(data->windowId);
return true;
} }
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE
#include "framelessmanager.moc"

View File

@ -62,11 +62,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
# define CRITICAL QT_NO_QDEBUG_MACRO() # define CRITICAL QT_NO_QDEBUG_MACRO()
#endif #endif
DECLARE_SIZE_COMPARE_OPERATORS(QSize, QSize)
DECLARE_SIZE_COMPARE_OPERATORS(QSizeF, QSizeF)
DECLARE_SIZE_COMPARE_OPERATORS(QSize, QSizeF)
DECLARE_SIZE_COMPARE_OPERATORS(QSizeF, QSize)
using namespace Global; using namespace Global;
[[maybe_unused]] static constexpr const QSize kMaximumPictureSize = { 1920, 1080 }; [[maybe_unused]] static constexpr const QSize kMaximumPictureSize = { 1920, 1080 };
@ -487,8 +482,7 @@ static inline void expblur(QImage &img, qreal radius, const bool improvedQuality
class WallpaperThread : public QThread class WallpaperThread : public QThread
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(WallpaperThread)
Q_DISABLE_COPY_MOVE(WallpaperThread)
public: public:
explicit WallpaperThread(QObject *parent = nullptr) : QThread(parent) {} explicit WallpaperThread(QObject *parent = nullptr) : QThread(parent) {}
@ -657,7 +651,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

@ -50,11 +50,11 @@ _GetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvD
Q_ASSERT(hWnd); Q_ASSERT(hWnd);
Q_ASSERT(pvData); Q_ASSERT(pvData);
if (!hWnd || !pvData) { if (!hWnd || !pvData) {
SetLastError(ERROR_INVALID_PARAMETER); ::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
if (!API_USER_AVAILABLE(GetWindowCompositionAttribute)) { if (!API_USER_AVAILABLE(GetWindowCompositionAttribute)) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return API_CALL_FUNCTION4(user32, GetWindowCompositionAttribute, hWnd, pvData); return API_CALL_FUNCTION4(user32, GetWindowCompositionAttribute, hWnd, pvData);
@ -66,11 +66,11 @@ _SetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvD
Q_ASSERT(hWnd); Q_ASSERT(hWnd);
Q_ASSERT(pvData); Q_ASSERT(pvData);
if (!hWnd || !pvData) { if (!hWnd || !pvData) {
SetLastError(ERROR_INVALID_PARAMETER); ::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
if (!API_USER_AVAILABLE(SetWindowCompositionAttribute)) { if (!API_USER_AVAILABLE(SetWindowCompositionAttribute)) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return API_CALL_FUNCTION4(user32, SetWindowCompositionAttribute, hWnd, pvData); return API_CALL_FUNCTION4(user32, SetWindowCompositionAttribute, hWnd, pvData);
@ -111,14 +111,14 @@ _ShouldAppsUseDarkMode(VOID)
{ {
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
static const auto pShouldAppsUseDarkMode static const auto pShouldAppsUseDarkMode
= reinterpret_cast<ShouldAppsUseDarkModePtr>( = reinterpret_cast<ShouldAppsUseDarkModePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(132))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(132)));
if (!pShouldAppsUseDarkMode) { if (!pShouldAppsUseDarkMode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pShouldAppsUseDarkMode(); return pShouldAppsUseDarkMode();
@ -129,19 +129,19 @@ _AllowDarkModeForWindow(const HWND hWnd, const BOOL bAllow)
{ {
Q_ASSERT(hWnd); Q_ASSERT(hWnd);
if (!hWnd) { if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER); ::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
static const auto pAllowDarkModeForWindow static const auto pAllowDarkModeForWindow
= reinterpret_cast<AllowDarkModeForWindowPtr>( = reinterpret_cast<AllowDarkModeForWindowPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(133))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(133)));
if (!pAllowDarkModeForWindow) { if (!pAllowDarkModeForWindow) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pAllowDarkModeForWindow(hWnd, bAllow); return pAllowDarkModeForWindow(hWnd, bAllow);
@ -152,14 +152,14 @@ _AllowDarkModeForApp(const BOOL bAllow)
{ {
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
static const auto pAllowDarkModeForApp static const auto pAllowDarkModeForApp
= reinterpret_cast<AllowDarkModeForAppPtr>( = reinterpret_cast<AllowDarkModeForAppPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135)));
if (!pAllowDarkModeForApp) { if (!pAllowDarkModeForApp) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pAllowDarkModeForApp(bAllow); return pAllowDarkModeForApp(bAllow);
@ -170,14 +170,14 @@ _FlushMenuThemes(VOID)
{ {
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return; return;
} }
static const auto pFlushMenuThemes static const auto pFlushMenuThemes
= reinterpret_cast<FlushMenuThemesPtr>( = reinterpret_cast<FlushMenuThemesPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(136))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(136)));
if (!pFlushMenuThemes) { if (!pFlushMenuThemes) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return; return;
} }
pFlushMenuThemes(); pFlushMenuThemes();
@ -188,14 +188,14 @@ _RefreshImmersiveColorPolicyState(VOID)
{ {
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return; return;
} }
static const auto pRefreshImmersiveColorPolicyState static const auto pRefreshImmersiveColorPolicyState
= reinterpret_cast<RefreshImmersiveColorPolicyStatePtr>( = reinterpret_cast<RefreshImmersiveColorPolicyStatePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(104))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(104)));
if (!pRefreshImmersiveColorPolicyState) { if (!pRefreshImmersiveColorPolicyState) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return; return;
} }
pRefreshImmersiveColorPolicyState(); pRefreshImmersiveColorPolicyState();
@ -206,19 +206,19 @@ _IsDarkModeAllowedForWindow(const HWND hWnd)
{ {
Q_ASSERT(hWnd); Q_ASSERT(hWnd);
if (!hWnd) { if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER); ::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
static const auto pIsDarkModeAllowedForWindow static const auto pIsDarkModeAllowedForWindow
= reinterpret_cast<IsDarkModeAllowedForWindowPtr>( = reinterpret_cast<IsDarkModeAllowedForWindowPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(137))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(137)));
if (!pIsDarkModeAllowedForWindow) { if (!pIsDarkModeAllowedForWindow) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pIsDarkModeAllowedForWindow(hWnd); return pIsDarkModeAllowedForWindow(hWnd);
@ -229,14 +229,14 @@ _GetIsImmersiveColorUsingHighContrast(const IMMERSIVE_HC_CACHE_MODE mode)
{ {
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
static const auto pGetIsImmersiveColorUsingHighContrast static const auto pGetIsImmersiveColorUsingHighContrast
= reinterpret_cast<GetIsImmersiveColorUsingHighContrastPtr>( = reinterpret_cast<GetIsImmersiveColorUsingHighContrastPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(106))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(106)));
if (!pGetIsImmersiveColorUsingHighContrast) { if (!pGetIsImmersiveColorUsingHighContrast) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pGetIsImmersiveColorUsingHighContrast(mode); return pGetIsImmersiveColorUsingHighContrast(mode);
@ -248,19 +248,19 @@ _OpenNcThemeData(const HWND hWnd, LPCWSTR pszClassList)
Q_ASSERT(hWnd); Q_ASSERT(hWnd);
Q_ASSERT(pszClassList); Q_ASSERT(pszClassList);
if (!hWnd || !pszClassList) { if (!hWnd || !pszClassList) {
SetLastError(ERROR_INVALID_PARAMETER); ::SetLastError(ERROR_INVALID_PARAMETER);
return nullptr; return nullptr;
} }
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return nullptr; return nullptr;
} }
static const auto pOpenNcThemeData static const auto pOpenNcThemeData
= reinterpret_cast<OpenNcThemeDataPtr>( = reinterpret_cast<OpenNcThemeDataPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(49))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(49)));
if (!pOpenNcThemeData) { if (!pOpenNcThemeData) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return nullptr; return nullptr;
} }
return pOpenNcThemeData(hWnd, pszClassList); return pOpenNcThemeData(hWnd, pszClassList);
@ -271,14 +271,14 @@ _ShouldSystemUseDarkMode(VOID)
{ {
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
static const auto pShouldSystemUseDarkMode static const auto pShouldSystemUseDarkMode
= reinterpret_cast<ShouldSystemUseDarkModePtr>( = reinterpret_cast<ShouldSystemUseDarkModePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(138))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(138)));
if (!pShouldSystemUseDarkMode) { if (!pShouldSystemUseDarkMode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pShouldSystemUseDarkMode(); return pShouldSystemUseDarkMode();
@ -289,14 +289,14 @@ _SetPreferredAppMode(const PREFERRED_APP_MODE mode)
{ {
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return PAM_MAX; return PAM_MAX;
} }
static const auto pSetPreferredAppMode static const auto pSetPreferredAppMode
= reinterpret_cast<SetPreferredAppModePtr>( = reinterpret_cast<SetPreferredAppModePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135)));
if (!pSetPreferredAppMode) { if (!pSetPreferredAppMode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return PAM_MAX; return PAM_MAX;
} }
return pSetPreferredAppMode(mode); return pSetPreferredAppMode(mode);
@ -307,14 +307,14 @@ _IsDarkModeAllowedForApp(VOID)
{ {
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
static const auto pIsDarkModeAllowedForApp static const auto pIsDarkModeAllowedForApp
= reinterpret_cast<IsDarkModeAllowedForAppPtr>( = reinterpret_cast<IsDarkModeAllowedForAppPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(139))); SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(139)));
if (!pIsDarkModeAllowedForApp) { if (!pIsDarkModeAllowedForApp) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pIsDarkModeAllowedForApp(); return pIsDarkModeAllowedForApp();
@ -325,12 +325,12 @@ _EnableChildWindowDpiMessage2(const HWND hWnd, const BOOL fEnable)
{ {
Q_ASSERT(hWnd); Q_ASSERT(hWnd);
if (!hWnd) { if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER); ::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
using EnableChildWindowDpiMessagePtr = decltype(&::_EnableChildWindowDpiMessage); using EnableChildWindowDpiMessagePtr = decltype(&::_EnableChildWindowDpiMessage);
@ -355,7 +355,7 @@ _EnableChildWindowDpiMessage2(const HWND hWnd, const BOOL fEnable)
return nullptr; return nullptr;
}(); }();
if (!pEnableChildWindowDpiMessage) { if (!pEnableChildWindowDpiMessage) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pEnableChildWindowDpiMessage(hWnd, fEnable); return pEnableChildWindowDpiMessage(hWnd, fEnable);
@ -366,7 +366,7 @@ _EnablePerMonitorDialogScaling2(VOID)
{ {
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
using EnablePerMonitorDialogScalingPtr = decltype(&::_EnablePerMonitorDialogScaling); using EnablePerMonitorDialogScalingPtr = decltype(&::_EnablePerMonitorDialogScaling);
@ -385,7 +385,7 @@ _EnablePerMonitorDialogScaling2(VOID)
return nullptr; return nullptr;
}(); }();
if (!pEnablePerMonitorDialogScaling) { if (!pEnablePerMonitorDialogScaling) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pEnablePerMonitorDialogScaling(); return pEnablePerMonitorDialogScaling();
@ -396,12 +396,12 @@ _GetDpiForWindow2(const HWND hWnd)
{ {
Q_ASSERT(hWnd); Q_ASSERT(hWnd);
if (!hWnd) { if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER); ::SetLastError(ERROR_INVALID_PARAMETER);
return 0; return 0;
} }
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0; return 0;
} }
using GetDpiForWindowPtr = decltype(&::_GetDpiForWindow); using GetDpiForWindowPtr = decltype(&::_GetDpiForWindow);
@ -424,7 +424,7 @@ _GetDpiForWindow2(const HWND hWnd)
return nullptr; return nullptr;
}(); }();
if (!pGetDpiForWindow) { if (!pGetDpiForWindow) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0; return 0;
} }
return pGetDpiForWindow(hWnd); return pGetDpiForWindow(hWnd);
@ -436,12 +436,12 @@ _GetSystemMetricsForDpi2(const int nIndex, const UINT dpi)
Q_ASSERT(nIndex >= 0); Q_ASSERT(nIndex >= 0);
Q_ASSERT(dpi != 0); Q_ASSERT(dpi != 0);
if ((nIndex < 0) || (dpi == 0)) { if ((nIndex < 0) || (dpi == 0)) {
SetLastError(ERROR_INVALID_PARAMETER); ::SetLastError(ERROR_INVALID_PARAMETER);
return 0; return 0;
} }
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0; return 0;
} }
using GetSystemMetricsForDpiPtr = decltype(&::_GetSystemMetricsForDpi); using GetSystemMetricsForDpiPtr = decltype(&::_GetSystemMetricsForDpi);
@ -460,7 +460,7 @@ _GetSystemMetricsForDpi2(const int nIndex, const UINT dpi)
return nullptr; return nullptr;
}(); }();
if (!pGetSystemMetricsForDpi) { if (!pGetSystemMetricsForDpi) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0; return 0;
} }
return pGetSystemMetricsForDpi(nIndex, dpi); return pGetSystemMetricsForDpi(nIndex, dpi);
@ -473,12 +473,12 @@ _AdjustWindowRectExForDpi2(LPRECT lpRect, const DWORD dwStyle,
Q_ASSERT(lpRect); Q_ASSERT(lpRect);
Q_ASSERT(dpi != 0); Q_ASSERT(dpi != 0);
if (!lpRect || (dpi == 0)) { if (!lpRect || (dpi == 0)) {
SetLastError(ERROR_INVALID_PARAMETER); ::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
if (!WindowsVersionHelper::isWin10OrGreater()) { if (!WindowsVersionHelper::isWin10OrGreater()) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
using AdjustWindowRectExForDpiPtr = decltype(&::_AdjustWindowRectExForDpi); using AdjustWindowRectExForDpiPtr = decltype(&::_AdjustWindowRectExForDpi);
@ -496,7 +496,7 @@ _AdjustWindowRectExForDpi2(LPRECT lpRect, const DWORD dwStyle,
return nullptr; return nullptr;
}(); }();
if (!pAdjustWindowRectExForDpi) { if (!pAdjustWindowRectExForDpi) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE; return FALSE;
} }
return pAdjustWindowRectExForDpi(lpRect, dwStyle, bMenu, dwExStyle, dpi); return pAdjustWindowRectExForDpi(lpRect, dwStyle, bMenu, dwExStyle, dpi);

View File

@ -24,6 +24,7 @@
#include "utils.h" #include "utils.h"
#include "framelesshelpercore_global_p.h" #include "framelesshelpercore_global_p.h"
#include "framelessmanager_p.h"
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
# include "winverhelper_p.h" # include "winverhelper_p.h"
#endif // Q_OS_WINDOWS #endif // Q_OS_WINDOWS
@ -210,29 +211,38 @@ QWindow *Utils::findWindow(const WId windowId)
return nullptr; return nullptr;
} }
void Utils::moveWindowToDesktopCenter(FramelessParamsConst params, const bool considerTaskBar) bool Utils::moveWindowToDesktopCenter(const WId windowId, const bool considerTaskBar)
{ {
Q_ASSERT(params); Q_ASSERT(windowId);
if (!params) { if (!windowId) {
return; return false;
} }
const QSize windowSize = params->getWindowSize(); const QObject *window = FramelessManagerPrivate::getWindow(windowId);
if (windowSize.isEmpty() || (windowSize == kDefaultWindowSize)) { if (!window) {
return; return false;
} }
const QScreen *screen = params->getWindowScreen(); const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data || !data->callbacks) {
return false;
}
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 +324,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

@ -132,7 +132,7 @@ extern QString gtkSettings(const gchar *);
// https://bugreports.qt.io/browse/QTBUG-102488 // https://bugreports.qt.io/browse/QTBUG-102488
const QPoint localPos = window->mapFromGlobal(globalPos); const QPoint localPos = window->mapFromGlobal(globalPos);
const QPoint scenePos = localPos; // windowPos in Qt5. const QPoint scenePos = localPos; // windowPos in Qt5.
const auto event = std::make_unique<QMouseEvent>( const auto event = new QMouseEvent(
QEvent::MouseButtonRelease, QEvent::MouseButtonRelease,
localPos, localPos,
scenePos, scenePos,
@ -140,7 +140,7 @@ extern QString gtkSettings(const gchar *);
Qt::LeftButton, Qt::LeftButton,
QGuiApplication::mouseButtons() ^ Qt::LeftButton, QGuiApplication::mouseButtons() ^ Qt::LeftButton,
QGuiApplication::keyboardModifiers()); QGuiApplication::keyboardModifiers());
QGuiApplication::sendEvent(window, event.get()); QGuiApplication::postEvent(window, event);
} }
QScreen *Utils::x11_findScreenForVirtualDesktop(const int virtualDesktopNumber) QScreen *Utils::x11_findScreenForVirtualDesktop(const int virtualDesktopNumber)

View File

@ -87,7 +87,7 @@ using namespace Global;
class MacOSNotificationObserver class MacOSNotificationObserver
{ {
Q_DISABLE_COPY_MOVE(MacOSNotificationObserver) FRAMELESSHELPER_CLASS(MacOSNotificationObserver)
public: public:
explicit MacOSNotificationObserver(NSObject *object, NSNotificationName name, const Callback &callback) { explicit MacOSNotificationObserver(NSObject *object, NSNotificationName name, const Callback &callback) {
@ -125,7 +125,7 @@ private:
class MacOSKeyValueObserver class MacOSKeyValueObserver
{ {
Q_DISABLE_COPY_MOVE(MacOSKeyValueObserver) FRAMELESSHELPER_CLASS(MacOSKeyValueObserver)
public: public:
// Note: MacOSKeyValueObserver must not outlive the object observed! // Note: MacOSKeyValueObserver must not outlive the object observed!
@ -176,7 +176,7 @@ private:
class MacOSThemeObserver class MacOSThemeObserver
{ {
Q_DISABLE_COPY_MOVE(MacOSThemeObserver) FRAMELESSHELPER_CLASS(MacOSThemeObserver)
public: public:
explicit MacOSThemeObserver() explicit MacOSThemeObserver()
@ -223,8 +223,7 @@ private:
class NSWindowProxy : public QObject class NSWindowProxy : public QObject
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_CLASS_INFO FRAMELESSHELPER_QT_CLASS(NSWindowProxy)
Q_DISABLE_COPY_MOVE(NSWindowProxy)
public: public:
explicit NSWindowProxy(QWindow *qtWindow, NSWindow *macWindow, QObject *parent = nil) : QObject(parent) explicit NSWindowProxy(QWindow *qtWindow, NSWindow *macWindow, QObject *parent = nil) : QObject(parent)

View File

@ -28,6 +28,7 @@
#include "framelesshelper_windows.h" #include "framelesshelper_windows.h"
#include "framelessmanager.h" #include "framelessmanager.h"
#include "framelessmanager_p.h"
#include "framelessconfig_p.h" #include "framelessconfig_p.h"
#include "sysapiloader_p.h" #include "sysapiloader_p.h"
#include "registrykey_p.h" #include "registrykey_p.h"
@ -193,19 +194,44 @@ FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient)
FRAMELESSHELPER_STRING_CONSTANT(DwmFlush) FRAMELESSHELPER_STRING_CONSTANT(DwmFlush)
FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos) FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos)
struct Win32UtilsData struct UtilsWinExtraData : public FramelessExtraData
{ {
SystemParameters params = {};
};
struct Win32UtilsInternal
{
QHash<WId, Win32UtilsData> data = {};
WNDPROC qtWindowProc = nullptr; WNDPROC qtWindowProc = nullptr;
QList<WId> micaWindowIds = {}; bool windowProcHooked = false;
}; bool mica = false;
Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData) UtilsWinExtraData();
~UtilsWinExtraData() override;
[[nodiscard]] static FramelessExtraDataPtr create();
};
using UtilsWinExtraDataPtr = std::shared_ptr<UtilsWinExtraData>;
UtilsWinExtraData::UtilsWinExtraData() = default;
UtilsWinExtraData::~UtilsWinExtraData() = default;
FramelessExtraDataPtr UtilsWinExtraData::create()
{
return std::make_shared<UtilsWinExtraData>();
}
[[nodiscard]] static inline UtilsWinExtraDataPtr tryGetExtraData(const FramelessDataPtr &data, const bool create)
{
Q_ASSERT(data);
if (!data) {
return nullptr;
}
auto it = data->extraData.find(ExtraDataType::WindowsUtilities);
if (it == data->extraData.end()) {
if (create) {
it = data->extraData.insert(ExtraDataType::WindowsUtilities, UtilsWinExtraData::create());
} else {
return nullptr;
}
}
return std::dynamic_pointer_cast<UtilsWinExtraData>(it.value());
}
struct Win32Message struct Win32Message
{ {
@ -583,99 +609,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)
{
return QPoint{ int(point.x), int(point.y) };
}
[[nodiscard]] POINT qpoint2point(const QPoint &point)
{
return POINT{ LONG(point.x()), LONG(point.y()) };
}
[[nodiscard]] QSize size2qsize(const SIZE &size)
{
return QSize{ int(size.cx), int(size.cy) };
}
[[nodiscard]] SIZE qsize2size(const QSize &size)
{
return SIZE{ LONG(size.width()), LONG(size.height()) };
}
[[nodiscard]] QRect rect2qrect(const RECT &rect)
{
return QRect{ QPoint{ int(rect.left), int(rect.top) }, QSize{ int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect)) } };
}
[[nodiscard]] RECT qrect2rect(const QRect &qrect)
{
return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) };
}
[[nodiscard]] QString hwnd2str(const WId windowId)
{
// NULL handle is allowed here.
return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(windowId, 16).toUpper().rightJustified(8, u'0');
}
[[nodiscard]] QString hwnd2str(const HWND hwnd)
{
// NULL handle is allowed here.
return hwnd2str(reinterpret_cast<WId>(hwnd));
}
[[nodiscard]] std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd) [[nodiscard]] std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd)
{ {
Q_ASSERT(hwnd); Q_ASSERT(hwnd);
@ -734,8 +667,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 +717,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 +770,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,8 +792,7 @@ 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 WId windowId, const int index, const bool horizontal, const bool scaled)
const bool horizontal, const bool scaled)
{ {
Q_ASSERT(windowId); Q_ASSERT(windowId);
if (!windowId) { if (!windowId) {
@ -883,29 +811,29 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return std::round(qreal(::GetSystemMetrics(index)) / dpr); return std::round(qreal(::GetSystemMetrics(index)) / dpr);
} }
[[maybe_unused]] [[nodiscard]] static inline [[maybe_unused]] [[nodiscard]] static inline constexpr
DWORD qtEdgesToWin32Orientation(const Qt::Edges edges) DWORD qtEdgesToWin32Orientation(const Qt::Edges edges)
{ {
if (edges == Qt::Edges{}) { if (edges == Qt::Edges{}) {
return 0; return 0;
} else if (edges == (Qt::LeftEdge)) { } else if (edges == (Qt::LeftEdge)) {
return 0xF001; // SC_SIZELEFT return SC_SIZELEFT;
} else if (edges == (Qt::RightEdge)) { } else if (edges == (Qt::RightEdge)) {
return 0xF002; // SC_SIZERIGHT return SC_SIZERIGHT;
} else if (edges == (Qt::TopEdge)) { } else if (edges == (Qt::TopEdge)) {
return 0xF003; // SC_SIZETOP return SC_SIZETOP;
} else if (edges == (Qt::TopEdge | Qt::LeftEdge)) { } else if (edges == (Qt::TopEdge | Qt::LeftEdge)) {
return 0xF004; // SC_SIZETOPLEFT return SC_SIZETOPLEFT;
} else if (edges == (Qt::TopEdge | Qt::RightEdge)) { } else if (edges == (Qt::TopEdge | Qt::RightEdge)) {
return 0xF005; // SC_SIZETOPRIGHT return SC_SIZETOPRIGHT;
} else if (edges == (Qt::BottomEdge)) { } else if (edges == (Qt::BottomEdge)) {
return 0xF006; // SC_SIZEBOTTOM return SC_SIZEBOTTOM;
} else if (edges == (Qt::BottomEdge | Qt::LeftEdge)) { } else if (edges == (Qt::BottomEdge | Qt::LeftEdge)) {
return 0xF007; // SC_SIZEBOTTOMLEFT return SC_SIZEBOTTOMLEFT;
} else if (edges == (Qt::BottomEdge | Qt::RightEdge)) { } else if (edges == (Qt::BottomEdge | Qt::RightEdge)) {
return 0xF008; // SC_SIZEBOTTOMRIGHT return SC_SIZEBOTTOMRIGHT;
} else { } else {
return 0xF000; // SC_SIZE return SC_SIZE;
} }
} }
@ -923,7 +851,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return result; return result;
} }
[[nodiscard]] static inline bool isNonClientMessage(const UINT message) [[nodiscard]] static inline constexpr bool isNonClientMessage(const UINT message)
{ {
if (((message >= WM_NCCREATE) && (message <= WM_NCACTIVATE)) if (((message >= WM_NCCREATE) && (message <= WM_NCACTIVATE))
|| ((message >= WM_NCMOUSEMOVE) && (message <= WM_NCMBUTTONDBLCLK)) || ((message >= WM_NCMOUSEMOVE) && (message <= WM_NCMBUTTONDBLCLK))
@ -936,7 +864,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
} }
} }
[[nodiscard]] static inline bool isMouseMessage(const UINT message, bool *isNonClient = nullptr) [[nodiscard]] static inline constexpr bool isMouseMessage(const UINT message, bool *isNonClient = nullptr)
{ {
if (((message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST)) if (((message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST))
|| ((message == WM_MOUSEHOVER) || (message == WM_MOUSELEAVE))) { || ((message == WM_MOUSEHOVER) || (message == WM_MOUSELEAVE))) {
@ -956,18 +884,12 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
} }
} }
[[nodiscard]] static inline bool usePureQtImplementation()
{
static const bool result = FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
return result;
}
[[nodiscard]] static inline LRESULT CALLBACK FramelessHelperHookWindowProc [[nodiscard]] static inline LRESULT CALLBACK FramelessHelperHookWindowProc
(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) (const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
{ {
Q_ASSERT(hWnd); Q_ASSERT(hWnd);
if (!hWnd) { if (!hWnd) {
return 0; return FALSE;
} }
#if FRAMELESSHELPER_CONFIG(debug_output) #if FRAMELESSHELPER_CONFIG(debug_output)
if (isWin32MessageDebuggingEnabled()) { if (isWin32MessageDebuggingEnabled()) {
@ -981,11 +903,27 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
Utils::printWin32Message(&message); Utils::printWin32Message(&message);
} }
#endif #endif
const auto defaultWindowProcessing = [hWnd, uMsg, wParam, lParam]() -> LRESULT { return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); };
const auto windowId = reinterpret_cast<WId>(hWnd); const auto windowId = reinterpret_cast<WId>(hWnd);
const auto it = g_win32UtilsData()->data.constFind(windowId); const QObject *window = FramelessManagerPrivate::getWindow(windowId);
if (it == g_win32UtilsData()->data.constEnd()) { if (!window) {
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); return defaultWindowProcessing();
} }
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data || !data->frameless || !data->callbacks) {
return defaultWindowProcessing();
}
const UtilsWinExtraDataPtr extraData = tryGetExtraData(data, false);
Q_ASSERT(extraData);
if (!extraData) {
return defaultWindowProcessing();
}
const QWindow *qWindow = data->callbacks->getWindowHandle();
Q_ASSERT(qWindow);
if (!qWindow) {
return defaultWindowProcessing();
}
#if FRAMELESSHELPER_CONFIG(native_impl)
// 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
// We can see from the source code that Qt will filter out some messages first and then send the unfiltered // We can see from the source code that Qt will filter out some messages first and then send the unfiltered
// messages to the event dispatcher. To activate the Snap Layout feature on Windows 11, we must process // messages to the event dispatcher. To activate the Snap Layout feature on Windows 11, we must process
@ -1004,7 +942,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
// (and correct client area size, especially when the window is maximized/fullscreen). So we still go through // (and correct client area size, especially when the window is maximized/fullscreen). So we still go through
// the normal code path of the original qWindowsWndProc() function, but only for this specific message. It should // the normal code path of the original qWindowsWndProc() function, but only for this specific message. It should
// be OK because Qt won't prevent us from handling WM_NCCALCSIZE. // be OK because Qt won't prevent us from handling WM_NCCALCSIZE.
if (!usePureQtImplementation() && (uMsg != WM_NCCALCSIZE)) { if (uMsg != WM_NCCALCSIZE) {
MSG message; MSG message;
SecureZeroMemory(&message, sizeof(message)); SecureZeroMemory(&message, sizeof(message));
message.hwnd = hWnd; message.hwnd = hWnd;
@ -1034,7 +972,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return LRESULT(filterResult); return LRESULT(filterResult);
} }
} }
const Win32UtilsData &data = it.value(); #endif // native_impl
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)};
}; };
@ -1073,8 +1011,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(qWindow, 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 +1022,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,20 +1050,20 @@ 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(windowId, 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
// entering Qt's own handling logic. // entering Qt's own handling logic.
return 0; // Return 0 means we have handled this event. return FALSE; // Return 0 means we have handled this event.
} }
Q_ASSERT(g_win32UtilsData()->qtWindowProc); Q_ASSERT(extraData->qtWindowProc);
if (g_win32UtilsData()->qtWindowProc) { if (extraData->qtWindowProc) {
// Hand over to Qt's original window proc function for events we are not // Hand over to Qt's original window proc function for events we are not
// interested in. // interested in.
return ::CallWindowProcW(g_win32UtilsData()->qtWindowProc, hWnd, uMsg, wParam, lParam); return ::CallWindowProcW(extraData->qtWindowProc, hWnd, uMsg, wParam, lParam);
} else { } else {
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); return defaultWindowProcessing();
} }
} }
@ -1167,16 +1105,12 @@ bool Utils::triggerFrameChange(const WId windowId)
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = reinterpret_cast<HWND>(windowId);
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;
@ -1193,19 +1127,31 @@ bool Utils::updateWindowFrameMargins(const WId windowId, const bool reset)
if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) { if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) {
return false; return false;
} }
// We can't extend the window frame when DWM composition is disabled. // We can't extend the window frame when DWM composition is disabled anyway.
// No need to try further in this case. // No need to try further in this case.
if (!isDwmCompositionEnabled()) { if (!isDwmCompositionEnabled()) {
return false; return false;
} }
const bool micaEnabled = g_win32UtilsData()->micaWindowIds.contains(windowId); const QObject *window = FramelessManagerPrivate::getWindow(windowId);
const auto margins = [micaEnabled, reset]() -> MARGINS { if (!window) {
return false;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data) {
return false;
}
const UtilsWinExtraDataPtr extraData = tryGetExtraData(data, false);
Q_ASSERT(extraData);
if (!extraData) {
return false;
}
const auto margins = [&extraData, 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
// redirection surface, but this will break GDI's rendering, so we // redirection surface, but this will break GDI's rendering, so we
// can't do this, unfortunately), so we can't change the window frame // can't do this, unfortunately), so we can't change the window frame
// margins in this case, otherwise Mica/Mica Alt will be broken. // margins in this case, otherwise Mica/Mica Alt will be broken.
if (micaEnabled) { if (extraData->mica) {
return {-1, -1, -1, -1}; return {-1, -1, -1, -1};
} }
if (reset || isWindowFrameBorderVisible()) { if (reset || isWindowFrameBorderVisible()) {
@ -1275,9 +1221,9 @@ QString Utils::getSystemErrorMessage(const QString &function)
if (function.isEmpty()) { if (function.isEmpty()) {
return {}; return {};
} }
const DWORD code = GetLastError(); const DWORD code = ::GetLastError();
if (code == ERROR_SUCCESS) { if (code == ERROR_SUCCESS) {
return {}; return kSuccessMessageText;
} }
return getSystemErrorMessageImpl(function, code); return getSystemErrorMessageImpl(function, code);
} }
@ -1342,12 +1288,19 @@ 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 WId windowId, const QPoint &pos, const bool selectFirstEntry)
FramelessParamsConst params)
{ {
Q_ASSERT(windowId); Q_ASSERT(windowId);
Q_ASSERT(params); if (!windowId) {
if (!windowId || !params) { return false;
}
const QObject *window = FramelessManagerPrivate::getWindow(windowId);
if (!window) {
return false;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data || !data->frameless || !data->callbacks) {
return false; return false;
} }
@ -1361,11 +1314,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(windowId));
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,14 +1352,13 @@ 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.
::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | MFS_UNHILITE)); ::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | MFS_UNHILITE));
if (result == 0) { if (result == FALSE) {
// The user canceled the menu, no need to continue. // The user canceled the menu, no need to continue.
return true; return true;
} }
@ -1614,13 +1566,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.
@ -1740,11 +1689,9 @@ 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));
} }
} }
@ -1755,11 +1702,9 @@ quint32 Utils::getResizeBorderThickness(const WId windowId, const bool horizonta
return 0; return 0;
} }
if (horizontal) { if (horizontal) {
return (getSystemMetrics2(windowId, SM_CXSIZEFRAME, true, scaled) return (getSystemMetrics2(windowId, SM_CXSIZEFRAME, true, scaled) + getSystemMetrics2(windowId, SM_CXPADDEDBORDER, true, scaled));
+ getSystemMetrics2(windowId, SM_CXPADDEDBORDER, true, scaled));
} else { } else {
return (getSystemMetrics2(windowId, SM_CYSIZEFRAME, false, scaled) return (getSystemMetrics2(windowId, SM_CYSIZEFRAME, false, scaled) + getSystemMetrics2(windowId, SM_CYPADDEDBORDER, false, scaled));
+ getSystemMetrics2(windowId, SM_CYPADDEDBORDER, false, scaled));
} }
} }
@ -1830,13 +1775,12 @@ quint32 Utils::getFrameBorderThickness(const WId windowId, const bool scaled)
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 = reinterpret_cast<HWND>(windowId);
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);
} }
} }
@ -1949,7 +1893,7 @@ bool Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(window->winId()); const auto hwnd = reinterpret_cast<HWND>(window->winId());
if (::PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) { if (::PostMessageW(hwnd, WM_SYSCOMMAND, SC_DRAGMOVE, 0) == FALSE) {
WARNING << getSystemErrorMessage(kPostMessageW); WARNING << getSystemErrorMessage(kPostMessageW);
return false; return false;
} }
@ -1986,10 +1930,8 @@ bool Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
bool Utils::isWindowFrameBorderVisible() bool Utils::isWindowFrameBorderVisible()
{ {
static const auto result = []() -> bool { static const auto result = []() -> bool {
#if FRAMELESSHELPER_CONFIG(native_impl)
const FramelessConfig * const config = FramelessConfig::instance(); const FramelessConfig * const config = FramelessConfig::instance();
if (config->isSet(Option::UseCrossPlatformQtImplementation)) {
return false;
}
if (config->isSet(Option::ForceShowWindowFrameBorder)) { if (config->isSet(Option::ForceShowWindowFrameBorder)) {
return true; return true;
} }
@ -1997,6 +1939,9 @@ bool Utils::isWindowFrameBorderVisible()
return false; return false;
} }
return WindowsVersionHelper::isWin10OrGreater(); return WindowsVersionHelper::isWin10OrGreater();
#else
return false;
#endif
}(); }();
return result; return result;
} }
@ -2016,15 +1961,29 @@ bool Utils::isFrameBorderColorized()
return isTitleBarColorized(); return isTitleBarColorized();
} }
bool Utils::installWindowProcHook(const WId windowId, FramelessParamsConst params) bool Utils::installWindowProcHook(const WId windowId)
{ {
Q_ASSERT(windowId); Q_ASSERT(windowId);
Q_ASSERT(params); if (!windowId) {
if (!windowId || !params) { return false;
}
const QObject *window = FramelessManagerPrivate::getWindow(windowId);
Q_ASSERT(window);
if (!window) {
return false;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
Q_ASSERT(data);
if (!data || data->frameless) {
return false;
}
const UtilsWinExtraDataPtr extraData = tryGetExtraData(data, true);
Q_ASSERT(extraData);
if (!extraData) {
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = reinterpret_cast<HWND>(windowId);
if (!g_win32UtilsData()->qtWindowProc) { if (!extraData->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));
Q_ASSERT(qtWindowProc); Q_ASSERT(qtWindowProc);
@ -2032,18 +1991,15 @@ bool Utils::installWindowProcHook(const WId windowId, FramelessParamsConst param
WARNING << getSystemErrorMessage(kGetWindowLongPtrW); WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
return false; return false;
} }
g_win32UtilsData()->qtWindowProc = qtWindowProc; extraData->qtWindowProc = qtWindowProc;
} }
const auto it = g_win32UtilsData()->data.constFind(windowId); if (!extraData->windowProcHooked) {
if (it == g_win32UtilsData()->data.constEnd()) {
Win32UtilsData data = {};
data.params = *params;
g_win32UtilsData()->data.insert(windowId, data);
::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;
} }
extraData->windowProcHooked = true;
} }
return true; return true;
} }
@ -2054,19 +2010,30 @@ bool Utils::uninstallWindowProcHook(const WId windowId)
if (!windowId) { if (!windowId) {
return false; return false;
} }
const auto it = g_win32UtilsData()->data.constFind(windowId); const QObject *window = FramelessManagerPrivate::getWindow(windowId);
if (it != g_win32UtilsData()->data.constEnd()) { if (!window) {
g_win32UtilsData()->data.erase(it); return false;
} }
if (g_win32UtilsData()->data.isEmpty() && g_win32UtilsData()->qtWindowProc) { const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
const auto hwnd = reinterpret_cast<HWND>(windowId); if (!data || !data->frameless) {
::SetLastError(ERROR_SUCCESS); return false;
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(g_win32UtilsData()->qtWindowProc)) == 0) {
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
return false;
}
g_win32UtilsData()->qtWindowProc = nullptr;
} }
const UtilsWinExtraDataPtr extraData = tryGetExtraData(data, false);
if (!extraData || !extraData->windowProcHooked) {
return false;
}
Q_ASSERT(extraData->qtWindowProc);
if (!extraData->qtWindowProc) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
::SetLastError(ERROR_SUCCESS);
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(extraData->qtWindowProc)) == 0) {
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
return false;
}
extraData->qtWindowProc = nullptr;
extraData->windowProcHooked = false;
return true; return true;
} }
@ -2323,6 +2290,19 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
if (!windowId) { if (!windowId) {
return false; return false;
} }
const QObject *window = FramelessManagerPrivate::getWindow(windowId);
if (!window) {
return false;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data) {
return false;
}
const UtilsWinExtraDataPtr extraData = tryGetExtraData(data, false);
// Don't assert here, the user may be using pure Qt solution.
if (!extraData) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = reinterpret_cast<HWND>(windowId);
if (WindowsVersionHelper::isWin8OrGreater()) { if (WindowsVersionHelper::isWin8OrGreater()) {
if (!(API_DWM_AVAILABLE(DwmSetWindowAttribute) if (!(API_DWM_AVAILABLE(DwmSetWindowAttribute)
@ -2330,8 +2310,8 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
WARNING << "Blur behind window is not available on current platform."; WARNING << "Blur behind window is not available on current platform.";
return false; return false;
} }
const auto restoreWindowFrameMargins = [windowId]() -> void { const auto restoreWindowFrameMargins = [windowId, &extraData]() -> void {
g_win32UtilsData()->micaWindowIds.removeAll(windowId); extraData->mica = false;
std::ignore = updateWindowFrameMargins(windowId, false); std::ignore = updateWindowFrameMargins(windowId, false);
}; };
static const auto userPreferredBlurMode = []() -> std::optional<BlurMode> { static const auto userPreferredBlurMode = []() -> std::optional<BlurMode> {
@ -2372,7 +2352,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
return mode; return mode;
} }
if (((mode == BlurMode::Windows_Mica) || (mode == BlurMode::Windows_MicaAlt)) if (((mode == BlurMode::Windows_Mica) || (mode == BlurMode::Windows_MicaAlt))
&& !WindowsVersionHelper::isWin11OrGreater()) { && !WindowsVersionHelper::isWin11OrGreater()) {
WARNING << "The Mica material is not supported on your system, fallback to the Acrylic blur instead..."; WARNING << "The Mica material is not supported on your system, fallback to the Acrylic blur instead...";
if (WindowsVersionHelper::isWin10OrGreater()) { if (WindowsVersionHelper::isWin10OrGreater()) {
return BlurMode::Windows_Acrylic; return BlurMode::Windows_Acrylic;
@ -2438,7 +2418,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
return result; return result;
} else { } else {
if ((blurMode == BlurMode::Windows_Mica) || (blurMode == BlurMode::Windows_MicaAlt)) { if ((blurMode == BlurMode::Windows_Mica) || (blurMode == BlurMode::Windows_MicaAlt)) {
g_win32UtilsData()->micaWindowIds.append(windowId); extraData->mica = true;
// By giving a negative value, DWM will extend the window frame into the whole // By giving a negative value, DWM will extend the window frame into the whole
// client area. We need this step because the Mica material can only be applied // client area. We need this step because the Mica material can only be applied
// to the non-client area of a window. Without this step, you'll get a window // to the non-client area of a window. Without this step, you'll get a window
@ -2682,9 +2662,9 @@ bool Utils::setQtDarkModeAwareEnabled(const bool enable)
// flag has no effect for pure Qt Quick applications. // flag has no effect for pure Qt Quick applications.
return {App::DarkModeWindowFrames | App::DarkModeStyle}; return {App::DarkModeWindowFrames | App::DarkModeStyle};
# else // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) \ # else // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) \
// Don't try to use the broken dark theme for Qt Widgets applications. \ // Don't try to use the broken dark theme for Qt Widgets applications. \
// For Qt Quick applications this is also enough. There's no global dark \ // For Qt Quick applications this is also enough. There's no global dark \
// theme for them anyway. // theme for them anyway.
return {App::DarkModeWindowFrames}; return {App::DarkModeWindowFrames};
# endif // (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) # endif // (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
}()); }());
@ -3107,16 +3087,6 @@ QRect Utils::getWindowRestoreGeometry(const WId windowId)
return rect2qrect(wp.rcNormalPosition).translated(getWindowPlacementOffset(windowId)); return rect2qrect(wp.rcNormalPosition).translated(getWindowPlacementOffset(windowId));
} }
bool Utils::removeMicaWindow(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return false;
}
g_win32UtilsData()->micaWindowIds.removeAll(windowId);
return true;
}
quint64 Utils::getKeyState() quint64 Utils::getKeyState()
{ {
quint64 result = 0; quint64 result = 0;
@ -3163,7 +3133,7 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo
return false; return false;
} }
const LONG_PTR exStyles = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE); const LONG_PTR exStyles = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
if ((exStyles != 0) && (exStyles & WS_EX_TOOLWINDOW)) { if ((exStyles == 0) || (exStyles & WS_EX_TOOLWINDOW)) {
return false; return false;
} }
RECT rect = { 0, 0, 0, 0 }; RECT rect = { 0, 0, 0, 0 };
@ -3209,11 +3179,11 @@ bool Utils::updateFramebufferTransparency(const WId windowId)
DWM_BLURBEHIND bb; DWM_BLURBEHIND bb;
SecureZeroMemory(&bb, sizeof(bb)); SecureZeroMemory(&bb, sizeof(bb));
bb.dwFlags = (DWM_BB_ENABLE | DWM_BB_BLURREGION); bb.dwFlags = (DWM_BB_ENABLE | DWM_BB_BLURREGION);
bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); bb.hRgnBlur = ::CreateRectRgn(0, 0, -1, -1);
bb.fEnable = TRUE; bb.fEnable = TRUE;
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmEnableBlurBehindWindow, hwnd, &bb); const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmEnableBlurBehindWindow, hwnd, &bb);
if (bb.hRgnBlur) { if (bb.hRgnBlur) {
if (DeleteObject(bb.hRgnBlur) == FALSE) { if (::DeleteObject(bb.hRgnBlur) == FALSE) {
WARNING << getSystemErrorMessage(kDeleteObject); WARNING << getSystemErrorMessage(kDeleteObject);
} }
} }

View File

@ -35,7 +35,7 @@ using namespace Global;
class WinVerHelper class WinVerHelper
{ {
Q_DISABLE_COPY_MOVE(WinVerHelper) FRAMELESSHELPER_CLASS(WinVerHelper)
public: public:
explicit WinVerHelper(); explicit WinVerHelper();

View File

@ -109,7 +109,7 @@ if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
COPYRIGHT "MIT License" COPYRIGHT "MIT License"
ORIGINAL_FILENAME "${SUB_MODULE_FULL_NAME}.dll" ORIGINAL_FILENAME "${SUB_MODULE_FULL_NAME}.dll"
PRODUCT "${PROJECT_NAME}" PRODUCT "${PROJECT_NAME}"
COMMENTS "Built from commit ${PROJECT_VERSION_COMMIT} on ${PROJECT_COMPILE_DATETIME} (UTC)." COMMENTS "Who don't love Raiden Shogun ?"
LIBRARY LIBRARY
) )
endif() endif()

View File

@ -32,6 +32,7 @@
#endif #endif
#include <FramelessHelper/Core/framelessmanager.h> #include <FramelessHelper/Core/framelessmanager.h>
#include <FramelessHelper/Core/utils.h> #include <FramelessHelper/Core/utils.h>
#include <FramelessHelper/Core/private/framelessmanager_p.h>
#include <FramelessHelper/Core/private/framelessconfig_p.h> #include <FramelessHelper/Core/private/framelessconfig_p.h>
#include <FramelessHelper/Core/private/framelesshelpercore_global_p.h> #include <FramelessHelper/Core/private/framelesshelpercore_global_p.h>
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -72,10 +73,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
struct FramelessQuickHelperData struct FramelessQuickHelperExtraData : public FramelessExtraData
{ {
bool ready = false;
SystemParameters params = {};
QPointer<QQuickItem> titleBarItem = nullptr; QPointer<QQuickItem> titleBarItem = nullptr;
QList<QPointer<QQuickItem>> hitTestVisibleItems = {}; QList<QPointer<QQuickItem>> hitTestVisibleItems = {};
QPointer<QQuickItem> windowIconButton = nullptr; QPointer<QQuickItem> windowIconButton = nullptr;
@ -84,11 +83,52 @@ struct FramelessQuickHelperData
QPointer<QQuickItem> maximizeButton = nullptr; QPointer<QQuickItem> maximizeButton = nullptr;
QPointer<QQuickItem> closeButton = nullptr; QPointer<QQuickItem> closeButton = nullptr;
QList<QRect> hitTestVisibleRects = {}; QList<QRect> hitTestVisibleRects = {};
FramelessQuickHelperExtraData();
~FramelessQuickHelperExtraData() override;
[[nodiscard]] static FramelessExtraDataPtr create();
}; };
using FramelessQuickHelperExtraDataPtr = std::shared_ptr<FramelessQuickHelperExtraData>;
using FramelessQuickHelperInternal = QHash<WId, FramelessQuickHelperData>; FramelessQuickHelperExtraData::FramelessQuickHelperExtraData() = default;
Q_GLOBAL_STATIC(FramelessQuickHelperInternal, g_framelessQuickHelperData) FramelessQuickHelperExtraData::~FramelessQuickHelperExtraData() = default;
FramelessExtraDataPtr FramelessQuickHelperExtraData::create()
{
return std::make_shared<FramelessQuickHelperExtraData>();
}
[[nodiscard]] static inline FramelessQuickHelperExtraDataPtr tryGetExtraData(const FramelessDataPtr &data, const bool create)
{
Q_ASSERT(data);
if (!data) {
return nullptr;
}
auto it = data->extraData.find(ExtraDataType::FramelessQuickHelper);
if (it == data->extraData.end()) {
if (create) {
it = data->extraData.insert(ExtraDataType::FramelessQuickHelper, FramelessQuickHelperExtraData::create());
} else {
return nullptr;
}
}
return std::dynamic_pointer_cast<FramelessQuickHelperExtraData>(it.value());
}
[[nodiscard]] static inline FramelessQuickHelperExtraDataPtr tryGetExtraData(const QQuickWindow *window, const bool create)
{
Q_ASSERT(window);
if (!window) {
return nullptr;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data) {
return nullptr;
}
return tryGetExtraData(data, create);
}
FramelessQuickHelperPrivate::FramelessQuickHelperPrivate(FramelessQuickHelper *q) : QObject(q) FramelessQuickHelperPrivate::FramelessQuickHelperPrivate(FramelessQuickHelper *q) : QObject(q)
{ {
@ -124,59 +164,61 @@ const FramelessQuickHelperPrivate *FramelessQuickHelperPrivate::get(const Framel
void FramelessQuickHelperPrivate::attach() void FramelessQuickHelperPrivate::attach()
{ {
Q_Q(FramelessQuickHelper); Q_Q(FramelessQuickHelper);
QQuickWindow * const window = q->window(); QQuickWindow *window = q->window();
Q_ASSERT(window); Q_ASSERT(window);
if (!window) { if (!window) {
return; return;
} }
const WId windowId = window->winId();
FramelessQuickHelperData * const data = getWindowDataMutable(); const FramelessDataPtr data = FramelessManagerPrivate::createData(window, windowId);
if (!data || data->ready) { Q_ASSERT(data);
if (!data || data->frameless) {
return; return;
} }
SystemParameters params = {}; if (!data->callbacks) {
params.getWindowId = [window]() -> WId { return window->winId(); }; data->callbacks = FramelessCallbacks::create();
params.getWindowFlags = [window]() -> Qt::WindowFlags { return window->flags(); }; data->callbacks->getWindowId = [window]() -> WId { return window->winId(); };
params.setWindowFlags = [window](const Qt::WindowFlags flags) -> void { window->setFlags(flags); }; data->callbacks->getWindowFlags = [window]() -> Qt::WindowFlags { return window->flags(); };
params.getWindowSize = [window]() -> QSize { return window->size(); }; data->callbacks->setWindowFlags = [window](const Qt::WindowFlags flags) -> void { window->setFlags(flags); };
params.setWindowSize = [window](const QSize &size) -> void { window->resize(size); }; data->callbacks->getWindowSize = [window]() -> QSize { return window->size(); };
params.getWindowPosition = [window]() -> QPoint { return window->position(); }; data->callbacks->setWindowSize = [window](const QSize &size) -> void { window->resize(size); };
params.setWindowPosition = [window](const QPoint &pos) -> void { window->setX(pos.x()); window->setY(pos.y()); }; data->callbacks->getWindowPosition = [window]() -> QPoint { return window->position(); };
params.getWindowScreen = [window]() -> QScreen * { return window->screen(); }; data->callbacks->setWindowPosition = [window](const QPoint &pos) -> void { window->setX(pos.x()); window->setY(pos.y()); };
params.isWindowFixedSize = [q]() -> bool { return q->isWindowFixedSize(); }; data->callbacks->getWindowScreen = [window]() -> QScreen * { return window->screen(); };
params.setWindowFixedSize = [q](const bool value) -> void { q->setWindowFixedSize(value); }; data->callbacks->isWindowFixedSize = [q]() -> bool { return q->isWindowFixedSize(); };
params.getWindowState = [window]() -> Qt::WindowState { return window->windowState(); }; data->callbacks->setWindowFixedSize = [q](const bool value) -> void { q->setWindowFixedSize(value); };
params.setWindowState = [window](const Qt::WindowState state) -> void { window->setWindowState(state); }; data->callbacks->getWindowState = [window]() -> Qt::WindowState { return window->windowState(); };
params.getWindowHandle = [window]() -> QWindow * { return window; }; data->callbacks->setWindowState = [window](const Qt::WindowState state) -> void { window->setWindowState(state); };
params.windowToScreen = [window](const QPoint &pos) -> QPoint { return window->mapToGlobal(pos); }; data->callbacks->getWindowHandle = [q]() -> QWindow * { return q->window(); };
params.screenToWindow = [window](const QPoint &pos) -> QPoint { return window->mapFromGlobal(pos); }; data->callbacks->windowToScreen = [window](const QPoint &pos) -> QPoint { return window->mapToGlobal(pos); };
params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { data->callbacks->screenToWindow = [window](const QPoint &pos) -> QPoint { return window->mapFromGlobal(pos); };
QuickGlobal::SystemButtonType button2 = QuickGlobal::SystemButtonType::Unknown; data->callbacks->isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool {
const bool result = isInSystemButtons(pos, &button2); QuickGlobal::SystemButtonType button2 = QuickGlobal::SystemButtonType::Unknown;
*button = FRAMELESSHELPER_ENUM_QUICK_TO_CORE(SystemButtonType, button2); const bool result = isInSystemButtons(pos, &button2);
return result; *button = FRAMELESSHELPER_ENUM_QUICK_TO_CORE(SystemButtonType, button2);
}; return result;
params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); }; };
params.getWindowDevicePixelRatio = [window]() -> qreal { return window->effectiveDevicePixelRatio(); }; data->callbacks->isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); };
params.setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void { data->callbacks->getWindowDevicePixelRatio = [window]() -> qreal { return window->effectiveDevicePixelRatio(); };
setSystemButtonState(FRAMELESSHELPER_ENUM_CORE_TO_QUICK(SystemButtonType, button), data->callbacks->setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void {
FRAMELESSHELPER_ENUM_CORE_TO_QUICK(ButtonState, state)); setSystemButtonState(FRAMELESSHELPER_ENUM_CORE_TO_QUICK(SystemButtonType, button), FRAMELESSHELPER_ENUM_CORE_TO_QUICK(ButtonState, state));
}; };
params.shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); }; data->callbacks->shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); };
params.showSystemMenu = [q](const QPoint &pos) -> void { q->showSystemMenu(pos); }; data->callbacks->showSystemMenu = [q](const QPoint &pos) -> void { q->showSystemMenu(pos); };
params.setProperty = [this](const char *name, const QVariant &value) -> void { setProperty(name, value); }; data->callbacks->setProperty = [this](const char *name, const QVariant &value) -> void { setProperty(name, value); };
params.getProperty = [this](const char *name, const QVariant &defaultValue) -> QVariant { return getProperty(name, defaultValue); }; data->callbacks->getProperty = [this](const char *name, const QVariant &defaultValue) -> QVariant { return getProperty(name, defaultValue); };
params.setCursor = [window](const QCursor &cursor) -> void { window->setCursor(cursor); }; data->callbacks->setCursor = [window](const QCursor &cursor) -> void { window->setCursor(cursor); };
params.unsetCursor = [window]() -> void { window->unsetCursor(); }; data->callbacks->unsetCursor = [window]() -> void { window->unsetCursor(); };
params.getWidgetHandle = []() -> QObject * { return nullptr; }; data->callbacks->getWidgetHandle = []() -> QObject * { return nullptr; };
params.forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); }; data->callbacks->forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); };
params.resetQtGrabbedControl = []() -> bool { return false; }; data->callbacks->resetQtGrabbedControl = []() -> bool { return false; };
}
FramelessManager::instance()->addWindow(&params); std::ignore = tryGetExtraData(data, true);
data->params = params; std::ignore = FramelessManager::instance()->addWindow(window, windowId);
data->ready = true;
// We have to wait for a little time before moving the top level window // We have to wait for a little time before moving the top level window
// , because the platform window may not finish initializing by the time // , because the platform window may not finish initializing by the time
@ -198,17 +240,11 @@ void FramelessQuickHelperPrivate::attach()
void FramelessQuickHelperPrivate::detach() void FramelessQuickHelperPrivate::detach()
{ {
Q_Q(FramelessQuickHelper); Q_Q(FramelessQuickHelper);
QQuickWindow * const w = q->window(); const QQuickWindow *window = q->window();
if (!w) { if (!window) {
return; return;
} }
const WId windowId = w->winId(); std::ignore = FramelessManager::instance()->removeWindow(window);
const auto it = g_framelessQuickHelperData()->constFind(windowId);
if (it == g_framelessQuickHelperData()->constEnd()) {
return;
}
g_framelessQuickHelperData()->erase(it);
FramelessManager::instance()->removeWindow(windowId);
} }
void FramelessQuickHelperPrivate::emitSignalForAllInstances(const char *signal) void FramelessQuickHelperPrivate::emitSignalForAllInstances(const char *signal)
@ -433,37 +469,43 @@ bool FramelessQuickHelperPrivate::isInSystemButtons(const QPoint &pos, QuickGlob
if (!button) { if (!button) {
return false; return false;
} }
const FramelessQuickHelperData *data = getWindowData(); Q_Q(const FramelessQuickHelper);
if (!data) { const QQuickWindow * const window = q->window();
if (!window) {
return false;
}
const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(window, false);
Q_ASSERT(extraData);
if (!extraData) {
return false; return false;
} }
*button = QuickGlobal::SystemButtonType::Unknown; *button = QuickGlobal::SystemButtonType::Unknown;
if (data->windowIconButton && data->windowIconButton->isVisible() && data->windowIconButton->isEnabled()) { if (extraData->windowIconButton && extraData->windowIconButton->isVisible() && extraData->windowIconButton->isEnabled()) {
if (mapItemGeometryToScene(data->windowIconButton).contains(pos)) { if (mapItemGeometryToScene(extraData->windowIconButton).contains(pos)) {
*button = QuickGlobal::SystemButtonType::WindowIcon; *button = QuickGlobal::SystemButtonType::WindowIcon;
return true; return true;
} }
} }
if (data->contextHelpButton && data->contextHelpButton->isVisible() && data->contextHelpButton->isEnabled()) { if (extraData->contextHelpButton && extraData->contextHelpButton->isVisible() && extraData->contextHelpButton->isEnabled()) {
if (mapItemGeometryToScene(data->contextHelpButton).contains(pos)) { if (mapItemGeometryToScene(extraData->contextHelpButton).contains(pos)) {
*button = QuickGlobal::SystemButtonType::Help; *button = QuickGlobal::SystemButtonType::Help;
return true; return true;
} }
} }
if (data->minimizeButton && data->minimizeButton->isVisible() && data->minimizeButton->isEnabled()) { if (extraData->minimizeButton && extraData->minimizeButton->isVisible() && extraData->minimizeButton->isEnabled()) {
if (mapItemGeometryToScene(data->minimizeButton).contains(pos)) { if (mapItemGeometryToScene(extraData->minimizeButton).contains(pos)) {
*button = QuickGlobal::SystemButtonType::Minimize; *button = QuickGlobal::SystemButtonType::Minimize;
return true; return true;
} }
} }
if (data->maximizeButton && data->maximizeButton->isVisible() && data->maximizeButton->isEnabled()) { if (extraData->maximizeButton && extraData->maximizeButton->isVisible() && extraData->maximizeButton->isEnabled()) {
if (mapItemGeometryToScene(data->maximizeButton).contains(pos)) { if (mapItemGeometryToScene(extraData->maximizeButton).contains(pos)) {
*button = QuickGlobal::SystemButtonType::Maximize; *button = QuickGlobal::SystemButtonType::Maximize;
return true; return true;
} }
} }
if (data->closeButton && data->closeButton->isVisible() && data->closeButton->isEnabled()) { if (extraData->closeButton && extraData->closeButton->isVisible() && extraData->closeButton->isEnabled()) {
if (mapItemGeometryToScene(data->closeButton).contains(pos)) { if (mapItemGeometryToScene(extraData->closeButton).contains(pos)) {
*button = QuickGlobal::SystemButtonType::Close; *button = QuickGlobal::SystemButtonType::Close;
return true; return true;
} }
@ -473,18 +515,6 @@ bool FramelessQuickHelperPrivate::isInSystemButtons(const QPoint &pos, QuickGlob
bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) const bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) const
{ {
const FramelessQuickHelperData *data = getWindowData();
if (!data) {
return false;
}
if (!data->titleBarItem) {
// There's no title bar at all, the mouse will always be in the client area.
return false;
}
if (!data->titleBarItem->isVisible() || !data->titleBarItem->isEnabled()) {
// The title bar is hidden or disabled for some reason, treat it as there's no title bar.
return false;
}
Q_Q(const FramelessQuickHelper); Q_Q(const FramelessQuickHelper);
const QQuickWindow * const window = q->window(); const QQuickWindow * const window = q->window();
if (!window) { if (!window) {
@ -492,8 +522,21 @@ bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) c
// so we assume there's no title bar. // so we assume there's no title bar.
return false; return false;
} }
const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(window, false);
Q_ASSERT(extraData);
if (!extraData) {
return false;
}
if (!extraData->titleBarItem) {
// There's no title bar at all, the mouse will always be in the client area.
return false;
}
if (!extraData->titleBarItem->isVisible() || !extraData->titleBarItem->isEnabled()) {
// The title bar is hidden or disabled for some reason, treat it as there's no title bar.
return false;
}
const QRect windowRect = {QPoint(0, 0), window->size()}; const QRect windowRect = {QPoint(0, 0), window->size()};
const QRect titleBarRect = mapItemGeometryToScene(data->titleBarItem); const QRect titleBarRect = mapItemGeometryToScene(extraData->titleBarItem);
if (!titleBarRect.intersects(windowRect)) { if (!titleBarRect.intersects(windowRect)) {
// The title bar is totally outside of the window for some reason, // The title bar is totally outside of the window for some reason,
// also treat it as there's no title bar. // also treat it as there's no title bar.
@ -501,24 +544,24 @@ bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) c
} }
QRegion region = titleBarRect; QRegion region = titleBarRect;
const auto systemButtons = { const auto systemButtons = {
data->windowIconButton, data->contextHelpButton, extraData->windowIconButton, extraData->contextHelpButton,
data->minimizeButton, data->maximizeButton, extraData->minimizeButton, extraData->maximizeButton,
data->closeButton extraData->closeButton
}; };
for (auto &&button : std::as_const(systemButtons)) { for (auto &&button : std::as_const(systemButtons)) {
if (button && button->isVisible() && button->isEnabled()) { if (button && button->isVisible() && button->isEnabled()) {
region -= mapItemGeometryToScene(button); region -= mapItemGeometryToScene(button);
} }
} }
if (!data->hitTestVisibleItems.isEmpty()) { if (!extraData->hitTestVisibleItems.isEmpty()) {
for (auto &&item : std::as_const(data->hitTestVisibleItems)) { for (auto &&item : std::as_const(extraData->hitTestVisibleItems)) {
if (item && item->isVisible() && item->isEnabled()) { if (item && item->isVisible() && item->isEnabled()) {
region -= mapItemGeometryToScene(item); region -= mapItemGeometryToScene(item);
} }
} }
} }
if (!data->hitTestVisibleRects.isEmpty()) { if (!extraData->hitTestVisibleRects.isEmpty()) {
for (auto &&rect : std::as_const(data->hitTestVisibleRects)) { for (auto &&rect : std::as_const(extraData->hitTestVisibleRects)) {
if (rect.isValid()) { if (rect.isValid()) {
region -= rect; region -= rect;
} }
@ -556,38 +599,6 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System
Q_UNUSED(state); Q_UNUSED(state);
} }
const FramelessQuickHelperData *FramelessQuickHelperPrivate::getWindowData() const
{
Q_Q(const FramelessQuickHelper);
const QQuickWindow * const window = q->window();
//Q_ASSERT(window);
if (!window) {
return nullptr;
}
const WId windowId = window->winId();
auto it = g_framelessQuickHelperData()->find(windowId);
if (it == g_framelessQuickHelperData()->end()) {
it = g_framelessQuickHelperData()->insert(windowId, {});
}
return &it.value();
}
FramelessQuickHelperData *FramelessQuickHelperPrivate::getWindowDataMutable() const
{
Q_Q(const FramelessQuickHelper);
const QQuickWindow * const window = q->window();
//Q_ASSERT(window);
if (!window) {
return nullptr;
}
const WId windowId = window->winId();
auto it = g_framelessQuickHelperData()->find(windowId);
if (it == g_framelessQuickHelperData()->end()) {
it = g_framelessQuickHelperData()->insert(windowId, {});
}
return &it.value();
}
void FramelessQuickHelperPrivate::rebindWindow() void FramelessQuickHelperPrivate::rebindWindow()
{ {
Q_Q(FramelessQuickHelper); Q_Q(FramelessQuickHelper);
@ -668,33 +679,41 @@ void FramelessQuickHelper::setHitTestVisible_item(QQuickItem *item, const bool v
if (!item) { if (!item) {
return; return;
} }
Q_D(FramelessQuickHelper); const QQuickWindow * const w = window();
FramelessQuickHelperData *data = d->getWindowDataMutable(); if (!w) {
if (!data) { return;
}
const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false);
Q_ASSERT(extraData);
if (!extraData) {
return; return;
} }
if (visible) { if (visible) {
data->hitTestVisibleItems.append(item); extraData->hitTestVisibleItems.append(item);
} else { } else {
data->hitTestVisibleItems.removeAll(item); extraData->hitTestVisibleItems.removeAll(item);
} }
} }
void FramelessQuickHelper::setHitTestVisible_rect(const QRect &rect, const bool visible) void FramelessQuickHelper::setHitTestVisible_rect(const QRect &rect, const bool visible)
{ {
Q_ASSERT(rect.isValid()); Q_ASSERT(Utils::isValidGeometry(rect));
if (!rect.isValid()) { if (!Utils::isValidGeometry(rect)) {
return; return;
} }
Q_D(FramelessQuickHelper); const QQuickWindow * const w = window();
FramelessQuickHelperData *data = d->getWindowDataMutable(); if (!w) {
if (!data) { return;
}
const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false);
Q_ASSERT(extraData);
if (!extraData) {
return; return;
} }
if (visible) { if (visible) {
data->hitTestVisibleRects.append(rect); extraData->hitTestVisibleRects.append(rect);
} else { } else {
data->hitTestVisibleRects.removeAll(rect); extraData->hitTestVisibleRects.removeAll(rect);
} }
} }
@ -714,9 +733,12 @@ void FramelessQuickHelper::setHitTestVisible_object(QObject *object, const bool
bool FramelessQuickHelper::isContentExtendedIntoTitleBar() const bool FramelessQuickHelper::isContentExtendedIntoTitleBar() const
{ {
Q_D(const FramelessQuickHelper); const QQuickWindow * const w = window();
const FramelessQuickHelperData *data = d->getWindowData(); if (!w) {
return (data ? data->ready : false); return false;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(w);
return (data && data->frameless);
} }
void FramelessQuickHelper::extendsContentIntoTitleBar(const bool value) void FramelessQuickHelper::extendsContentIntoTitleBar(const bool value)
@ -736,9 +758,16 @@ void FramelessQuickHelper::extendsContentIntoTitleBar(const bool value)
QQuickItem *FramelessQuickHelper::titleBarItem() const QQuickItem *FramelessQuickHelper::titleBarItem() const
{ {
Q_D(const FramelessQuickHelper); const QQuickWindow * const w = window();
const FramelessQuickHelperData *data = d->getWindowData(); if (!w) {
return (data ? data->titleBarItem : nullptr); return nullptr;
}
const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false);
Q_ASSERT(extraData);
if (!extraData) {
return nullptr;
}
return extraData->titleBarItem;
} }
void FramelessQuickHelper::setTitleBarItem(QQuickItem *value) void FramelessQuickHelper::setTitleBarItem(QQuickItem *value)
@ -747,12 +776,17 @@ void FramelessQuickHelper::setTitleBarItem(QQuickItem *value)
if (!value) { if (!value) {
return; return;
} }
Q_D(FramelessQuickHelper); const QQuickWindow * const w = window();
FramelessQuickHelperData *data = d->getWindowDataMutable(); if (!w) {
if (!data || (data->titleBarItem == value)) {
return; return;
} }
data->titleBarItem = value; const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false);
Q_ASSERT(extraData);
if (!extraData || (extraData->titleBarItem == value)) {
return;
}
extraData->titleBarItem = value;
Q_D(FramelessQuickHelper);
d->emitSignalForAllInstances("titleBarItemChanged"); d->emitSignalForAllInstances("titleBarItemChanged");
} }
@ -763,27 +797,31 @@ void FramelessQuickHelper::setSystemButton(QQuickItem *item, const QuickGlobal::
if (!item || (buttonType == QuickGlobal::SystemButtonType::Unknown)) { if (!item || (buttonType == QuickGlobal::SystemButtonType::Unknown)) {
return; return;
} }
Q_D(FramelessQuickHelper); const QQuickWindow * const w = window();
FramelessQuickHelperData *data = d->getWindowDataMutable(); if (!w) {
if (!data) { return;
}
const FramelessQuickHelperExtraDataPtr extraData = tryGetExtraData(w, false);
Q_ASSERT(extraData);
if (!extraData) {
return; return;
} }
switch (buttonType) { switch (buttonType) {
case QuickGlobal::SystemButtonType::WindowIcon: case QuickGlobal::SystemButtonType::WindowIcon:
data->windowIconButton = item; extraData->windowIconButton = item;
break; break;
case QuickGlobal::SystemButtonType::Help: case QuickGlobal::SystemButtonType::Help:
data->contextHelpButton = item; extraData->contextHelpButton = item;
break; break;
case QuickGlobal::SystemButtonType::Minimize: case QuickGlobal::SystemButtonType::Minimize:
data->minimizeButton = item; extraData->minimizeButton = item;
break; break;
case QuickGlobal::SystemButtonType::Maximize: case QuickGlobal::SystemButtonType::Maximize:
case QuickGlobal::SystemButtonType::Restore: case QuickGlobal::SystemButtonType::Restore:
data->maximizeButton = item; extraData->maximizeButton = item;
break; break;
case QuickGlobal::SystemButtonType::Close: case QuickGlobal::SystemButtonType::Close:
data->closeButton = item; extraData->closeButton = item;
break; break;
case QuickGlobal::SystemButtonType::Unknown: case QuickGlobal::SystemButtonType::Unknown:
Q_UNREACHABLE(); Q_UNREACHABLE();
@ -799,8 +837,7 @@ void FramelessQuickHelper::showSystemMenu(const QPoint &pos)
const WId windowId = w->winId(); const WId windowId = w->winId();
const QPoint nativePos = Utils::toNativeGlobalPosition(w, pos); const QPoint nativePos = Utils::toNativeGlobalPosition(w, pos);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
Q_D(FramelessQuickHelper); std::ignore = Utils::showSystemMenu(windowId, nativePos, false);
std::ignore = Utils::showSystemMenu(windowId, nativePos, false, &d->getWindowData()->params);
#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) #elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
Utils::openSystemMenu(windowId, nativePos); Utils::openSystemMenu(windowId, nativePos);
#else #else
@ -832,11 +869,11 @@ void FramelessQuickHelper::windowStartSystemResize2(const Qt::Edges edges, const
void FramelessQuickHelper::moveWindowToDesktopCenter() void FramelessQuickHelper::moveWindowToDesktopCenter()
{ {
if (!window()) { const QQuickWindow * const w = window();
if (!w) {
return; return;
} }
Q_D(FramelessQuickHelper); std::ignore = Utils::moveWindowToDesktopCenter(w->winId(), true);
Utils::moveWindowToDesktopCenter(&d->getWindowData()->params, true);
} }
void FramelessQuickHelper::bringWindowToFront() void FramelessQuickHelper::bringWindowToFront()
@ -912,6 +949,7 @@ bool FramelessQuickHelper::isBlurBehindWindowEnabled() const
void FramelessQuickHelper::setBlurBehindWindowEnabled(const bool value) void FramelessQuickHelper::setBlurBehindWindowEnabled(const bool value)
{ {
#if (!defined(Q_OS_WINDOWS) || FRAMELESSHELPER_CONFIG(native_impl))
QQuickWindow * const w = window(); QQuickWindow * const w = window();
if (!w) { if (!w) {
return; return;
@ -948,6 +986,9 @@ void FramelessQuickHelper::setBlurBehindWindowEnabled(const bool value)
#endif #endif
d->emitSignalForAllInstances("blurBehindWindowEnabledChanged"); d->emitSignalForAllInstances("blurBehindWindowEnabledChanged");
} }
#else // Windows && !native_impl
Q_UNUSED(value);
#endif
} }
bool FramelessQuickHelper::isReady() const bool FramelessQuickHelper::isReady() const

View File

@ -102,7 +102,7 @@ if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
COPYRIGHT "MIT License" COPYRIGHT "MIT License"
ORIGINAL_FILENAME "${SUB_MODULE_FULL_NAME}.dll" ORIGINAL_FILENAME "${SUB_MODULE_FULL_NAME}.dll"
PRODUCT "${PROJECT_NAME}" PRODUCT "${PROJECT_NAME}"
COMMENTS "Built from commit ${PROJECT_VERSION_COMMIT} on ${PROJECT_COMPILE_DATETIME} (UTC)." COMMENTS "Who don't love Raiden Shogun ?"
LIBRARY LIBRARY
) )
endif() endif()

View File

@ -35,6 +35,7 @@
#include "widgetssharedhelper_p.h" #include "widgetssharedhelper_p.h"
#include <FramelessHelper/Core/framelessmanager.h> #include <FramelessHelper/Core/framelessmanager.h>
#include <FramelessHelper/Core/utils.h> #include <FramelessHelper/Core/utils.h>
#include <FramelessHelper/Core/private/framelessmanager_p.h>
#include <FramelessHelper/Core/private/framelessconfig_p.h> #include <FramelessHelper/Core/private/framelessconfig_p.h>
#include <FramelessHelper/Core/private/framelesshelpercore_global_p.h> #include <FramelessHelper/Core/private/framelesshelpercore_global_p.h>
#include <QtCore/qhash.h> #include <QtCore/qhash.h>
@ -71,10 +72,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
struct FramelessWidgetsHelperData struct FramelessWidgetsHelperExtraData : public FramelessExtraData
{ {
bool ready = false;
SystemParameters params = {};
QPointer<QWidget> titleBarWidget = nullptr; QPointer<QWidget> titleBarWidget = nullptr;
QList<QPointer<QWidget>> hitTestVisibleWidgets = {}; QList<QPointer<QWidget>> hitTestVisibleWidgets = {};
QPointer<QWidget> windowIconButton = nullptr; QPointer<QWidget> windowIconButton = nullptr;
@ -83,13 +82,54 @@ struct FramelessWidgetsHelperData
QPointer<QWidget> maximizeButton = nullptr; QPointer<QWidget> maximizeButton = nullptr;
QPointer<QWidget> closeButton = nullptr; QPointer<QWidget> closeButton = nullptr;
QList<QRect> hitTestVisibleRects = {}; QList<QRect> hitTestVisibleRects = {};
FramelessWidgetsHelperExtraData();
~FramelessWidgetsHelperExtraData() override;
[[nodiscard]] static FramelessExtraDataPtr create();
}; };
using FramelessWidgetsHelperExtraDataPtr = std::shared_ptr<FramelessWidgetsHelperExtraData>;
using FramelessWidgetsHelperInternal = QHash<WId, FramelessWidgetsHelperData>; FramelessWidgetsHelperExtraData::FramelessWidgetsHelperExtraData() = default;
Q_GLOBAL_STATIC(FramelessWidgetsHelperInternal, g_framelessWidgetsHelperData) FramelessWidgetsHelperExtraData::~FramelessWidgetsHelperExtraData() = default;
[[nodiscard]] static inline bool isWidgetFixedSize(const QWidget * const widget) FramelessExtraDataPtr FramelessWidgetsHelperExtraData::create()
{
return std::make_shared<FramelessWidgetsHelperExtraData>();
}
[[nodiscard]] static inline FramelessWidgetsHelperExtraDataPtr tryGetExtraData(const FramelessDataPtr &data, const bool create)
{
Q_ASSERT(data);
if (!data) {
return nullptr;
}
auto it = data->extraData.find(ExtraDataType::FramelessWidgetsHelper);
if (it == data->extraData.end()) {
if (create) {
it = data->extraData.insert(ExtraDataType::FramelessWidgetsHelper, FramelessWidgetsHelperExtraData::create());
} else {
return nullptr;
}
}
return std::dynamic_pointer_cast<FramelessWidgetsHelperExtraData>(it.value());
}
[[nodiscard]] static inline FramelessWidgetsHelperExtraDataPtr tryGetExtraData(const QWidget *window, const bool create)
{
Q_ASSERT(window);
if (!window) {
return nullptr;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data) {
return nullptr;
}
return tryGetExtraData(data, create);
}
[[nodiscard]] static inline bool isWidgetFixedSize(const QWidget *widget)
{ {
Q_ASSERT(widget); Q_ASSERT(widget);
if (!widget) { if (!widget) {
@ -114,7 +154,7 @@ Q_GLOBAL_STATIC(FramelessWidgetsHelperInternal, g_framelessWidgetsHelperData)
return false; return false;
} }
static inline void forceWidgetRepaint(QWidget * const widget) static inline void forceWidgetRepaint(QWidget *widget)
{ {
Q_ASSERT(widget); Q_ASSERT(widget);
if (!widget) { if (!widget) {
@ -360,7 +400,7 @@ void FramelessWidgetsHelperPrivate::setReadyWaitTime(const quint32 time)
void FramelessWidgetsHelperPrivate::attach() void FramelessWidgetsHelperPrivate::attach()
{ {
QWidget * const tlw = findTopLevelWindow(); QWidget *tlw = findTopLevelWindow();
Q_ASSERT(tlw); Q_ASSERT(tlw);
if (!tlw) { if (!tlw) {
return; return;
@ -377,69 +417,72 @@ void FramelessWidgetsHelperPrivate::attach()
window->setAttribute(Qt::WA_NativeWindow); window->setAttribute(Qt::WA_NativeWindow);
} }
FramelessWidgetsHelperData * const data = getWindowDataMutable(); const WId windowId = window->winId();
if (!data || data->ready) { const FramelessDataPtr data = FramelessManagerPrivate::createData(window, windowId);
Q_ASSERT(data);
if (!data || data->frameless) {
return; return;
} }
Q_Q(FramelessWidgetsHelper); Q_Q(FramelessWidgetsHelper);
SystemParameters params = {}; if (!data->callbacks) {
params.getWindowId = [this]() -> WId { return window->winId(); }; data->callbacks = FramelessCallbacks::create();
params.getWindowFlags = [this]() -> Qt::WindowFlags { return window->windowFlags(); }; data->callbacks->getWindowId = [this]() -> WId { return window->winId(); };
params.setWindowFlags = [this](const Qt::WindowFlags flags) -> void { window->setWindowFlags(flags); }; data->callbacks->getWindowFlags = [this]() -> Qt::WindowFlags { return window->windowFlags(); };
params.getWindowSize = [this]() -> QSize { return window->size(); }; data->callbacks->setWindowFlags = [this](const Qt::WindowFlags flags) -> void { window->setWindowFlags(flags); };
params.setWindowSize = [this](const QSize &size) -> void { window->resize(size); }; data->callbacks->getWindowSize = [this]() -> QSize { return window->size(); };
params.getWindowPosition = [this]() -> QPoint { return window->pos(); }; data->callbacks->setWindowSize = [this](const QSize &size) -> void { window->resize(size); };
params.setWindowPosition = [this](const QPoint &pos) -> void { window->move(pos); }; data->callbacks->getWindowPosition = [this]() -> QPoint { return window->pos(); };
params.getWindowScreen = [this]() -> QScreen * { data->callbacks->setWindowPosition = [this](const QPoint &pos) -> void { window->move(pos); };
data->callbacks->getWindowScreen = [this]() -> QScreen * {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return window->screen(); return window->screen();
#else #else
return window->windowHandle()->screen(); return window->windowHandle()->screen();
#endif #endif
}; };
params.isWindowFixedSize = [q]() -> bool { return q->isWindowFixedSize(); }; data->callbacks->isWindowFixedSize = [q]() -> bool { return q->isWindowFixedSize(); };
params.setWindowFixedSize = [q](const bool value) -> void { q->setWindowFixedSize(value); }; data->callbacks->setWindowFixedSize = [q](const bool value) -> void { q->setWindowFixedSize(value); };
params.getWindowState = [this]() -> Qt::WindowState { return Utils::windowStatesToWindowState(window->windowState()); }; data->callbacks->getWindowState = [this]() -> Qt::WindowState { return Utils::windowStatesToWindowState(window->windowState()); };
params.setWindowState = [this](const Qt::WindowState state) -> void { window->setWindowState(state); }; data->callbacks->setWindowState = [this](const Qt::WindowState state) -> void { window->setWindowState(state); };
params.getWindowHandle = [this]() -> QWindow * { return window->windowHandle(); }; data->callbacks->getWindowHandle = [this]() -> QWindow * { return window->windowHandle(); };
params.windowToScreen = [this](const QPoint &pos) -> QPoint { return window->mapToGlobal(pos); }; data->callbacks->windowToScreen = [this](const QPoint &pos) -> QPoint { return window->mapToGlobal(pos); };
params.screenToWindow = [this](const QPoint &pos) -> QPoint { return window->mapFromGlobal(pos); }; data->callbacks->screenToWindow = [this](const QPoint &pos) -> QPoint { return window->mapFromGlobal(pos); };
params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); }; data->callbacks->isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); };
params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); }; data->callbacks->isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); };
params.getWindowDevicePixelRatio = [this]() -> qreal { return window->devicePixelRatioF(); }; data->callbacks->getWindowDevicePixelRatio = [this]() -> qreal { return window->devicePixelRatioF(); };
params.setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void { setSystemButtonState(button, state); }; data->callbacks->setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void { setSystemButtonState(button, state); };
params.shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); }; data->callbacks->shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); };
params.showSystemMenu = [q](const QPoint &pos) -> void { q->showSystemMenu(pos); }; data->callbacks->showSystemMenu = [q](const QPoint &pos) -> void { q->showSystemMenu(pos); };
params.setProperty = [this](const char *name, const QVariant &value) -> void { setProperty(name, value); }; data->callbacks->setProperty = [this](const char *name, const QVariant &value) -> void { setProperty(name, value); };
params.getProperty = [this](const char *name, const QVariant &defaultValue) -> QVariant { return getProperty(name, defaultValue); }; data->callbacks->getProperty = [this](const char *name, const QVariant &defaultValue) -> QVariant { return getProperty(name, defaultValue); };
params.setCursor = [this](const QCursor &cursor) -> void { window->setCursor(cursor); }; data->callbacks->setCursor = [this](const QCursor &cursor) -> void { window->setCursor(cursor); };
params.unsetCursor = [this]() -> void { window->unsetCursor(); }; data->callbacks->unsetCursor = [this]() -> void { window->unsetCursor(); };
params.getWidgetHandle = [this]() -> QObject * { return window; }; data->callbacks->getWidgetHandle = [this]() -> QObject * { return window; };
params.forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); }; data->callbacks->forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); };
params.resetQtGrabbedControl = []() -> bool { data->callbacks->resetQtGrabbedControl = []() -> bool {
if (qt_button_down) { if (qt_button_down) {
static constexpr const auto invalidPos = QPoint{ -99999, -99999 }; static constexpr const auto invalidPos = QPoint{ -99999, -99999 };
const auto event = std::make_unique<QMouseEvent>( const auto event = new QMouseEvent(
QEvent::MouseButtonRelease, QEvent::MouseButtonRelease,
invalidPos, invalidPos,
invalidPos, invalidPos,
invalidPos, invalidPos,
Qt::LeftButton, Qt::LeftButton,
QGuiApplication::mouseButtons() ^ Qt::LeftButton, QGuiApplication::mouseButtons() ^ Qt::LeftButton,
QGuiApplication::keyboardModifiers()); QGuiApplication::keyboardModifiers());
QApplication::sendEvent(qt_button_down, event.get()); QApplication::postEvent(qt_button_down, event);
qt_button_down = nullptr; qt_button_down = nullptr;
return true; return true;
} }
return false; return false;
}; };
}
FramelessManager::instance()->addWindow(&params); std::ignore = tryGetExtraData(data, true);
data->params = params; std::ignore = FramelessManager::instance()->addWindow(window, windowId);
data->ready = true;
// We have to wait for a little time before moving the top level window // We have to wait for a little time before moving the top level window
// , because the platform window may not finish initializing by the time // , because the platform window may not finish initializing by the time
@ -464,13 +507,7 @@ void FramelessWidgetsHelperPrivate::detach()
if (!window) { if (!window) {
return; return;
} }
const WId windowId = window->winId(); std::ignore = FramelessManager::instance()->removeWindow(window);
const auto it = g_framelessWidgetsHelperData()->constFind(windowId);
if (it == g_framelessWidgetsHelperData()->constEnd()) {
return;
}
g_framelessWidgetsHelperData()->erase(it);
FramelessManager::instance()->removeWindow(windowId);
window = nullptr; window = nullptr;
emitSignalForAllInstances("windowChanged"); emitSignalForAllInstances("windowChanged");
} }
@ -488,34 +525,6 @@ QWidget *FramelessWidgetsHelperPrivate::findTopLevelWindow() const
return nullptr; return nullptr;
} }
const FramelessWidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowData() const
{
//Q_ASSERT(window);
if (!window) {
return nullptr;
}
const WId windowId = window->winId();
auto it = g_framelessWidgetsHelperData()->find(windowId);
if (it == g_framelessWidgetsHelperData()->end()) {
it = g_framelessWidgetsHelperData()->insert(windowId, {});
}
return &it.value();
}
FramelessWidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowDataMutable() const
{
//Q_ASSERT(window);
if (!window) {
return nullptr;
}
const WId windowId = window->winId();
auto it = g_framelessWidgetsHelperData()->find(windowId);
if (it == g_framelessWidgetsHelperData()->end()) {
it = g_framelessWidgetsHelperData()->insert(windowId, {});
}
return &it.value();
}
QRect FramelessWidgetsHelperPrivate::mapWidgetGeometryToScene(const QWidget * const widget) const QRect FramelessWidgetsHelperPrivate::mapWidgetGeometryToScene(const QWidget * const widget) const
{ {
Q_ASSERT(widget); Q_ASSERT(widget);
@ -536,37 +545,41 @@ bool FramelessWidgetsHelperPrivate::isInSystemButtons(const QPoint &pos, SystemB
if (!button) { if (!button) {
return false; return false;
} }
const FramelessWidgetsHelperData *data = getWindowData(); if (!window) {
if (!data) { return false;
}
const FramelessWidgetsHelperExtraDataPtr extraData = tryGetExtraData(window, false);
Q_ASSERT(extraData);
if (!extraData) {
return false; return false;
} }
*button = SystemButtonType::Unknown; *button = SystemButtonType::Unknown;
if (data->windowIconButton && data->windowIconButton->isVisible() && data->windowIconButton->isEnabled()) { if (extraData->windowIconButton && extraData->windowIconButton->isVisible() && extraData->windowIconButton->isEnabled()) {
if (mapWidgetGeometryToScene(data->windowIconButton).contains(pos)) { if (mapWidgetGeometryToScene(extraData->windowIconButton).contains(pos)) {
*button = SystemButtonType::WindowIcon; *button = SystemButtonType::WindowIcon;
return true; return true;
} }
} }
if (data->contextHelpButton && data->contextHelpButton->isVisible() && data->contextHelpButton->isEnabled()) { if (extraData->contextHelpButton && extraData->contextHelpButton->isVisible() && extraData->contextHelpButton->isEnabled()) {
if (mapWidgetGeometryToScene(data->contextHelpButton).contains(pos)) { if (mapWidgetGeometryToScene(extraData->contextHelpButton).contains(pos)) {
*button = SystemButtonType::Help; *button = SystemButtonType::Help;
return true; return true;
} }
} }
if (data->minimizeButton && data->minimizeButton->isVisible() && data->minimizeButton->isEnabled()) { if (extraData->minimizeButton && extraData->minimizeButton->isVisible() && extraData->minimizeButton->isEnabled()) {
if (mapWidgetGeometryToScene(data->minimizeButton).contains(pos)) { if (mapWidgetGeometryToScene(extraData->minimizeButton).contains(pos)) {
*button = SystemButtonType::Minimize; *button = SystemButtonType::Minimize;
return true; return true;
} }
} }
if (data->maximizeButton && data->maximizeButton->isVisible() && data->maximizeButton->isEnabled()) { if (extraData->maximizeButton && extraData->maximizeButton->isVisible() && extraData->maximizeButton->isEnabled()) {
if (mapWidgetGeometryToScene(data->maximizeButton).contains(pos)) { if (mapWidgetGeometryToScene(extraData->maximizeButton).contains(pos)) {
*button = SystemButtonType::Maximize; *button = SystemButtonType::Maximize;
return true; return true;
} }
} }
if (data->closeButton && data->closeButton->isVisible() && data->closeButton->isEnabled()) { if (extraData->closeButton && extraData->closeButton->isVisible() && extraData->closeButton->isEnabled()) {
if (mapWidgetGeometryToScene(data->closeButton).contains(pos)) { if (mapWidgetGeometryToScene(extraData->closeButton).contains(pos)) {
*button = SystemButtonType::Close; *button = SystemButtonType::Close;
return true; return true;
} }
@ -576,25 +589,26 @@ bool FramelessWidgetsHelperPrivate::isInSystemButtons(const QPoint &pos, SystemB
bool FramelessWidgetsHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) const bool FramelessWidgetsHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) const
{ {
const FramelessWidgetsHelperData *data = getWindowData();
if (!data) {
return false;
}
if (!data->titleBarWidget) {
// There's no title bar at all, the mouse will always be in the client area.
return false;
}
if (!data->titleBarWidget->isVisible() || !data->titleBarWidget->isEnabled()) {
// The title bar is hidden or disabled for some reason, treat it as there's no title bar.
return false;
}
if (!window) { if (!window) {
// The FramelessWidgetsHelper object has not been attached to a specific window yet, // The FramelessWidgetsHelper object has not been attached to a specific window yet,
// so we assume there's no title bar. // so we assume there's no title bar.
return false; return false;
} }
const FramelessWidgetsHelperExtraDataPtr extraData = tryGetExtraData(window, false);
Q_ASSERT(extraData);
if (!extraData) {
return false;
}
if (!extraData->titleBarWidget) {
// There's no title bar at all, the mouse will always be in the client area.
return false;
}
if (!extraData->titleBarWidget->isVisible() || !extraData->titleBarWidget->isEnabled()) {
// The title bar is hidden or disabled for some reason, treat it as there's no title bar.
return false;
}
const QRect windowRect = {QPoint(0, 0), window->size()}; const QRect windowRect = {QPoint(0, 0), window->size()};
const QRect titleBarRect = mapWidgetGeometryToScene(data->titleBarWidget); const QRect titleBarRect = mapWidgetGeometryToScene(extraData->titleBarWidget);
if (!titleBarRect.intersects(windowRect)) { if (!titleBarRect.intersects(windowRect)) {
// The title bar is totally outside of the window for some reason, // The title bar is totally outside of the window for some reason,
// also treat it as there's no title bar. // also treat it as there's no title bar.
@ -602,24 +616,24 @@ bool FramelessWidgetsHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos)
} }
QRegion region = titleBarRect; QRegion region = titleBarRect;
const auto systemButtons = { const auto systemButtons = {
data->windowIconButton, data->contextHelpButton, extraData->windowIconButton, extraData->contextHelpButton,
data->minimizeButton, data->maximizeButton, extraData->minimizeButton, extraData->maximizeButton,
data->closeButton extraData->closeButton
}; };
for (auto &&button : std::as_const(systemButtons)) { for (auto &&button : std::as_const(systemButtons)) {
if (button && button->isVisible() && button->isEnabled()) { if (button && button->isVisible() && button->isEnabled()) {
region -= mapWidgetGeometryToScene(button); region -= mapWidgetGeometryToScene(button);
} }
} }
if (!data->hitTestVisibleWidgets.isEmpty()) { if (!extraData->hitTestVisibleWidgets.isEmpty()) {
for (auto &&widget : std::as_const(data->hitTestVisibleWidgets)) { for (auto &&widget : std::as_const(extraData->hitTestVisibleWidgets)) {
if (widget && widget->isVisible() && widget->isEnabled()) { if (widget && widget->isVisible() && widget->isEnabled()) {
region -= mapWidgetGeometryToScene(widget); region -= mapWidgetGeometryToScene(widget);
} }
} }
} }
if (!data->hitTestVisibleRects.isEmpty()) { if (!extraData->hitTestVisibleRects.isEmpty()) {
for (auto &&rect : std::as_const(data->hitTestVisibleRects)) { for (auto &&rect : std::as_const(extraData->hitTestVisibleRects)) {
if (rect.isValid()) { if (rect.isValid()) {
region -= rect; region -= rect;
} }
@ -660,7 +674,7 @@ void FramelessWidgetsHelper::moveWindowToDesktopCenter()
if (!d->window) { if (!d->window) {
return; return;
} }
Utils::moveWindowToDesktopCenter(&d->getWindowData()->params, true); std::ignore = Utils::moveWindowToDesktopCenter(d->window->winId(), true);
} }
void FramelessWidgetsHelper::bringWindowToFront() void FramelessWidgetsHelper::bringWindowToFront()
@ -692,7 +706,7 @@ void FramelessWidgetsHelper::showSystemMenu(const QPoint &pos)
const WId windowId = d->window->winId(); const WId windowId = d->window->winId();
const QPoint nativePos = Utils::toNativeGlobalPosition(d->window->windowHandle(), pos); const QPoint nativePos = Utils::toNativeGlobalPosition(d->window->windowHandle(), pos);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
std::ignore = Utils::showSystemMenu(windowId, nativePos, false, &d->getWindowData()->params); std::ignore = Utils::showSystemMenu(windowId, nativePos, false);
#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) #elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
Utils::openSystemMenu(windowId, nativePos); Utils::openSystemMenu(windowId, nativePos);
#else #else
@ -730,26 +744,30 @@ void FramelessWidgetsHelper::setSystemButton(QWidget *widget, const SystemButton
return; return;
} }
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
FramelessWidgetsHelperData *data = d->getWindowDataMutable(); if (!d->window) {
if (!data) { return;
}
const FramelessWidgetsHelperExtraDataPtr extraData = tryGetExtraData(d->window, false);
Q_ASSERT(extraData);
if (!extraData) {
return; return;
} }
switch (buttonType) { switch (buttonType) {
case SystemButtonType::WindowIcon: case SystemButtonType::WindowIcon:
data->windowIconButton = widget; extraData->windowIconButton = widget;
break; break;
case SystemButtonType::Help: case SystemButtonType::Help:
data->contextHelpButton = widget; extraData->contextHelpButton = widget;
break; break;
case SystemButtonType::Minimize: case SystemButtonType::Minimize:
data->minimizeButton = widget; extraData->minimizeButton = widget;
break; break;
case SystemButtonType::Maximize: case SystemButtonType::Maximize:
case SystemButtonType::Restore: case SystemButtonType::Restore:
data->maximizeButton = widget; extraData->maximizeButton = widget;
break; break;
case SystemButtonType::Close: case SystemButtonType::Close:
data->closeButton = widget; extraData->closeButton = widget;
break; break;
case SystemButtonType::Unknown: case SystemButtonType::Unknown:
Q_UNREACHABLE(); Q_UNREACHABLE();
@ -835,6 +853,7 @@ bool FramelessWidgetsHelper::isBlurBehindWindowEnabled() const
void FramelessWidgetsHelper::setBlurBehindWindowEnabled(const bool enable) void FramelessWidgetsHelper::setBlurBehindWindowEnabled(const bool enable)
{ {
#if (!defined(Q_OS_WINDOWS) || FRAMELESSHELPER_CONFIG(native_impl))
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
if (!d->window) { if (!d->window) {
return; return;
@ -866,6 +885,9 @@ void FramelessWidgetsHelper::setBlurBehindWindowEnabled(const bool enable)
DEBUG << "Blur behind window is not supported on current platform."; DEBUG << "Blur behind window is not supported on current platform.";
} }
} }
#else // Windows && !native_impl
Q_UNUSED(enable);
#endif
} }
bool FramelessWidgetsHelper::isReady() const bool FramelessWidgetsHelper::isReady() const
@ -895,8 +917,11 @@ void FramelessWidgetsHelper::waitForReady()
bool FramelessWidgetsHelper::isContentExtendedIntoTitleBar() const bool FramelessWidgetsHelper::isContentExtendedIntoTitleBar() const
{ {
Q_D(const FramelessWidgetsHelper); Q_D(const FramelessWidgetsHelper);
const FramelessWidgetsHelperData *data = d->getWindowData(); if (!d->window) {
return (data ? data->ready : false); return false;
}
const FramelessDataPtr data = FramelessManagerPrivate::getData(d->window);
return (data && data->frameless);
} }
void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget) void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
@ -906,19 +931,30 @@ void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
return; return;
} }
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
FramelessWidgetsHelperData *data = d->getWindowDataMutable(); if (!d->window) {
if (!data || (data->titleBarWidget == widget)) {
return; return;
} }
data->titleBarWidget = widget; const FramelessWidgetsHelperExtraDataPtr extraData = tryGetExtraData(d->window, false);
Q_ASSERT(extraData);
if (!extraData || (extraData->titleBarWidget == widget)) {
return;
}
extraData->titleBarWidget = widget;
d->emitSignalForAllInstances("titleBarWidgetChanged"); d->emitSignalForAllInstances("titleBarWidgetChanged");
} }
QWidget *FramelessWidgetsHelper::titleBarWidget() const QWidget *FramelessWidgetsHelper::titleBarWidget() const
{ {
Q_D(const FramelessWidgetsHelper); Q_D(const FramelessWidgetsHelper);
const FramelessWidgetsHelperData *data = d->getWindowData(); if (!d->window) {
return (data ? data->titleBarWidget : nullptr); return nullptr;
}
const FramelessWidgetsHelperExtraDataPtr extraData = tryGetExtraData(d->window, false);
Q_ASSERT(extraData);
if (!extraData) {
return nullptr;
}
return extraData->titleBarWidget;
} }
void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visible) void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visible)
@ -928,32 +964,40 @@ void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visib
return; return;
} }
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
FramelessWidgetsHelperData *data = d->getWindowDataMutable(); if (!d->window) {
if (!data) { return;
}
const FramelessWidgetsHelperExtraDataPtr extraData = tryGetExtraData(d->window, false);
Q_ASSERT(extraData);
if (!extraData) {
return; return;
} }
if (visible) { if (visible) {
data->hitTestVisibleWidgets.append(widget); extraData->hitTestVisibleWidgets.append(widget);
} else { } else {
data->hitTestVisibleWidgets.removeAll(widget); extraData->hitTestVisibleWidgets.removeAll(widget);
} }
} }
void FramelessWidgetsHelper::setHitTestVisible(const QRect &rect, const bool visible) void FramelessWidgetsHelper::setHitTestVisible(const QRect &rect, const bool visible)
{ {
Q_ASSERT(rect.isValid()); Q_ASSERT(Utils::isValidGeometry(rect));
if (!rect.isValid()) { if (!Utils::isValidGeometry(rect)) {
return; return;
} }
Q_D(FramelessWidgetsHelper); Q_D(FramelessWidgetsHelper);
FramelessWidgetsHelperData *data = d->getWindowDataMutable(); if (!d->window) {
if (!data) { return;
}
const FramelessWidgetsHelperExtraDataPtr extraData = tryGetExtraData(d->window, false);
Q_ASSERT(extraData);
if (!extraData) {
return; return;
} }
if (visible) { if (visible) {
data->hitTestVisibleRects.append(rect); extraData->hitTestVisibleRects.append(rect);
} else { } else {
data->hitTestVisibleRects.removeAll(rect); extraData->hitTestVisibleRects.removeAll(rect);
} }
} }