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(cmake/utils.cmake)
# TODO: Use add_feature_info() for every option below? Is it worth doing?
option(FRAMELESSHELPER_BUILD_STATIC "Build FramelessHelper as a static library." OFF)
@ -61,16 +62,7 @@ option(FRAMELESSHELPER_NO_TRANSLATION "Don't bundle the I18N translations into t
option(FRAMELESSHELPER_NO_MICA_MATERIAL "Disable the cross-platform homemade Mica Material." OFF)
option(FRAMELESSHELPER_NO_BORDER_PAINTER "Disable the cross-platform window frame border painter." OFF)
option(FRAMELESSHELPER_NO_SYSTEM_BUTTON "Disable the pre-defined StandardSystemButton control." OFF)
if(FRAMELESSHELPER_NO_WINDOW AND FRAMELESSHELPER_BUILD_EXAMPLES)
message(WARNING "You can't build the examples when the FramelessWindow class is disabled at the same time!")
set(FRAMELESSHELPER_BUILD_EXAMPLES OFF)
endif()
set(FRAMELESSHELPER_64BIT_POSTFIX "")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(FRAMELESSHELPER_64BIT_POSTFIX "64")
endif()
cmake_dependent_option(FRAMELESSHELPER_NATIVE_IMPL "Use platform native implementation instead of Qt to get best experience." ON WIN32 OFF)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui)
@ -78,10 +70,18 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui)
find_package(QT NAMES Qt6 Qt5 QUIET COMPONENTS Widgets Quick)
find_package(Qt${QT_VERSION_MAJOR} QUIET COMPONENTS Widgets Quick)
include(cmake/utils.cmake)
if(FRAMELESSHELPER_NATIVE_IMPL AND NOT WIN32)
message(WARNING "FRAMELESSHELPER_NATIVE_IMPL currently only supports the Windows platform!")
set(FRAMELESSHELPER_NATIVE_IMPL OFF)
endif()
if(NOT APPLE AND FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
message(WARNING "Current OS is not macOS, universal build will be disabled.")
if(FRAMELESSHELPER_NO_WINDOW AND FRAMELESSHELPER_BUILD_EXAMPLES)
message(WARNING "You can't build the examples when the FramelessWindow class is disabled at the same time!")
set(FRAMELESSHELPER_BUILD_EXAMPLES OFF)
endif()
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD AND NOT APPLE)
message(WARNING "Universal build is a macOS only feature, it will be disabled on current platform.")
set(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD OFF)
elseif(APPLE AND ((QT_VERSION VERSION_LESS "6.2" AND QT_VERSION VERSION_GREATER_EQUAL "6.0") OR (QT_VERSION VERSION_LESS "5.15.9")))
message(WARNING "Your Qt version ${QT_VERSION} doesn't support universal build, it will be disabled.")
@ -94,6 +94,29 @@ endif()
if(FRAMELESSHELPER_ENABLE_VCLTL AND NOT MSVC)
message(WARNING "VC-LTL is only available for the MSVC toolchain.")
set(FRAMELESSHELPER_ENABLE_VCLTL OFF)
endif()
if(FRAMELESSHELPER_ENABLE_YYTHUNKS AND NOT MSVC)
message(WARNING "YY-Thunks is only available for the MSVC toolchain.")
set(FRAMELESSHELPER_ENABLE_YYTHUNKS OFF)
endif()
if(NOT TARGET Qt${QT_VERSION_MAJOR}::Core OR NOT TARGET Qt${QT_VERSION_MAJOR}::Gui)
message(WARNING "Can't find the QtCore and/or QtGui module. Nothing will be built.")
set(FRAMELESSHELPER_BUILD_WIDGETS OFF)
set(FRAMELESSHELPER_BUILD_QUICK OFF)
set(FRAMELESSHELPER_BUILD_EXAMPLES OFF)
endif()
if(FRAMELESSHELPER_BUILD_QUICK AND NOT TARGET Qt${QT_VERSION_MAJOR}::Quick)
message(WARNING "Can't find the QtQuick module. FramelessHelper's QtQuick implementation and the QtQuick demo won't be built.")
set(FRAMELESSHELPER_BUILD_QUICK OFF)
endif()
set(FRAMELESSHELPER_64BIT_POSTFIX "")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(FRAMELESSHELPER_64BIT_POSTFIX "64")
endif()
set(FRAMELESSHELPER_LICENSE_HEADER "/*
@ -144,25 +167,23 @@ if(MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(FRAMELESSHELPER_ENABLE_CFGUARD OFF)
endif()
if(MSVC)
if(FRAMELESSHELPER_ENABLE_VCLTL)
include(cmake/VC-LTL.cmake)
if("x${SupportLTL}" STREQUAL "xtrue")
# Make sure we will always overwrite the previous settings.
unset(CMAKE_MSVC_RUNTIME_LIBRARY)
unset(CMAKE_MSVC_RUNTIME_LIBRARY CACHE)
#unset(CMAKE_MSVC_RUNTIME_LIBRARY PARENT_SCOPE)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<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)
if(FRAMELESSHELPER_ENABLE_VCLTL)
include(cmake/VC-LTL.cmake)
if("x${SupportLTL}" STREQUAL "xtrue")
# Make sure we will always overwrite the previous settings.
unset(CMAKE_MSVC_RUNTIME_LIBRARY)
unset(CMAKE_MSVC_RUNTIME_LIBRARY CACHE)
#unset(CMAKE_MSVC_RUNTIME_LIBRARY PARENT_SCOPE)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<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()
set(__extra_flags "")
if(FRAMELESSHELPER_NO_INSTALL)
@ -175,11 +196,6 @@ prepare_package_export(
)
unset(__extra_flags)
if(FRAMELESSHELPER_BUILD_QUICK AND NOT TARGET Qt${QT_VERSION_MAJOR}::Quick)
message(WARNING "Can't find the QtQuick module. FramelessHelper's QtQuick implementation and the QtQuick demo won't be built.")
set(FRAMELESSHELPER_BUILD_QUICK OFF)
endif()
set(FRAMELESSHELPER_VERSION_FILE "${PROJECT_BINARY_DIR}/framelesshelper.version")
generate_project_version(
PATH "${FRAMELESSHELPER_VERSION_FILE}"
@ -202,14 +218,11 @@ add_project_config(KEY "translation" CONDITION NOT FRAMELESSHELPER_NO_TRANSLATIO
add_project_config(KEY "mica_material" CONDITION NOT FRAMELESSHELPER_NO_MICA_MATERIAL)
add_project_config(KEY "border_painter" CONDITION NOT FRAMELESSHELPER_NO_BORDER_PAINTER)
add_project_config(KEY "system_button" CONDITION NOT FRAMELESSHELPER_NO_SYSTEM_BUTTON)
add_project_config(KEY "native_impl" CONDITION FRAMELESSHELPER_NATIVE_IMPL)
generate_project_config(PATH "${FRAMELESSHELPER_CONFIG_FILE}")
if(TARGET Qt${QT_VERSION_MAJOR}::Core AND TARGET Qt${QT_VERSION_MAJOR}::Gui)
if(FRAMELESSHELPER_BUILD_WIDGETS OR FRAMELESSHELPER_BUILD_QUICK)
add_subdirectory(src)
else()
message(WARNING "Can't find the QtCore and QtGui module. Nothing will be built.")
set(FRAMELESSHELPER_BUILD_WIDGETS OFF)
set(FRAMELESSHELPER_BUILD_EXAMPLES OFF)
endif()
if(FRAMELESSHELPER_BUILD_EXAMPLES)

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

View File

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

View File

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

View File

@ -86,6 +86,46 @@
#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
# define WM_SIZEWAIT (0x0004)
#endif
@ -1102,7 +1142,7 @@ _AdjustWindowRectExForDpi2(
EXTERN_C_END
[[maybe_unused]] inline constexpr const int kAutoHideTaskBarThickness = 2; // The thickness of an auto-hide taskbar in pixels.
[[maybe_unused]] inline constexpr const unsigned char kAutoHideTaskBarThickness = 2; // The thickness of an auto-hide taskbar in pixels.
[[maybe_unused]] inline constexpr const wchar_t kDwmRegistryKey[] = LR"(Software\Microsoft\Windows\DWM)";
[[maybe_unused]] inline constexpr const wchar_t kPersonalizeRegistryKey[] = LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)";
[[maybe_unused]] inline constexpr const wchar_t kThemeSettingChangeEventName[] = L"ImmersiveColorSet";
@ -1111,3 +1151,95 @@ EXTERN_C_END
[[maybe_unused]] inline constexpr const wchar_t kSystemLightThemeResourceName[] = L"Explorer";
[[maybe_unused]] inline constexpr const wchar_t kDesktopRegistryKey[] = LR"(Control Panel\Desktop)";
[[maybe_unused]] inline constexpr const wchar_t kDarkModePropertyName[] = L"UseImmersiveDarkModeColors";
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator==(const POINT &lhs, const POINT &rhs) noexcept
{
return ((lhs.x == rhs.x) && (lhs.y == rhs.y));
}
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator!=(const POINT &lhs, const POINT &rhs) noexcept
{
return !operator==(lhs, rhs);
}
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept
{
return ((lhs.cx == rhs.cx) && (lhs.cy == rhs.cy));
}
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept
{
return !operator==(lhs, rhs);
}
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator>(const SIZE &lhs, const SIZE &rhs) noexcept
{
return ((lhs.cx * lhs.cy) > (rhs.cx * rhs.cy));
}
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator>=(const SIZE &lhs, const SIZE &rhs) noexcept
{
return (operator>(lhs, rhs) || operator==(lhs, rhs));
}
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator<(const SIZE &lhs, const SIZE &rhs) noexcept
{
return (operator!=(lhs, rhs) && !operator>(lhs, rhs));
}
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator<=(const SIZE &lhs, const SIZE &rhs) noexcept
{
return (operator<(lhs, rhs) || operator==(lhs, rhs));
}
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator==(const RECT &lhs, const RECT &rhs) noexcept
{
return ((lhs.left == rhs.left) && (lhs.top == rhs.top) && (lhs.right == rhs.right) && (lhs.bottom == rhs.bottom));
}
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator!=(const RECT &lhs, const RECT &rhs) noexcept
{
return !operator==(lhs, rhs);
}
[[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
#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
# define Q_DISABLE_COPY_MOVE(Class) \
Q_DISABLE_COPY(Class) \
Class(Class &&) = delete; \
Class &operator=(Class &&) = delete;
Q_DISABLE_MOVE(Class)
#endif
#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
@ -253,6 +258,83 @@ QT_END_NAMESPACE
}
#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)
// 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.

View File

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

View File

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

View File

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

View File

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

View File

@ -25,7 +25,10 @@
#pragma once
#include <FramelessHelper/Core/framelesshelpercore_global.h>
#include <QtCore/qhash.h>
#include <QtGui/qwindowdefs.h>
#include <functional>
#include <memory>
QT_BEGIN_NAMESPACE
class QScreen;
@ -62,7 +65,7 @@ using GetWidgetHandleCallback = std::function<QObject *()>;
using ForceChildrenRepaintCallback = std::function<void(const int)>;
using ResetQtGrabbedControlCallback = std::function<bool()>;
struct SystemParameters
struct FRAMELESSHELPER_CORE_API FramelessCallbacks
{
GetWindowFlagsCallback getWindowFlags = nullptr;
SetWindowFlagsCallback setWindowFlags = nullptr;
@ -92,29 +95,90 @@ struct SystemParameters
GetWidgetHandleCallback getWidgetHandle = nullptr;
ForceChildrenRepaintCallback forceChildrenRepaint = 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 *;
using FramelessParamsConst = const SystemParameters *;
using FramelessParamsRef = SystemParameters &;
using FramelessParamsConstRef = const SystemParameters &;
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
inline uint qHash(const ExtraDataType key, const uint seed = 0) noexcept {
return ::qHash(static_cast<quint8>(key), seed);
}
#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
#define DECLARE_SIZE_COMPARE_OPERATORS(Type1, Type2) \
[[maybe_unused]] [[nodiscard]] static inline constexpr bool operator>(const Type1 &lhs, const Type2 &rhs) noexcept \
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator>(const Type1 &lhs, const Type2 &rhs) noexcept \
{ \
return ((lhs.width() * lhs.height()) > (rhs.width() * rhs.height())); \
} \
[[maybe_unused]] [[nodiscard]] static inline constexpr bool operator>=(const Type1 &lhs, const Type2 &rhs) noexcept \
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator>=(const Type1 &lhs, const Type2 &rhs) noexcept \
{ \
return (operator>(lhs, rhs) || operator==(lhs, rhs)); \
} \
[[maybe_unused]] [[nodiscard]] static inline constexpr bool operator<(const Type1 &lhs, const Type2 &rhs) noexcept \
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator<(const Type1 &lhs, const Type2 &rhs) noexcept \
{ \
return (operator!=(lhs, rhs) && !operator>(lhs, rhs)); \
} \
[[maybe_unused]] [[nodiscard]] static inline constexpr bool operator<=(const Type1 &lhs, const Type2 &rhs) noexcept \
[[maybe_unused]] [[nodiscard]] inline constexpr bool operator<=(const Type1 &lhs, const Type2 &rhs) noexcept \
{ \
return (operator<(lhs, rhs) || operator==(lhs, rhs)); \
}
DECLARE_SIZE_COMPARE_OPERATORS(QSize, QSize)
DECLARE_SIZE_COMPARE_OPERATORS(QSizeF, QSizeF)
DECLARE_SIZE_COMPARE_OPERATORS(QSize, QSizeF)
DECLARE_SIZE_COMPARE_OPERATORS(QSizeF, QSize)

View File

@ -30,23 +30,19 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
struct SystemParameters;
class FramelessManager;
struct FramelessData;
using FramelessDataPtr = std::shared_ptr<FramelessData>;
class FramelessManager;
class FRAMELESSHELPER_CORE_API FramelessManagerPrivate : public QObject
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DECLARE_PUBLIC(FramelessManager)
Q_DISABLE_COPY_MOVE(FramelessManagerPrivate)
FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessManager)
public:
explicit FramelessManagerPrivate(FramelessManager *q);
~FramelessManagerPrivate() override;
Q_NODISCARD static FramelessManagerPrivate *get(FramelessManager *pub);
Q_NODISCARD static const FramelessManagerPrivate *get(const FramelessManager *pub);
static void initializeIconFont();
Q_NODISCARD static QFont getIconFont();
@ -60,7 +56,12 @@ public:
void doNotifySystemThemeHasChangedOrNot();
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;
std::optional<Global::SystemTheme> overrideTheme = std::nullopt;
QColor accentColor = {};

View File

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

View File

@ -60,8 +60,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_CORE_API RegistryKey : public QObject
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DISABLE_COPY_MOVE(RegistryKey)
FRAMELESSHELPER_QT_CLASS(RegistryKey)
public:
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
{
Q_DISABLE_COPY(ScopeGuard)
FRAMELESSHELPER_CLASS(ScopeGuard)
public:
ScopeGuard()

View File

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

View File

@ -32,22 +32,15 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
class WindowBorderPainter;
class FRAMELESSHELPER_CORE_API WindowBorderPainterPrivate : public QObject
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DECLARE_PUBLIC(WindowBorderPainter)
Q_DISABLE_COPY_MOVE(WindowBorderPainterPrivate)
FRAMELESSHELPER_PRIVATE_QT_CLASS(WindowBorderPainter)
public:
explicit WindowBorderPainterPrivate(WindowBorderPainter *q);
~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<Global::WindowEdges> edges = std::nullopt;
std::optional<QColor> activeColor = std::nullopt;

View File

@ -37,30 +37,22 @@ QT_END_NAMESPACE
FRAMELESSHELPER_BEGIN_NAMESPACE
struct SystemParameters;
namespace Utils
{
[[nodiscard]] FRAMELESSHELPER_CORE_API
Qt::CursorShape calculateCursorShape(const QWindow *window, const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API
Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::CursorShape calculateCursorShape(const QWindow *window, const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool startSystemMove(QWindow *window, const QPoint &globalPos);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool startSystemResize(QWindow *window, const Qt::Edges edges, const QPoint &globalPos);
[[nodiscard]] FRAMELESSHELPER_CORE_API QString getSystemButtonGlyph(const Global::SystemButtonType button);
[[nodiscard]] FRAMELESSHELPER_CORE_API QWindow *findWindow(const WId windowId);
FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
const SystemParameters *params, const bool considerTaskBar);
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::WindowState windowStatesToWindowState(
const Qt::WindowStates states);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool moveWindowToDesktopCenter(const WId windowId, const bool considerTaskBar);
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::WindowState windowStatesToWindowState(const Qt::WindowStates states);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isThemeChangeEvent(const QEvent * const event);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor calculateSystemButtonBackgroundColor(
const Global::SystemButtonType button, const Global::ButtonState state);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor calculateSystemButtonBackgroundColor(const Global::SystemButtonType button, const Global::ButtonState state);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool
setBlurBehindWindowEnabled(const WId windowId, const Global::BlurMode mode, const QColor &color);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool setBlurBehindWindowEnabled(const WId windowId, const Global::BlurMode mode, const QColor &color);
[[nodiscard]] FRAMELESSHELPER_CORE_API QString getWallpaperFilePath();
[[nodiscard]] FRAMELESSHELPER_CORE_API Global::WallpaperAspectStyle getWallpaperAspectStyle();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isBlurBehindWindowSupported();
@ -100,31 +92,24 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFullScreen(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowNoState(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool syncWmPaintWithDwm();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool showSystemMenu(
const WId windowId, const QPoint &pos,
const bool selectFirstEntry, const SystemParameters *params);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool showSystemMenu(const WId windowId, const QPoint &pos, const bool selectFirstEntry);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmColorizationColor(bool *opaque = nullptr, bool *ok = nullptr);
[[nodiscard]] FRAMELESSHELPER_CORE_API Global::DwmColorizationArea getDwmColorizationArea();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isHighContrastModeEnabled();
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getPrimaryScreenDpi(const bool horizontal);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getWindowDpi(const WId windowId, const bool horizontal);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThicknessForDpi
(const bool horizontal, const quint32 dpi);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThickness(const WId windowId,
const bool horizontal,
const bool scaled);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThicknessForDpi(const bool horizontal, const quint32 dpi);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getResizeBorderThickness(const WId windowId, const bool horizontal, const bool scaled);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getCaptionBarHeightForDpi(const quint32 dpi);
[[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 getTitleBarHeight(const WId windowId, const bool scaled);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThicknessForDpi(const quint32 dpi);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const WId windowId,
const bool scaled);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const WId windowId, const bool scaled);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool maybeFixupQtInternals(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFrameBorderVisible();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool installWindowProcHook(
const WId windowId, const SystemParameters *params);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool installWindowProcHook(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 tryToEnableHighestDpiAwarenessLevel();
@ -132,20 +117,17 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_windows();
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_windows();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool setCornerStyleForWindow(const WId windowId, const Global::WindowCornerStyle style);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool hideOriginalTitleBarElements
(const WId windowId, const bool disable = true);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool hideOriginalTitleBarElements(const WId windowId, const bool disable = true);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool setQtDarkModeAwareEnabled(const bool enable);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool refreshWin32ThemeResources(const WId windowId, const bool dark);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool enableNonClientAreaDpiScalingForWindow(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API
Global::DpiAwareness getDpiAwarenessForCurrentProcess(bool *highest = nullptr);
[[nodiscard]] FRAMELESSHELPER_CORE_API Global::DpiAwareness getDpiAwarenessForCurrentProcess(bool *highest = nullptr);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool fixupChildWindowsDpiMessage(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool fixupDialogsDpiScaling();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool setDarkModeAllowedForApp(const bool allow = true);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool bringWindowToFront(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool removeMicaWindow(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint64 getKeyState();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isValidWindow(const WId windowId, const bool checkVisible, const bool checkTopLevel);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool updateFramebufferTransparency(const WId windowId);
@ -156,8 +138,7 @@ FRAMELESSHELPER_CORE_API void printWin32Message(void *msg);
#endif // Q_OS_WINDOWS
#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
[[nodiscard]] FRAMELESSHELPER_CORE_API QScreen *x11_findScreenForVirtualDesktop
(const int virtualDesktopNumber);
[[nodiscard]] FRAMELESSHELPER_CORE_API QScreen *x11_findScreenForVirtualDesktop(const int virtualDesktopNumber);
[[nodiscard]] FRAMELESSHELPER_CORE_API x11_return_type x11_appRootWindow(const int screen);
[[nodiscard]] FRAMELESSHELPER_CORE_API int x11_appScreen();
[[nodiscard]] FRAMELESSHELPER_CORE_API x11_return_type x11_appTime();
@ -166,11 +147,8 @@ FRAMELESSHELPER_CORE_API void printWin32Message(void *msg);
[[nodiscard]] FRAMELESSHELPER_CORE_API QByteArray x11_nextStartupId();
[[nodiscard]] FRAMELESSHELPER_CORE_API Display *x11_display();
[[nodiscard]] FRAMELESSHELPER_CORE_API xcb_connection_t *x11_connection();
[[nodiscard]] FRAMELESSHELPER_CORE_API QByteArray getWindowProperty
(const WId windowId, const xcb_atom_t prop, const xcb_atom_t type, const quint32 data_len);
FRAMELESSHELPER_CORE_API void setWindowProperty
(const WId windowId, const xcb_atom_t prop, const xcb_atom_t type,
const void *data, const quint32 data_len, const uint8_t format);
[[nodiscard]] FRAMELESSHELPER_CORE_API QByteArray getWindowProperty(const WId windowId, const xcb_atom_t prop, const xcb_atom_t type, const quint32 data_len);
FRAMELESSHELPER_CORE_API void setWindowProperty(const WId windowId, const xcb_atom_t prop, const xcb_atom_t type, const void *data, const quint32 data_len, const uint8_t format);
FRAMELESSHELPER_CORE_API void clearWindowProperty(const WId windowId, const xcb_atom_t prop);
[[nodiscard]] FRAMELESSHELPER_CORE_API xcb_atom_t internAtom(const char *name);
[[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);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_linux();
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_linux();
FRAMELESSHELPER_CORE_API void sendMoveResizeMessage
(const WId windowId, const uint32_t action, const QPoint &globalPos, const Qt::MouseButton button = Qt::LeftButton);
FRAMELESSHELPER_CORE_API void sendMoveResizeMessage(const 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
setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &props);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &props);
#endif // Q_OS_LINUX
#ifdef Q_OS_MACOS

View File

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

View File

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

View File

@ -36,20 +36,18 @@ class QuickMicaMaterial;
#if FRAMELESSHELPER_CONFIG(border_painter)
class QuickWindowBorder;
#endif
class FramelessQuickHelperPrivate;
class FramelessQuickHelperPrivate;
class FRAMELESSHELPER_QUICK_API FramelessQuickHelper : public QQuickItem
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessQuickHelper)
#ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(FramelessHelper)
#endif
#ifdef QML_ATTACHED
QML_ATTACHED(FramelessQuickHelper)
#endif
Q_DECLARE_PRIVATE(FramelessQuickHelper)
Q_DISABLE_COPY_MOVE(FramelessQuickHelper)
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 blurBehindWindowEnabled READ isBlurBehindWindowEnabled WRITE setBlurBehindWindowEnabled NOTIFY blurBehindWindowEnabledChanged FINAL)
@ -109,9 +107,6 @@ Q_SIGNALS:
void blurBehindWindowEnabledChanged();
void windowChanged2();
void ready();
private:
QScopedPointer<FramelessQuickHelperPrivate> d_ptr;
};
FRAMELESSHELPER_END_NAMESPACE

View File

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

View File

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

View File

@ -35,23 +35,17 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
#if FRAMELESSHELPER_CONFIG(border_painter)
class QuickWindowBorder;
#endif
class FramelessQuickApplicationWindow;
class FramelessQuickApplicationWindow;
class FRAMELESSHELPER_QUICK_API FramelessQuickApplicationWindowPrivate : public QObject
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DECLARE_PUBLIC(FramelessQuickApplicationWindow)
Q_DISABLE_COPY_MOVE(FramelessQuickApplicationWindowPrivate)
FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessQuickApplicationWindow)
public:
explicit FramelessQuickApplicationWindowPrivate(FramelessQuickApplicationWindow *q);
~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;
#if FRAMELESSHELPER_CONFIG(border_painter)
QuickWindowBorder *windowBorder = nullptr;

View File

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

View File

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

View File

@ -35,23 +35,17 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
#if FRAMELESSHELPER_CONFIG(border_painter)
class QuickWindowBorder;
#endif
class FramelessQuickWindow;
class FramelessQuickWindow;
class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DECLARE_PUBLIC(FramelessQuickWindow)
Q_DISABLE_COPY_MOVE(FramelessQuickWindowPrivate)
FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessQuickWindow)
public:
explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q);
~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;
#if FRAMELESSHELPER_CONFIG(border_painter)
QuickWindowBorder *windowBorder = nullptr;

View File

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

View File

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

View File

@ -40,11 +40,10 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_QUICK_API QuickStandardSystemButton : public QQuickButton
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
FRAMELESSHELPER_QT_CLASS(QuickStandardSystemButton)
#ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(StandardSystemButton)
#endif
Q_DISABLE_COPY_MOVE(QuickStandardSystemButton)
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(QColor hoverColor READ hoverColor WRITE setHoverColor NOTIFY hoverColorChanged FINAL)

View File

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

View File

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

View File

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

View File

@ -32,16 +32,13 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
class QuickMicaMaterialPrivate;
class FRAMELESSHELPER_QUICK_API QuickMicaMaterial : public QQuickPaintedItem
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
FRAMELESSHELPER_PUBLIC_QT_CLASS(QuickMicaMaterial)
#ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(MicaMaterial)
#endif
Q_DISABLE_COPY_MOVE(QuickMicaMaterial)
Q_DECLARE_PRIVATE(QuickMicaMaterial)
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged 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 classBegin() override;
void componentComplete() override;
private:
QScopedPointer<QuickMicaMaterialPrivate> d_ptr;
};
FRAMELESSHELPER_END_NAMESPACE

View File

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

View File

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

View File

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

View File

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

View File

@ -35,14 +35,12 @@ class MicaMaterial;
#if FRAMELESSHELPER_CONFIG(border_painter)
class WindowBorderPainter;
#endif
class FramelessWidgetsHelperPrivate;
class FramelessWidgetsHelperPrivate;
class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelper : public QObject
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DECLARE_PRIVATE(FramelessWidgetsHelper)
Q_DISABLE_COPY_MOVE(FramelessWidgetsHelper)
FRAMELESSHELPER_PUBLIC_QT_CLASS(FramelessWidgetsHelper)
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 blurBehindWindowEnabled READ isBlurBehindWindowEnabled WRITE setBlurBehindWindowEnabled NOTIFY blurBehindWindowEnabledChanged FINAL)
@ -96,9 +94,6 @@ Q_SIGNALS:
void blurBehindWindowEnabledChanged();
void windowChanged();
void ready();
private:
QScopedPointer<FramelessWidgetsHelperPrivate> d_ptr;
};
FRAMELESSHELPER_END_NAMESPACE

View File

@ -30,24 +30,18 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessDialog;
class WidgetsSharedHelper;
class FramelessDialog;
class FRAMELESSHELPER_WIDGETS_API FramelessDialogPrivate : public QObject
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DECLARE_PUBLIC(FramelessDialog)
Q_DISABLE_COPY_MOVE(FramelessDialogPrivate)
FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessDialog)
public:
explicit FramelessDialogPrivate(FramelessDialog *q);
~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;
};

View File

@ -30,24 +30,18 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessMainWindow;
class WidgetsSharedHelper;
class FramelessMainWindow;
class FRAMELESSHELPER_WIDGETS_API FramelessMainWindowPrivate : public QObject
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DECLARE_PUBLIC(FramelessMainWindow)
Q_DISABLE_COPY_MOVE(FramelessMainWindowPrivate)
FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessMainWindow)
public:
explicit FramelessMainWindowPrivate(FramelessMainWindow *q);
~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;
WidgetsSharedHelper *sharedHelper = nullptr;
};

View File

@ -30,24 +30,18 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessWidget;
class WidgetsSharedHelper;
class FramelessWidget;
class FRAMELESSHELPER_WIDGETS_API FramelessWidgetPrivate : public QObject
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DECLARE_PUBLIC(FramelessWidget)
Q_DISABLE_COPY_MOVE(FramelessWidgetPrivate)
FRAMELESSHELPER_PRIVATE_QT_CLASS(FramelessWidget)
public:
explicit FramelessWidgetPrivate(FramelessWidget *q);
~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;
WidgetsSharedHelper *sharedHelper = nullptr;
};

View File

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

View File

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

View File

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

View File

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

View File

@ -32,13 +32,10 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
class StandardSystemButtonPrivate;
class FRAMELESSHELPER_WIDGETS_API StandardSystemButton : public QPushButton
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DECLARE_PRIVATE(StandardSystemButton)
Q_DISABLE_COPY_MOVE(StandardSystemButton)
FRAMELESSHELPER_PUBLIC_QT_CLASS(StandardSystemButton)
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(QColor hoverColor READ hoverColor WRITE setHoverColor NOTIFY hoverColorChanged FINAL)
@ -89,9 +86,6 @@ Q_SIGNALS:
void inactiveForegroundColorChanged();
void activeChanged();
void glyphSizeChanged();
private:
QScopedPointer<StandardSystemButtonPrivate> d_ptr;
};
FRAMELESSHELPER_END_NAMESPACE

View File

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

View File

@ -35,18 +35,18 @@ if(UNIX AND NOT APPLE)
endif()
find_package(X11 QUIET COMPONENTS xcb)
if(TARGET X11::xcb)
message("Found system XCB. The XCB wrapper will be disabled.")
message(STATUS "--- Found system XCB. The XCB wrapper will be disabled.")
else()
message("System XCB not found. The XCB wrapper will be used instead.")
message(STATUS "--- System XCB not found. The XCB wrapper will be used instead.")
endif()
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
pkg_check_modules(GTK3 QUIET IMPORTED_TARGET gtk+-3.0)
endif()
if(TARGET PkgConfig::GTK3)
message("Found system GTK. The GTK wrapper will be disabled.")
message(STATUS "--- Found system GTK. The GTK wrapper will be disabled.")
else()
message("System GTK not found. The GTK wrapper will be used instead.")
message(STATUS "--- System GTK not found. The GTK wrapper will be used instead.")
endif()
endif()
@ -61,14 +61,12 @@ set(PUBLIC_HEADERS
${FRAMELESSHELPER_VERSION_FILE}
${FRAMELESSHELPER_CONFIG_FILE}
${INCLUDE_PREFIX}/framelesshelpercore_global.h
${INCLUDE_PREFIX}/framelesshelper_qt.h
${INCLUDE_PREFIX}/framelessmanager.h
${INCLUDE_PREFIX}/utils.h
)
set(PUBLIC_HEADERS_ALIAS
${INCLUDE_PREFIX}/Global
${INCLUDE_PREFIX}/FramelessHelper_Qt
${INCLUDE_PREFIX}/FramelessManager
${INCLUDE_PREFIX}/Utils
)
@ -84,7 +82,6 @@ set(PRIVATE_HEADERS
set(SOURCES
utils.cpp
framelesshelper_qt.cpp
framelessmanager.cpp
framelessconfig.cpp
sysapiloader.cpp
@ -92,14 +89,8 @@ set(SOURCES
)
if(WIN32)
list(APPEND PUBLIC_HEADERS
${INCLUDE_PREFIX}/framelesshelper_windows.h
${INCLUDE_PREFIX}/framelesshelper_win.h
)
list(APPEND PUBLIC_HEADERS_ALIAS
${INCLUDE_PREFIX}/FramelessHelper_Windows
${INCLUDE_PREFIX}/FramelessHelper_Win
)
list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_windows.h)
list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Windows)
list(APPEND PRIVATE_HEADERS
${INCLUDE_PREFIX}/private/registrykey_p.h
${INCLUDE_PREFIX}/private/winverhelper_p.h
@ -107,25 +98,35 @@ if(WIN32)
list(APPEND SOURCES
registrykey.cpp
utils_win.cpp
framelesshelper_win.cpp
winverhelper.cpp
platformsupport_win.cpp
)
elseif(APPLE)
list(APPEND SOURCES utils_mac.mm)
elseif(UNIX)
list(APPEND PUBLIC_HEADERS
${INCLUDE_PREFIX}/framelesshelper_linux.h
)
list(APPEND PUBLIC_HEADERS_ALIAS
${INCLUDE_PREFIX}/FramelessHelper_Linux
)
list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_linux.h)
list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Linux)
list(APPEND SOURCES
utils_linux.cpp
platformsupport_linux.cpp
)
endif()
if(FRAMELESSHELPER_NATIVE_IMPL)
if(WIN32)
list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_win.h)
list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Win)
list(APPEND SOURCES framelesshelper_win.cpp)
elseif(APPLE)
elseif(UNIX)
else()
endif()
else()
list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/framelesshelper_qt.h)
list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/FramelessHelper_Qt)
list(APPEND SOURCES framelesshelper_qt.cpp)
endif()
if(NOT FRAMELESSHELPER_NO_TITLEBAR)
list(APPEND PUBLIC_HEADERS ${INCLUDE_PREFIX}/chromepalette.h)
list(APPEND PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/ChromePalette)
@ -158,7 +159,7 @@ if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
COPYRIGHT "MIT License"
ORIGINAL_FILENAME "${SUB_MODULE_FULL_NAME}.dll"
PRODUCT "${PROJECT_NAME}"
COMMENTS "Built from commit ${PROJECT_VERSION_COMMIT} on ${PROJECT_COMPILE_DATETIME} (UTC)."
COMMENTS "Who don't love Raiden Shogun ?"
LIBRARY
)
endif()

View File

@ -85,14 +85,14 @@ Q_GLOBAL_STATIC(FramelessConfigData, g_framelessConfigData)
static inline void warnInappropriateOptions()
{
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
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
if (cfg->isSet(Option::UseCrossPlatformQtImplementation)) {
WARNING << "Option::UseCrossPlatformQtImplementation is default on non-Windows platforms.";
}
if (cfg->isSet(Option::ForceHideWindowFrameBorder)) {
WARNING << "Option::ForceHideWindowFrameBorder is only available on Windows.";
}

View File

@ -23,6 +23,9 @@
*/
#include "framelesshelper_qt.h"
#if !FRAMELESSHELPER_CONFIG(native_impl)
#include "framelessmanager.h"
#include "framelessmanager_p.h"
#include "framelessconfig_p.h"
@ -49,40 +52,80 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global;
struct FramelessQtHelperData
struct FramelessDataQt : public FramelessData
{
SystemParameters params = {};
FramelessHelperQt *eventFilter = nullptr;
FramelessHelperQt *framelessHelperImpl = nullptr;
bool cursorShapeChanged = 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;
void FramelessHelperQt::addWindow(FramelessParamsConst params)
void FramelessHelperQt::addWindow(const QObject *window)
{
Q_ASSERT(params);
if (!params) {
Q_ASSERT(window);
if (!window) {
return;
}
const WId windowId = params->getWindowId();
const auto it = g_framelessQtHelperData()->constFind(windowId);
if (it != g_framelessQtHelperData()->constEnd()) {
const FramelessDataQtPtr data = tryGetData(window);
if (!data || data->frameless || !data->callbacks) {
return;
}
FramelessQtHelperData data = {};
data.params = *params;
QWindow *window = params->getWindowHandle();
// Give it a parent so that it can be automatically deleted by Qt.
data.eventFilter = new FramelessHelperQt(window);
g_framelessQtHelperData()->insert(windowId, data);
const auto shouldApplyFramelessFlag = []() -> bool {
QWindow *qWindow = data->callbacks->getWindowHandle();
Q_ASSERT(qWindow);
if (!qWindow) {
return;
}
data->frameless = true;
static const auto shouldApplyFramelessFlag = []() -> bool {
#ifdef Q_OS_MACOS
return false;
#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
@ -92,35 +135,47 @@ void FramelessHelperQt::addWindow(FramelessParamsConst params)
#endif // Q_OS_MACOS
}();
#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)))
if (shouldApplyFramelessFlag) {
params->setWindowFlags(params->getWindowFlags() | Qt::FramelessWindowHint);
data->callbacks->setWindowFlags(data->callbacks->getWindowFlags() | Qt::FramelessWindowHint);
} else {
#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
std::ignore = Utils::tryHideSystemTitleBar(windowId, true);
std::ignore = Utils::tryHideSystemTitleBar(data->callbacks->getWindowId(), true);
#elif defined(Q_OS_MACOS)
Utils::setSystemTitleBarVisible(windowId, false);
Utils::setSystemTitleBarVisible(data->callbacks->getWindowId(), false);
#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();
}
void FramelessHelperQt::removeWindow(const WId windowId)
void FramelessHelperQt::removeWindow(const QObject *window)
{
Q_ASSERT(windowId);
if (!windowId) {
Q_ASSERT(window);
if (!window) {
return;
}
const auto it = g_framelessQtHelperData()->constFind(windowId);
if (it == g_framelessQtHelperData()->constEnd()) {
const FramelessDataQtPtr data = tryGetData(window);
if (!data || !data->frameless || !data->callbacks) {
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
Utils::removeWindowProxy(windowId);
#endif
Utils::removeWindowProxy(data->callbacks->getWindowId());
#endif // Q_OS_MACOS
}
bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
@ -131,24 +186,22 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
return false;
}
#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)) {
// Sometimes the FramelessManager instance may be destroyed already.
if (FramelessManager * const manager = FramelessManager::instance()) {
if (FramelessManagerPrivate * const managerPriv = FramelessManagerPrivate::get(manager)) {
if (FramelessManager *manager = FramelessManager::instance()) {
if (FramelessManagerPrivate *managerPriv = FramelessManagerPrivate::get(manager)) {
managerPriv->notifySystemThemeHasChangedOrNot();
}
}
return QObject::eventFilter(object, event);
return false;
}
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0))
// We are only interested in events that are dispatched to top level windows.
if (!object->isWindowType()) {
return QObject::eventFilter(object, event);
Q_D(FramelessHelperQt);
if (!d->window || !object->isWindowType()) {
return false;
}
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)
&& (type != QEvent::MouseButtonDblClick) && (type != QEvent::MouseMove)
#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.
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
) {
return QObject::eventFilter(object, event);
return false;
}
const auto window = qobject_cast<QWindow *>(object);
const WId windowId = window->winId();
const auto it = g_framelessQtHelperData()->find(windowId);
if (it == g_framelessQtHelperData()->end()) {
return QObject::eventFilter(object, event);
const FramelessDataQtPtr data = tryGetData(d->window);
if (!data || !data->frameless || !data->callbacks) {
return false;
}
const FramelessQtHelperData &data = it.value();
FramelessQtHelperData &muData = it.value();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
if (type == QEvent::DevicePixelRatioChange)
#else // QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
if (type == QEvent::ScreenChangeInternal)
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
{
data.params.forceChildrenRepaint(500);
return QObject::eventFilter(object, event);
data->callbacks->forceChildrenRepaint(500);
return false;
}
const auto qWindow = qobject_cast<QWindow *>(object);
const auto mouseEvent = static_cast<QMouseEvent *>(event);
const Qt::MouseButton button = mouseEvent->button();
#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 globalPos = mouseEvent->screenPos().toPoint();
#endif
const bool windowFixedSize = data.params.isWindowFixedSize();
const bool ignoreThisEvent = data.params.shouldIgnoreMouseEvents(scenePos);
const bool insideTitleBar = data.params.isInsideTitleBarDraggableArea(scenePos);
const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool();
const bool dontToggleMaximize = data.params.getProperty(kDontToggleMaximizeVar, false).toBool();
const bool windowFixedSize = data->callbacks->isWindowFixedSize();
const bool ignoreThisEvent = data->callbacks->shouldIgnoreMouseEvents(scenePos);
const bool insideTitleBar = data->callbacks->isInsideTitleBarDraggableArea(scenePos);
const bool dontOverrideCursor = data->callbacks->getProperty(kDontOverrideCursorVar, false).toBool();
const bool dontToggleMaximize = data->callbacks->getProperty(kDontToggleMaximizeVar, false).toBool();
switch (type) {
case QEvent::MouseButtonPress: {
case QEvent::MouseButtonPress:
if (button == Qt::LeftButton) {
muData.leftButtonPressed = true;
data->leftButtonPressed = true;
if (!windowFixedSize) {
const Qt::Edges edges = Utils::calculateWindowEdges(window, scenePos);
const Qt::Edges edges = Utils::calculateWindowEdges(qWindow, scenePos);
if (edges != Qt::Edges{}) {
std::ignore = Utils::startSystemResize(window, edges, globalPos);
std::ignore = Utils::startSystemResize(qWindow, edges, globalPos);
event->accept();
return true;
}
}
}
} break;
case QEvent::MouseButtonRelease: {
break;
case QEvent::MouseButtonRelease:
if (button == Qt::LeftButton) {
muData.leftButtonPressed = false;
}
if (button == Qt::RightButton) {
data->leftButtonPressed = false;
} else if (button == Qt::RightButton) {
if (!ignoreThisEvent && insideTitleBar) {
data.params.showSystemMenu(globalPos);
data->callbacks->showSystemMenu(globalPos);
event->accept();
return true;
}
}
} break;
case QEvent::MouseButtonDblClick: {
break;
case QEvent::MouseButtonDblClick:
if (!dontToggleMaximize && (button == Qt::LeftButton) && !windowFixedSize && !ignoreThisEvent && insideTitleBar) {
Qt::WindowState newWindowState = Qt::WindowNoState;
if (data.params.getWindowState() != Qt::WindowMaximized) {
if (data->callbacks->getWindowState() != Qt::WindowMaximized) {
newWindowState = Qt::WindowMaximized;
}
data.params.setWindowState(newWindowState);
data->callbacks->setWindowState(newWindowState);
event->accept();
return true;
}
} break;
break;
case QEvent::MouseMove: {
if (!dontOverrideCursor && !windowFixedSize) {
const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos);
const Qt::CursorShape cs = Utils::calculateCursorShape(qWindow, scenePos);
if (cs == Qt::ArrowCursor) {
if (data.cursorShapeChanged) {
data.params.unsetCursor();
muData.cursorShapeChanged = false;
if (data->cursorShapeChanged) {
data->callbacks->unsetCursor();
data->cursorShapeChanged = false;
}
} else {
data.params.setCursor(cs);
muData.cursorShapeChanged = true;
data->callbacks->setCursor(cs);
data->cursorShapeChanged = true;
}
}
if (data.leftButtonPressed) {
if (data->leftButtonPressed) {
if (!ignoreThisEvent && insideTitleBar) {
std::ignore = Utils::startSystemMove(window, globalPos);
std::ignore = Utils::startSystemMove(qWindow, globalPos);
event->accept();
return true;
}
@ -251,7 +300,9 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
default:
break;
}
return QObject::eventFilter(object, event);
return false;
}
FRAMELESSHELPER_END_NAMESPACE
#endif // !native_impl

View File

@ -26,6 +26,8 @@
#ifdef Q_OS_WINDOWS
#if FRAMELESSHELPER_CONFIG(native_impl)
#include "framelessmanager.h"
#include "framelessmanager_p.h"
#include "framelessconfig_p.h"
@ -60,7 +62,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global;
static constexpr const auto kMessageTag = WPARAM(2546789017);
static constexpr const auto kMessageTag = WPARAM(0x97CCEA99);
FRAMELESSHELPER_STRING_CONSTANT(MonitorFromWindow)
FRAMELESSHELPER_STRING_CONSTANT(GetMonitorInfoW)
@ -100,9 +102,8 @@ enum class WindowPart : quint8
TitleBar
};
struct FramelessWin32HelperData
struct FramelessDataWin : public FramelessData
{
SystemParameters params = {};
// Store the last hit test result, it's helpful to handle WM_MOUSEMOVE and WM_NCMOUSELEAVE.
WindowPart lastHitTestResult = WindowPart::Outside;
// True if we blocked a WM_MOUSELEAVE when mouse moves on chrome button, false when a
@ -112,36 +113,39 @@ struct FramelessWin32HelperData
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
QRect restoreGeometry = {};
#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;
QHash<WId, FramelessWin32HelperData> data = {};
return std::make_shared<FramelessDataWin>();
}
[[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(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);
Q_GLOBAL_STATIC(FramelessHelperWinInternal, g_internalData)
[[nodiscard]] extern std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd);
@ -212,49 +216,48 @@ FramelessHelperWin::FramelessHelperWin() : QAbstractNativeEventFilter() {}
FramelessHelperWin::~FramelessHelperWin() = default;
void FramelessHelperWin::addWindow(FramelessParamsConst params)
void FramelessHelperWin::addWindow(const QObject *window)
{
Q_ASSERT(params);
if (!params) {
Q_ASSERT(window);
if (!window) {
return;
}
const WId windowId = params->getWindowId();
const auto it = g_framelessWin32HelperData()->data.constFind(windowId);
if (it != g_framelessWin32HelperData()->data.constEnd()) {
const FramelessDataWinPtr data = tryGetData(window);
if (!data || data->frameless || !data->callbacks) {
return;
}
FramelessWin32HelperData data = {};
data.params = *params;
data.dpi = {Utils::getWindowDpi(windowId, true), Utils::getWindowDpi(windowId, false)};
g_framelessWin32HelperData()->data.insert(windowId, data);
if (!g_framelessWin32HelperData()->nativeEventFilter) {
g_framelessWin32HelperData()->nativeEventFilter = std::make_unique<FramelessHelperWin>();
qApp->installNativeEventFilter(g_framelessWin32HelperData()->nativeEventFilter.get());
QWindow *qWindow = data->callbacks->getWindowHandle();
Q_ASSERT(qWindow);
if (!qWindow) {
return;
}
DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data.dpi;
const QWindow *window = params->getWindowHandle();
data->frameless = true;
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).
std::ignore = Utils::maybeFixupQtInternals(windowId);
std::ignore = Utils::maybeFixupQtInternals(data->windowId);
#if 0
params->setWindowFlags(params->getWindowFlags() | Qt::FramelessWindowHint);
data->callbacks->setWindowFlags(data->callbacks->getWindowFlags() | Qt::FramelessWindowHint);
#else
// Qt maintains a frame margin internally, we need to update it accordingly
// otherwise we'll get lots of warning messages when we change the window
// geometry, it will also affect the final window geometry because QPA will
// 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
// 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.
std::ignore = Utils::hideOriginalTitleBarElements(windowId);
std::ignore = Utils::hideOriginalTitleBarElements(data->windowId);
// Without this hack, the child windows can't get DPI change messages from
// Windows, which means only the top level windows can be scaled to the correct
// size, we of course don't want such thing from happening.
std::ignore = Utils::fixupChildWindowsDpiMessage(windowId);
std::ignore = Utils::fixupChildWindowsDpiMessage(data->windowId);
#if 0 // Conflicts with our blur mode setting.
if (Utils::isWindowAccelerated(window) && Utils::isWindowTransparent(window)) {
std::ignore = Utils::updateFramebufferTransparency(windowId);
// If we are using 3D APIs (D3D, Vulkan, OpenGL, etc) to draw the window content,
// we need to setup the DWM rendering policy as well.
if (Utils::isWindowAccelerated(qWindow) && Utils::isWindowTransparent(qWindow)) {
std::ignore = Utils::updateFramebufferTransparency(data->windowId);
}
#endif
if (WindowsVersionHelper::isWin10RS1OrGreater()) {
@ -262,42 +265,33 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
FramelessHelperEnableThemeAware();
if (WindowsVersionHelper::isWin10RS5OrGreater()) {
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
const auto isWidget = [params]() -> bool {
const QObject *widget = params->getWidgetHandle();
const auto isWidget = [&data]() -> bool {
const QObject *widget = data->callbacks->getWidgetHandle();
return (widget && widget->isWidgetType());
}();
if (!isWidget) {
// Tell UXTheme we may need dark theme controls.
// Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications.
std::ignore = Utils::updateGlobalWin32ControlsTheme(windowId, dark);
std::ignore = Utils::updateGlobalWin32ControlsTheme(data->windowId, dark);
}
std::ignore = Utils::refreshWin32ThemeResources(windowId, dark);
std::ignore = Utils::refreshWin32ThemeResources(data->windowId, dark);
if (WindowsVersionHelper::isWin11OrGreater()) {
// DWM provides official API to adjust the window corner style, but only since Windows 11.
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);
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();
}
}
Q_UNUSED(window);
}
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.
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.
// WM_QUIT won't be posted to the WindowProc function.
// NOTE: WM_QUIT won't be posted to the WindowProc function.
switch (uMsg) {
case WM_CLOSE:
case WM_DESTROY:
@ -340,19 +329,30 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break;
}
const auto it = g_framelessWin32HelperData()->data.find(windowId);
if (it == g_framelessWin32HelperData()->data.end()) {
const auto windowId = reinterpret_cast<WId>(hWnd);
// Let's be extra safe.
if (!Utils::isValidWindow(windowId, false, true)) {
return false;
}
const FramelessWin32HelperData &data = it.value();
FramelessWin32HelperData &muData = it.value();
const QWindow *window = data.params.getWindowHandle();
const QObject *window = FramelessManagerPrivate::getWindow(windowId);
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 WPARAM wParam = msg->wParam;
const LPARAM lParam = msg->lParam;
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
const auto updateRestoreGeometry = [windowId, &data, &muData](const bool ignoreWindowState) -> void {
const auto updateRestoreGeometry = [windowId, &data](const bool ignoreWindowState) -> void {
if (!ignoreWindowState && !Utils::isWindowNoState(windowId)) {
return;
}
@ -361,10 +361,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
WARNING << "The calculated restore geometry is invalid.";
return;
}
if (Utils::isValidGeometry(data.restoreGeometry) && (data.restoreGeometry == rect)) {
if (Utils::isValidGeometry(data->restoreGeometry) && (data->restoreGeometry == rect)) {
return;
}
muData.restoreGeometry = rect;
data->restoreGeometry = rect;
};
#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 auto wparam = [myMsg, wParam]() -> WPARAM {
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;
}
const quint64 keyState = Utils::getKeyState();
@ -383,6 +386,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}();
const auto lparam = [myMsg, lParam, hWnd]() -> LPARAM {
if (myMsg == WM_NCMOUSELEAVE) {
// lParam is always ignored in mouse leave messages.
return 0;
}
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:
SEND_MESSAGE(hWnd, WM_XBUTTONDBLCLK, wparam, lparam);
break;
#if 0
#if 0 // ### TODO: How to handle touch events?
case WM_NCPOINTERUPDATE:
case WM_NCPOINTERDOWN:
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
// 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.
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;
if (data.params.isInsideSystemButtons(qtScenePos, &dummy)) {
muData.mouseLeaveBlocked = true;
if (data->callbacks->isInsideSystemButtons(qtScenePos, &dummy)) {
data->mouseLeaveBlocked = true;
*result = FALSE;
return true;
}
}
muData.mouseLeaveBlocked = false;
data->mouseLeaveBlocked = false;
}
switch (uMsg) {
#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,
// such as the caption bar, the scrollbars, and the menu bar. We need
// to do this explicitly and manually here (only inside WM_NCCREATE).
// 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
// be no need to do this in that case.
Utils::enableNonClientAreaDpiScalingForWindow(windowId);
} break;
std::ignore = Utils::enableNonClientAreaDpiScalingForWindow(windowId);
break;
#endif
case WM_NCCALCSIZE: {
// Windows是根据这个消息的返回值来设置窗口的客户区窗口中真正显示的内容
@ -811,8 +815,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// color, our homemade top border can almost have exactly the same
// appearance with the system's one.
const auto hitTestRecorder = qScopeGuard([&muData, &result](){
muData.lastHitTestResult = getHittedWindowPart(*result);
const auto hitTestRecorder = qScopeGuard([&data, &result](){
data->lastHitTestResult = getHittedWindowPart(*result);
});
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 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;
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
// 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.
@ -881,10 +885,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const bool full = Utils::isFullScreen(windowId);
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
const bool isTop = (nativeLocalPos.y < frameSizeY);
const bool isTitleBar = data.params.isInsideTitleBarDraggableArea(qtScenePos);
const bool isFixedSize = data.params.isWindowFixedSize();
const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool();
const bool dontToggleMaximize = data.params.getProperty(kDontToggleMaximizeVar, false).toBool();
const bool isTitleBar = data->callbacks->isInsideTitleBarDraggableArea(qtScenePos);
const bool isFixedSize = data->callbacks->isWindowFixedSize();
const bool dontOverrideCursor = data->callbacks->getProperty(kDontOverrideCursorVar, false).toBool();
const bool dontToggleMaximize = data->callbacks->getProperty(kDontToggleMaximizeVar, false).toBool();
if (dontToggleMaximize) {
static bool once = false;
@ -995,8 +999,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return true;
}
case WM_MOUSEMOVE:
if ((data.lastHitTestResult != WindowPart::ChromeButton) && data.mouseLeaveBlocked) {
muData.mouseLeaveBlocked = false;
if ((data->lastHitTestResult != WindowPart::ChromeButton) && data->mouseLeaveBlocked) {
data->mouseLeaveBlocked = false;
std::ignore = requestForMouseLeaveMessage(hWnd, false);
}
break;
@ -1013,17 +1017,17 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
case WM_NCXBUTTONDOWN:
case WM_NCXBUTTONUP:
case WM_NCXBUTTONDBLCLK:
#if 0
#if 0 // ### TODO: How to handle touch events?
case WM_NCPOINTERUPDATE:
case WM_NCPOINTERDOWN:
case WM_NCPOINTERUP:
#endif
case WM_NCMOUSEHOVER: {
const WindowPart currentWindowPart = data.lastHitTestResult;
const WindowPart currentWindowPart = data->lastHitTestResult;
if (uMsg == WM_NCMOUSEMOVE) {
if (currentWindowPart != WindowPart::ChromeButton) {
std::ignore = data.params.resetQtGrabbedControl();
if (muData.mouseLeaveBlocked) {
std::ignore = data->callbacks->resetQtGrabbedControl();
if (data->mouseLeaveBlocked) {
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
// it to `Client` before the WM_NCMOUSELEAVE comes;
// 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) {
emulateClientAreaMessage();
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);
} 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);
}
return true;
}
} break;
case WM_NCMOUSELEAVE: {
const WindowPart currentWindowPart = data.lastHitTestResult;
const WindowPart currentWindowPart = data->lastHitTestResult;
if (currentWindowPart == WindowPart::ChromeButton) {
// 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
// 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 (muData.mouseLeaveBlocked) {
muData.mouseLeaveBlocked = false;
if (data->mouseLeaveBlocked) {
data->mouseLeaveBlocked = false;
std::ignore = requestForMouseLeaveMessage(hWnd, false);
}
} else {
if (data.mouseLeaveBlocked) {
if (data->mouseLeaveBlocked) {
// 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.
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,
// but it has no bad effect.
std::ignore = data.params.resetQtGrabbedControl();
std::ignore = data->callbacks->resetQtGrabbedControl();
}
}
} break;
@ -1085,9 +1095,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// of the application a lot.
const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam);
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);
if (Utils::toNativePixels(window, window->size()) != suggestedGeometry.size()) {
if (Utils::toNativePixels(qWindow, qWindow->size()) != suggestedGeometry.size()) {
windowPos->flags |= SWP_NOCOPYBITS;
}
} break;
@ -1106,7 +1116,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
const auto newDpi = UINT(wParam);
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);
suggestedSize->cx = newSize.width();
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))
case WM_DPICHANGED: {
const Dpi oldDpi = data.dpi;
const Dpi oldDpi = data->dpi;
const Dpi newDpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))};
if (Q_UNLIKELY(newDpi == oldDpi)) {
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)
<< "is" << newDpi << "(was" << oldDpi << ").";
muData.dpi = newDpi;
data->dpi = newDpi;
#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.
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))
data.params.forceChildrenRepaint(500);
data->callbacks->forceChildrenRepaint(500);
} break;
case WM_DWMCOMPOSITIONCHANGED:
// 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) {
break;
}
if (!Utils::isValidGeometry(data.restoreGeometry)) {
if (!Utils::isValidGeometry(data->restoreGeometry)) {
updateRestoreGeometry(true);
break;
}
@ -1169,11 +1179,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break;
}
// The restore geometry is correct, no need to bother.
if (rect2qrect(wp.rcNormalPosition) == data.restoreGeometry) {
if (rect2qrect(wp.rcNormalPosition) == data->restoreGeometry) {
break;
}
// 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) {
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 ((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);
}
}
@ -1288,7 +1298,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if (WindowsVersionHelper::isWin10RS5OrGreater()) {
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
const auto isWidget = [&data]() -> bool {
const auto widget = data.params.getWidgetHandle();
const auto widget = data->callbacks->getWidgetHandle();
return (widget && widget->isWidgetType());
}();
if (!isWidget) {
@ -1319,4 +1329,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
FRAMELESSHELPER_END_NAMESPACE
#endif // native_impl
#endif // Q_OS_WINDOWS

View File

@ -114,6 +114,23 @@ using namespace Global;
static_assert(std::size(WindowsVersions) == (static_cast<int>(WindowsVersion::Latest) + 1));
#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()
{
static bool inited = false;

View File

@ -24,12 +24,20 @@
#include "framelessmanager.h"
#include "framelessmanager_p.h"
#include "framelesshelper_qt.h"
#include "framelessconfig_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"
#ifdef Q_OS_WINDOWS
# include "framelesshelper_win.h"
# include "winverhelper_p.h"
#endif
#include <QtCore/qvariant.h>
@ -37,6 +45,7 @@
#include <QtCore/qloggingcategory.h>
#include <QtGui/qfontdatabase.h>
#include <QtGui/qwindow.h>
#include <QtGui/qevent.h>
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
# include <QtGui/qguiapplication.h>
# include <QtGui/qstylehints.h>
@ -59,12 +68,26 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global;
using FramelessManagerData = QList<WId>;
Q_GLOBAL_STATIC(FramelessManagerData, g_framelessManagerData)
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)
[[nodiscard]] static inline QString iconFontFamilyName()
{
@ -83,16 +106,60 @@ static constexpr const int kEventDelayInterval = 1000;
}
#endif
[[nodiscard]] static inline bool usePureQtImplementation()
class InternalEventFilter : public QObject
{
static const auto result = []() -> bool {
#ifdef Q_OS_WINDOWS
return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
#else
return true;
#endif
}();
return result;
Q_OBJECT
FRAMELESSHELPER_QT_CLASS(InternalEventFilter)
public:
explicit InternalEventFilter(const QObject *window, QObject *parent = nullptr);
~InternalEventFilter() override;
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)
@ -133,7 +200,7 @@ void FramelessManagerPrivate::initializeIconFont()
return;
}
inited = true;
framelesshelpercore_initResource();
FramelessHelperCoreInitResource();
// We always register this font because it's our only fallback.
const int id = QFontDatabase::addApplicationFont(FRAMELESSHELPER_STRING_LITERAL(":/org.wangwenx190.FramelessHelper/resources/fonts/iconfont.ttf"));
if (id < 0) {
@ -229,6 +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
{
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 don't use Qt's theme notifier on Windows. But for other platforms
// we want to use as many Qt functionalities as possible.
#if ((QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) && !defined(Q_OS_WINDOWS))
QStyleHints * const styleHints = QGuiApplication::styleHints();
#if ((QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) && !FRAMELESSHELPER_CONFIG(native_impl))
QStyleHints *styleHints = QGuiApplication::styleHints();
Q_ASSERT(styleHints);
if (styleHints) {
connect(styleHints, &QStyleHints::colorSchemeChanged, this, [this](const Qt::ColorScheme colorScheme){
@ -342,51 +483,81 @@ void FramelessManager::setOverrideTheme(const SystemTheme theme)
Q_EMIT systemThemeChanged();
}
void FramelessManager::addWindow(FramelessParamsConst params)
bool FramelessManager::addWindow(const QObject *window, const WId windowId)
{
Q_ASSERT(params);
if (!params) {
return;
Q_ASSERT(window);
Q_ASSERT(window->isWidgetType() || window->isWindowType());
Q_ASSERT(windowId);
if (!window || !(window->isWidgetType() || window->isWindowType()) || !windowId) {
return false;
}
const WId windowId = params->getWindowId();
if (g_framelessManagerData()->contains(windowId)) {
return;
FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (data && data->frameless) {
return false;
}
g_framelessManagerData()->append(windowId);
static const bool pureQt = usePureQtImplementation();
if (pureQt) {
FramelessHelperQt::addWindow(params);
if (!data) {
data = FramelessData::create();
data->window = const_cast<QObject *>(window);
data->windowId = windowId;
g_internalData()->dataMap.insert(data->window, data);
g_internalData()->windowMap.insert(windowId, data->window);
}
#ifdef Q_OS_WINDOWS
if (!pureQt) {
FramelessHelperWin::addWindow(params);
}
std::ignore = Utils::installWindowProcHook(windowId, params);
#if FRAMELESSHELPER_CONFIG(native_impl)
# ifdef Q_OS_WINDOWS
std::ignore = Utils::installWindowProcHook(windowId);
FramelessHelperWin::addWindow(window);
# elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
# elif defined(Q_OS_MACOS)
# else
# endif
#else
FramelessHelperQt::addWindow(window);
#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);
if (!windowId) {
return;
Q_ASSERT(window);
if (!window) {
return false;
}
if (!g_framelessManagerData()->contains(windowId)) {
return;
const auto it = g_internalData()->dataMap.constFind(const_cast<QObject *>(window));
if (it == g_internalData()->dataMap.constEnd()) {
return false;
}
g_framelessManagerData()->removeAll(windowId);
static const bool pureQt = usePureQtImplementation();
if (pureQt) {
FramelessHelperQt::removeWindow(windowId);
const FramelessDataPtr data = it.value();
Q_ASSERT(data);
Q_ASSERT(data->window);
Q_ASSERT(data->windowId);
if (!data || !data->window || !data->windowId) {
return false;
}
#ifdef Q_OS_WINDOWS
if (!pureQt) {
FramelessHelperWin::removeWindow(windowId);
if (data->internalEventHandler) {
data->window->removeEventFilter(data->internalEventHandler);
delete data->internalEventHandler;
data->internalEventHandler = nullptr;
}
std::ignore = Utils::uninstallWindowProcHook(windowId);
std::ignore = Utils::removeMicaWindow(windowId);
#if FRAMELESSHELPER_CONFIG(native_impl)
# 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
g_internalData()->dataMap.erase(it);
g_internalData()->windowMap.remove(data->windowId);
return true;
}
FRAMELESSHELPER_END_NAMESPACE
#include "framelessmanager.moc"

View File

@ -62,11 +62,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
# define CRITICAL QT_NO_QDEBUG_MACRO()
#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;
[[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
{
Q_OBJECT
FRAMELESSHELPER_CLASS_INFO
Q_DISABLE_COPY_MOVE(WallpaperThread)
FRAMELESSHELPER_QT_CLASS(WallpaperThread)
public:
explicit WallpaperThread(QObject *parent = nullptr) : QThread(parent) {}
@ -657,7 +651,7 @@ void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force)
void MicaMaterialPrivate::updateMaterialBrush()
{
#if FRAMELESSHELPER_CONFIG(bundle_resource)
framelesshelpercore_initResource();
FramelessHelperCoreInitResource();
static const QImage noiseTexture = QImage(FRAMELESSHELPER_STRING_LITERAL(":/org.wangwenx190.FramelessHelper/resources/images/noise.png"));
#endif // FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE
QImage micaTexture = QImage(QSize(64, 64), kDefaultImageFormat);

View File

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

View File

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

View File

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

View File

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

View File

@ -28,6 +28,7 @@
#include "framelesshelper_windows.h"
#include "framelessmanager.h"
#include "framelessmanager_p.h"
#include "framelessconfig_p.h"
#include "sysapiloader_p.h"
#include "registrykey_p.h"
@ -193,19 +194,44 @@ FRAMELESSHELPER_STRING_CONSTANT(ScreenToClient)
FRAMELESSHELPER_STRING_CONSTANT(DwmFlush)
FRAMELESSHELPER_STRING_CONSTANT(GetCursorPos)
struct Win32UtilsData
struct UtilsWinExtraData : public FramelessExtraData
{
SystemParameters params = {};
};
struct Win32UtilsInternal
{
QHash<WId, Win32UtilsData> data = {};
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
{
@ -583,99 +609,6 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
};
#undef DEFINE_WIN32_MESSAGE
[[nodiscard]] bool operator==(const POINT &lhs, const POINT &rhs) noexcept
{
return ((lhs.x == rhs.x) && (lhs.y == rhs.y));
}
[[nodiscard]] bool operator!=(const POINT &lhs, const POINT &rhs) noexcept
{
return !operator==(lhs, rhs);
}
[[nodiscard]] bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept
{
return ((lhs.cx == rhs.cx) && (lhs.cy == rhs.cy));
}
[[nodiscard]] bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept
{
return !operator==(lhs, rhs);
}
[[nodiscard]] bool operator>(const SIZE &lhs, const SIZE &rhs) noexcept
{
return ((lhs.cx * lhs.cy) > (rhs.cx * rhs.cy));
}
[[nodiscard]] bool operator>=(const SIZE &lhs, const SIZE &rhs) noexcept
{
return (operator>(lhs, rhs) || operator==(lhs, rhs));
}
[[nodiscard]] bool operator<(const SIZE &lhs, const SIZE &rhs) noexcept
{
return (operator!=(lhs, rhs) && !operator>(lhs, rhs));
}
[[nodiscard]] bool operator<=(const SIZE &lhs, const SIZE &rhs) noexcept
{
return (operator<(lhs, rhs) || operator==(lhs, rhs));
}
[[nodiscard]] bool operator==(const RECT &lhs, const RECT &rhs) noexcept
{
return ((lhs.left == rhs.left) && (lhs.top == rhs.top)
&& (lhs.right == rhs.right) && (lhs.bottom == rhs.bottom));
}
[[nodiscard]] bool operator!=(const RECT &lhs, const RECT &rhs) noexcept
{
return !operator==(lhs, rhs);
}
[[nodiscard]] QPoint point2qpoint(const POINT &point)
{
return QPoint{ int(point.x), int(point.y) };
}
[[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)
{
Q_ASSERT(hwnd);
@ -734,8 +667,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
static const auto currentOsVer = []() -> std::optional<VersionNumber> {
if (API_NT_AVAILABLE(RtlGetVersion)) {
using RtlGetVersionPtr = _NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
const auto pRtlGetVersion =
reinterpret_cast<RtlGetVersionPtr>(SysApiLoader::instance()->get(kntdll, kRtlGetVersion));
const auto pRtlGetVersion = reinterpret_cast<RtlGetVersionPtr>(SysApiLoader::instance()->get(kntdll, kRtlGetVersion));
RTL_OSVERSIONINFOEXW osvi;
SecureZeroMemory(&osvi, 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);
#else // !FRAMELESSHELPER_CONFIG(private_qt)
LPWSTR buf = nullptr;
if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&buf), 0, nullptr) == 0) {
if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&buf), 0, nullptr) == 0) {
return FRAMELESSHELPER_STRING_LITERAL("FormatMessageW() returned empty string.");
}
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);
static constexpr const UINT flags =
(SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
if (::SetWindowPos(hwnd, nullptr, newWindowX, newWindowY,
currentWindowWidth, currentWindowHeight, flags) == FALSE) {
if (::SetWindowPos(hwnd, nullptr, newWindowX, newWindowY, currentWindowWidth, currentWindowHeight, flags) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kSetWindowPos);
return false;
}
return true;
}
[[nodiscard]] static inline int getSystemMetrics2(const int index, const bool horizontal,
const quint32 dpi)
[[nodiscard]] static inline int getSystemMetrics2(const int index, const bool horizontal, const quint32 dpi)
{
Q_ASSERT(dpi != 0);
if (dpi == 0) {
@ -863,8 +792,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return std::round(qreal(::GetSystemMetrics(index)) / currentDpr * requestedDpr);
}
[[nodiscard]] static inline int getSystemMetrics2(const WId windowId, const int index,
const bool horizontal, const bool scaled)
[[nodiscard]] static inline int getSystemMetrics2(const WId windowId, const int index, const bool horizontal, const bool scaled)
{
Q_ASSERT(windowId);
if (!windowId) {
@ -883,29 +811,29 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return std::round(qreal(::GetSystemMetrics(index)) / dpr);
}
[[maybe_unused]] [[nodiscard]] static inline
[[maybe_unused]] [[nodiscard]] static inline constexpr
DWORD qtEdgesToWin32Orientation(const Qt::Edges edges)
{
if (edges == Qt::Edges{}) {
return 0;
} else if (edges == (Qt::LeftEdge)) {
return 0xF001; // SC_SIZELEFT
return SC_SIZELEFT;
} else if (edges == (Qt::RightEdge)) {
return 0xF002; // SC_SIZERIGHT
return SC_SIZERIGHT;
} else if (edges == (Qt::TopEdge)) {
return 0xF003; // SC_SIZETOP
return SC_SIZETOP;
} else if (edges == (Qt::TopEdge | Qt::LeftEdge)) {
return 0xF004; // SC_SIZETOPLEFT
return SC_SIZETOPLEFT;
} else if (edges == (Qt::TopEdge | Qt::RightEdge)) {
return 0xF005; // SC_SIZETOPRIGHT
return SC_SIZETOPRIGHT;
} else if (edges == (Qt::BottomEdge)) {
return 0xF006; // SC_SIZEBOTTOM
return SC_SIZEBOTTOM;
} else if (edges == (Qt::BottomEdge | Qt::LeftEdge)) {
return 0xF007; // SC_SIZEBOTTOMLEFT
return SC_SIZEBOTTOMLEFT;
} else if (edges == (Qt::BottomEdge | Qt::RightEdge)) {
return 0xF008; // SC_SIZEBOTTOMRIGHT
return SC_SIZEBOTTOMRIGHT;
} else {
return 0xF000; // SC_SIZE
return SC_SIZE;
}
}
@ -923,7 +851,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
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))
|| ((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))
|| ((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
(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
{
Q_ASSERT(hWnd);
if (!hWnd) {
return 0;
return FALSE;
}
#if FRAMELESSHELPER_CONFIG(debug_output)
if (isWin32MessageDebuggingEnabled()) {
@ -981,11 +903,27 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
Utils::printWin32Message(&message);
}
#endif
const auto defaultWindowProcessing = [hWnd, uMsg, wParam, lParam]() -> LRESULT { return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); };
const auto windowId = reinterpret_cast<WId>(hWnd);
const auto it = g_win32UtilsData()->data.constFind(windowId);
if (it == g_win32UtilsData()->data.constEnd()) {
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
const QObject *window = FramelessManagerPrivate::getWindow(windowId);
if (!window) {
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
// 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
@ -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
// 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.
if (!usePureQtImplementation() && (uMsg != WM_NCCALCSIZE)) {
if (uMsg != WM_NCCALCSIZE) {
MSG message;
SecureZeroMemory(&message, sizeof(message));
message.hwnd = hWnd;
@ -1034,7 +972,7 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
return LRESULT(filterResult);
}
}
const Win32UtilsData &data = it.value();
#endif // native_impl
const auto getNativePosFromMouse = [lParam]() -> QPoint {
return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
};
@ -1073,8 +1011,8 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
switch (uMsg) {
case WM_RBUTTONUP: {
const QPoint nativeLocalPos = getNativePosFromMouse();
const QPoint qtScenePos = Utils::fromNativeLocalPosition(data.params.getWindowHandle(), nativeLocalPos);
if (data.params.isInsideTitleBarDraggableArea(qtScenePos)) {
const QPoint qtScenePos = Utils::fromNativeLocalPosition(qWindow, nativeLocalPos);
if (data->callbacks->isInsideTitleBarDraggableArea(qtScenePos)) {
POINT pos = {nativeLocalPos.x(), nativeLocalPos.y()};
if (::ClientToScreen(hWnd, &pos) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kClientToScreen);
@ -1084,12 +1022,12 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
nativeGlobalPos = {pos.x, pos.y};
}
} break;
case WM_NCRBUTTONUP: {
case WM_NCRBUTTONUP:
if (wParam == HTCAPTION) {
shouldShowSystemMenu = true;
nativeGlobalPos = getNativePosFromMouse();
}
} break;
break;
case WM_SYSCOMMAND: {
const WPARAM filteredWParam = (wParam & 0xFFF0);
if ((filteredWParam == SC_KEYMENU) && (lParam == VK_SPACE)) {
@ -1112,20 +1050,20 @@ static constexpr const std::array<Win32Message, 333> g_win32MessageMap =
break;
}
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
// 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
// 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);
if (g_win32UtilsData()->qtWindowProc) {
Q_ASSERT(extraData->qtWindowProc);
if (extraData->qtWindowProc) {
// Hand over to Qt's original window proc function for events we are not
// interested in.
return ::CallWindowProcW(g_win32UtilsData()->qtWindowProc, hWnd, uMsg, wParam, lParam);
return ::CallWindowProcW(extraData->qtWindowProc, hWnd, uMsg, wParam, lParam);
} else {
return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
return defaultWindowProcessing();
}
}
@ -1167,16 +1105,12 @@ bool Utils::triggerFrameChange(const WId windowId)
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
static constexpr const UINT swpFlags =
(SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE
| SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
static constexpr const UINT swpFlags = (SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
if (::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, swpFlags) == FALSE) {
WARNING << getSystemErrorMessage(kSetWindowPos);
return false;
}
static constexpr const UINT rdwFlags =
(RDW_ERASE | RDW_FRAME | RDW_INVALIDATE
| RDW_UPDATENOW | RDW_ALLCHILDREN);
static constexpr const UINT rdwFlags = (RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
if (::RedrawWindow(hwnd, nullptr, nullptr, rdwFlags) == FALSE) {
WARNING << getSystemErrorMessage(kRedrawWindow);
return false;
@ -1193,19 +1127,31 @@ bool Utils::updateWindowFrameMargins(const WId windowId, const bool reset)
if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) {
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.
if (!isDwmCompositionEnabled()) {
return false;
}
const bool micaEnabled = g_win32UtilsData()->micaWindowIds.contains(windowId);
const auto margins = [micaEnabled, reset]() -> MARGINS {
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);
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
// let the window frame extend to the whole window (or disable the
// redirection surface, but this will break GDI's rendering, so we
// can't do this, unfortunately), so we can't change the window frame
// margins in this case, otherwise Mica/Mica Alt will be broken.
if (micaEnabled) {
if (extraData->mica) {
return {-1, -1, -1, -1};
}
if (reset || isWindowFrameBorderVisible()) {
@ -1275,9 +1221,9 @@ QString Utils::getSystemErrorMessage(const QString &function)
if (function.isEmpty()) {
return {};
}
const DWORD code = GetLastError();
const DWORD code = ::GetLastError();
if (code == ERROR_SUCCESS) {
return {};
return kSuccessMessageText;
}
return getSystemErrorMessageImpl(function, code);
}
@ -1342,12 +1288,19 @@ DwmColorizationArea Utils::getDwmColorizationArea()
return DwmColorizationArea::None;
}
bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool selectFirstEntry,
FramelessParamsConst params)
bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool selectFirstEntry)
{
Q_ASSERT(windowId);
Q_ASSERT(params);
if (!windowId || !params) {
if (!windowId) {
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;
}
@ -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.
const bool disableRestore = params->getProperty(kSysMenuDisableRestoreVar, false).toBool();
const bool disableMinimize = params->getProperty(kSysMenuDisableMinimizeVar, false).toBool();
const bool disableMaximize = params->getProperty(kSysMenuDisableMaximizeVar, false).toBool();
const bool disableRestore = data->callbacks->getProperty(kSysMenuDisableRestoreVar, false).toBool();
const bool disableMinimize = data->callbacks->getProperty(kSysMenuDisableMinimizeVar, false).toBool();
const bool disableMaximize = data->callbacks->getProperty(kSysMenuDisableMaximizeVar, false).toBool();
const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(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)));
// The first menu item should be selected by default if the menu is brought
// up by keyboard. I don't know how to pre-select a menu item but it seems
@ -1399,14 +1352,13 @@ bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool sel
::SetMenuDefaultItem(hMenu, defaultItemId, FALSE);
// Popup the system menu at the required position.
const int result = ::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft()
? TPM_RIGHTALIGN : TPM_LEFTALIGN)), pos.x(), pos.y(), 0, hWnd, nullptr);
const int result = ::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), pos.x(), pos.y(), 0, hWnd, nullptr);
// Unhighlight the first menu item after the popup menu is closed, otherwise it will keep
// highlighting until we unhighlight it manually.
::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | MFS_UNHILITE));
if (result == 0) {
if (result == FALSE) {
// The user canceled the menu, no need to continue.
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
// and onwards, but it has been marked as deprecated by Microsoft.
if (API_D2D_AVAILABLE(D2D1CreateFactory)) {
using D2D1CreateFactoryPtr =
HRESULT(WINAPI *)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS *, void **);
const auto pD2D1CreateFactory =
reinterpret_cast<D2D1CreateFactoryPtr>(SysApiLoader::instance()->get(kd2d1, kD2D1CreateFactory));
using D2D1CreateFactoryPtr = HRESULT(WINAPI *)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS *, void **);
const auto pD2D1CreateFactory = reinterpret_cast<D2D1CreateFactoryPtr>(SysApiLoader::instance()->get(kd2d1, kD2D1CreateFactory));
ID2D1Factory *d2dFactory = nullptr;
HRESULT hr = pD2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory),
nullptr, reinterpret_cast<void **>(&d2dFactory));
HRESULT hr = pD2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), nullptr, reinterpret_cast<void **>(&d2dFactory));
if (SUCCEEDED(hr)) {
// We want to get the newest system DPI, so refresh the system metrics
// manually to ensure that.
@ -1740,11 +1689,9 @@ quint32 Utils::getResizeBorderThicknessForDpi(const bool horizontal, const quint
return 0;
}
if (horizontal) {
return (getSystemMetrics2(SM_CXSIZEFRAME, true, dpi)
+ getSystemMetrics2(SM_CXPADDEDBORDER, true, dpi));
return (getSystemMetrics2(SM_CXSIZEFRAME, true, dpi) + getSystemMetrics2(SM_CXPADDEDBORDER, true, dpi));
} else {
return (getSystemMetrics2(SM_CYSIZEFRAME, false, dpi)
+ getSystemMetrics2(SM_CYPADDEDBORDER, false, dpi));
return (getSystemMetrics2(SM_CYSIZEFRAME, false, dpi) + getSystemMetrics2(SM_CYPADDEDBORDER, false, dpi));
}
}
@ -1755,11 +1702,9 @@ quint32 Utils::getResizeBorderThickness(const WId windowId, const bool horizonta
return 0;
}
if (horizontal) {
return (getSystemMetrics2(windowId, SM_CXSIZEFRAME, true, scaled)
+ getSystemMetrics2(windowId, SM_CXPADDEDBORDER, true, scaled));
return (getSystemMetrics2(windowId, SM_CXSIZEFRAME, true, scaled) + getSystemMetrics2(windowId, SM_CXPADDEDBORDER, true, scaled));
} else {
return (getSystemMetrics2(windowId, SM_CYSIZEFRAME, false, scaled)
+ getSystemMetrics2(windowId, SM_CYPADDEDBORDER, false, scaled));
return (getSystemMetrics2(windowId, SM_CYSIZEFRAME, 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 auto hwnd = reinterpret_cast<HWND>(windowId);
UINT value = 0;
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetWindowAttribute, hwnd,
_DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value));
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetWindowAttribute, hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value));
if (SUCCEEDED(hr)) {
const qreal dpr = (scaled ? 1.0 : scaleFactor);
const qreal dpr = (scaled ? qreal(1) : scaleFactor);
return std::round(qreal(value) / dpr);
} else {
const qreal dpr = (scaled ? scaleFactor : 1.0);
const qreal dpr = (scaled ? scaleFactor : qreal(1));
return std::round(qreal(kDefaultWindowFrameBorderThickness) * dpr);
}
}
@ -1949,7 +1893,7 @@ bool Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
return false;
}
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);
return false;
}
@ -1986,10 +1930,8 @@ bool Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
bool Utils::isWindowFrameBorderVisible()
{
static const auto result = []() -> bool {
#if FRAMELESSHELPER_CONFIG(native_impl)
const FramelessConfig * const config = FramelessConfig::instance();
if (config->isSet(Option::UseCrossPlatformQtImplementation)) {
return false;
}
if (config->isSet(Option::ForceShowWindowFrameBorder)) {
return true;
}
@ -1997,6 +1939,9 @@ bool Utils::isWindowFrameBorderVisible()
return false;
}
return WindowsVersionHelper::isWin10OrGreater();
#else
return false;
#endif
}();
return result;
}
@ -2016,15 +1961,29 @@ bool Utils::isFrameBorderColorized()
return isTitleBarColorized();
}
bool Utils::installWindowProcHook(const WId windowId, FramelessParamsConst params)
bool Utils::installWindowProcHook(const WId windowId)
{
Q_ASSERT(windowId);
Q_ASSERT(params);
if (!windowId || !params) {
if (!windowId) {
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;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
if (!g_win32UtilsData()->qtWindowProc) {
if (!extraData->qtWindowProc) {
::SetLastError(ERROR_SUCCESS);
const auto qtWindowProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hwnd, GWLP_WNDPROC));
Q_ASSERT(qtWindowProc);
@ -2032,18 +1991,15 @@ bool Utils::installWindowProcHook(const WId windowId, FramelessParamsConst param
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
return false;
}
g_win32UtilsData()->qtWindowProc = qtWindowProc;
extraData->qtWindowProc = qtWindowProc;
}
const auto it = g_win32UtilsData()->data.constFind(windowId);
if (it == g_win32UtilsData()->data.constEnd()) {
Win32UtilsData data = {};
data.params = *params;
g_win32UtilsData()->data.insert(windowId, data);
if (!extraData->windowProcHooked) {
::SetLastError(ERROR_SUCCESS);
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(FramelessHelperHookWindowProc)) == 0) {
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
return false;
}
extraData->windowProcHooked = true;
}
return true;
}
@ -2054,19 +2010,30 @@ bool Utils::uninstallWindowProcHook(const WId windowId)
if (!windowId) {
return false;
}
const auto it = g_win32UtilsData()->data.constFind(windowId);
if (it != g_win32UtilsData()->data.constEnd()) {
g_win32UtilsData()->data.erase(it);
const QObject *window = FramelessManagerPrivate::getWindow(windowId);
if (!window) {
return false;
}
if (g_win32UtilsData()->data.isEmpty() && g_win32UtilsData()->qtWindowProc) {
const auto hwnd = reinterpret_cast<HWND>(windowId);
::SetLastError(ERROR_SUCCESS);
if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(g_win32UtilsData()->qtWindowProc)) == 0) {
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
return false;
}
g_win32UtilsData()->qtWindowProc = nullptr;
const FramelessDataPtr data = FramelessManagerPrivate::getData(window);
if (!data || !data->frameless) {
return false;
}
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;
}
@ -2323,6 +2290,19 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
if (!windowId) {
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);
if (WindowsVersionHelper::isWin8OrGreater()) {
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.";
return false;
}
const auto restoreWindowFrameMargins = [windowId]() -> void {
g_win32UtilsData()->micaWindowIds.removeAll(windowId);
const auto restoreWindowFrameMargins = [windowId, &extraData]() -> void {
extraData->mica = false;
std::ignore = updateWindowFrameMargins(windowId, false);
};
static const auto userPreferredBlurMode = []() -> std::optional<BlurMode> {
@ -2372,7 +2352,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
return mode;
}
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...";
if (WindowsVersionHelper::isWin10OrGreater()) {
return BlurMode::Windows_Acrylic;
@ -2438,7 +2418,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
return result;
} else {
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
// 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
@ -2682,9 +2662,9 @@ bool Utils::setQtDarkModeAwareEnabled(const bool enable)
// flag has no effect for pure Qt Quick applications.
return {App::DarkModeWindowFrames | App::DarkModeStyle};
# else // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) \
// 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 \
// theme for them anyway.
// 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 \
// theme for them anyway.
return {App::DarkModeWindowFrames};
# 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));
}
bool Utils::removeMicaWindow(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return false;
}
g_win32UtilsData()->micaWindowIds.removeAll(windowId);
return true;
}
quint64 Utils::getKeyState()
{
quint64 result = 0;
@ -3163,7 +3133,7 @@ bool Utils::isValidWindow(const WId windowId, const bool checkVisible, const boo
return false;
}
const LONG_PTR exStyles = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
if ((exStyles != 0) && (exStyles & WS_EX_TOOLWINDOW)) {
if ((exStyles == 0) || (exStyles & WS_EX_TOOLWINDOW)) {
return false;
}
RECT rect = { 0, 0, 0, 0 };
@ -3209,11 +3179,11 @@ bool Utils::updateFramebufferTransparency(const WId windowId)
DWM_BLURBEHIND bb;
SecureZeroMemory(&bb, sizeof(bb));
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;
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmEnableBlurBehindWindow, hwnd, &bb);
if (bb.hRgnBlur) {
if (DeleteObject(bb.hRgnBlur) == FALSE) {
if (::DeleteObject(bb.hRgnBlur) == FALSE) {
WARNING << getSystemErrorMessage(kDeleteObject);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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