Compare commits

..

9 Commits

Author SHA1 Message Date
Yuhang Zhao 90b2fe42c6 macos: fix compile error 2023-08-01 16:18:57 +08:00
Yuhang Zhao 60a691eb61 macos: fix syntax error 2023-08-01 15:48:12 +08:00
Yuhang Zhao 5500e50075 cmake: update submodule 2023-08-01 15:43:18 +08:00
Yuhang Zhao 3342a28895 refactor 2023-08-01 14:28:09 +08:00
Yuhang Zhao f2758aba25 cmake: minor tweaks 2023-07-30 18:56:07 +08:00
Yuhang Zhao 563a3cfb2d update README 2023-07-30 18:44:18 +08:00
Yuhang Zhao cb21815934 bump version to 2.5.0 2023-07-30 18:29:54 +08:00
Yuhang Zhao 86bc1c0142 cleanup & optimize, part 2
The file size of FramelessHelper binaries should be smaller than before. Core: Win32 MSVC2022 x64 release build, -20KB
The general performance should be improved, due to double lookups are all eliminated.
2023-07-30 18:28:38 +08:00
Yuhang Zhao 20ab4f7d4b mica material: prefer speed over quality 2023-07-30 15:14:16 +08:00
39 changed files with 426 additions and 320 deletions

View File

@ -25,7 +25,7 @@
cmake_minimum_required(VERSION 3.20)
project(FramelessHelper
VERSION "2.4.2"
VERSION "2.5.0"
DESCRIPTION "Cross-platform window customization framework for Qt Widgets and Qt Quick."
HOMEPAGE_URL "https://github.com/wangwenx190/framelesshelper/"
)

View File

@ -28,17 +28,25 @@ set(_@PROJECT_NAME@_supported_components Core Widgets Quick)
foreach(_comp ${@PROJECT_NAME@_FIND_COMPONENTS})
if(_comp IN_LIST _@PROJECT_NAME@_supported_components)
set(__targets_file "${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@${_comp}Targets.cmake")
set(__target @PROJECT_NAME@::${_comp})
if(TARGET ${__target})
continue()
else()
set(__target_full @PROJECT_NAME@${_comp})
set(__targets_file "${CMAKE_CURRENT_LIST_DIR}/${__target_full}Targets.cmake")
if(EXISTS "${__targets_file}")
include("${__targets_file}")
add_library(@PROJECT_NAME@::${__target_full} ALIAS ${__target_full})
add_library(${__target} ALIAS ${__target_full})
else()
set(@PROJECT_NAME@_FOUND FALSE)
set(@PROJECT_NAME@_NOT_FOUND_MESSAGE "Can't find necessary configuration file for @PROJECT_NAME@::${_comp}, please make sure this component is built successfully and installed properly.")
set(@PROJECT_NAME@_NOT_FOUND_MESSAGE "Can't find necessary configuration file for ${__target}, please make sure this component is built successfully and installed properly.")
break()
endif()
endif()
else()
set(@PROJECT_NAME@_FOUND FALSE)
set(@PROJECT_NAME@_NOT_FOUND_MESSAGE "Unknown component: @PROJECT_NAME@::${_comp}.")
set(@PROJECT_NAME@_NOT_FOUND_MESSAGE "Unknown component: ${__target}.")
break()
endif()
endforeach()

View File

@ -17,6 +17,14 @@ You can join our [Discord channel](https://discord.gg/grrM4Tmesy) to communicate
- Examples: Add demo projects that have transparent background and doesn't have rectangular window frame.
- Feature requests are welcome!
## Highlights v2.5
- General: The file size of FramelessHelper binaries should be smaller than before, due to most static string literals and some internal structures are constexpr now, this change may also help to improve the general performance.
- General: The performance should be improved quite some bit, due to most double lookups of Qt container types and unnecessary data copies are avoided now.
- Mica Material: FramelessHelper now prefers speed over quality. This change will lower the image quality but since the image is highly blurred anyway, there should not be any significant differences in the final user experience.
- Build system: Improved RPATH support.
- Routine bug fixes and internal refactorings.
## Highlights v2.4
- Widgets: Nested frameless windows are supported now!

2
cmake

@ -1 +1 @@
Subproject commit d4c8265fa4afe6244fadff6648d1d091de0c5d68
Subproject commit 68b2bcba1456bbad73309d748ce50dc6cefc04a2

View File

@ -28,13 +28,11 @@
#include <QtCore/qmath.h>
#include <QtCore/qpoint.h>
#include <QtCore/qsize.h>
#include <QtCore/qrect.h>
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <QtGui/qcolor.h>
#include <QtGui/qwindowdefs.h>
#include <functional>
#include <optional>
#include <memory>
QT_BEGIN_NAMESPACE
class QEvent;
@ -292,7 +290,8 @@ enum class Option : quint8
EnableBlurBehindWindow,
ForceNonNativeBackgroundBlur,
DisableLazyInitializationForMicaMaterial,
ForceNativeBackgroundBlur
ForceNativeBackgroundBlur,
Last = ForceNativeBackgroundBlur
};
Q_ENUM_NS(Option)
@ -313,7 +312,8 @@ enum class SystemButtonType : quint8
Minimize,
Maximize,
Restore,
Close
Close,
Last = Close
};
Q_ENUM_NS(SystemButtonType)

View File

@ -25,7 +25,6 @@
#pragma once
#include <FramelessHelper/Core/framelesshelpercore_global.h>
#include <QtCore/qrect.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,6 +25,7 @@
#pragma once
#include <FramelessHelper/Core/framelesshelpercore_global.h>
#include <functional>
QT_BEGIN_NAMESPACE
class QScreen;

View File

@ -31,7 +31,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class MicaMaterial;
using Transform = struct Transform
struct Transform
{
qreal Horizontal = 0;
qreal Vertical = 0;

View File

@ -25,6 +25,7 @@
#pragma once
#include <FramelessHelper/Core/framelesshelpercore_global.h>
#include <functional>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
# include <QtCore/qscopeguard.h>

View File

@ -89,7 +89,7 @@ struct VersionNumber
};
#ifdef Q_OS_WINDOWS
[[maybe_unused]] inline constexpr const std::array<VersionNumber, 27> WindowsVersions =
[[maybe_unused]] inline constexpr const std::array<VersionNumber, static_cast<int>(Global::WindowsVersion::Latest) + 1> WindowsVersions =
{
VersionNumber{ 5, 0, 2195 }, // Windows 2000
VersionNumber{ 5, 1, 2600 }, // Windows XP

View File

@ -74,6 +74,8 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_QUICK_URI[] = "org.wangwenx190.FramelessHelper";
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_QUICK_VERSION_MAJOR = 1;
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_QUICK_VERSION_MINOR = 0;
class FRAMELESSHELPER_QUICK_API QuickGlobal : public QObject
{

View File

@ -36,7 +36,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessQuickHelper;
class QuickMicaMaterial;
class QuickWindowBorder;
struct QuickHelperData;
struct FramelessQuickHelperData;
class FRAMELESSHELPER_QUICK_API FramelessQuickHelperPrivate : public QObject
{
@ -89,7 +89,10 @@ public:
Q_NODISCARD bool isReady() const;
void waitForReady();
void repaintAllChildren(const int delay = 0) const;
void repaintAllChildren(const quint32 delay = 0) const;
Q_NODISCARD quint32 readyWaitTime() const;
void setReadyWaitTime(const quint32 time);
private:
Q_NODISCARD QRect mapItemGeometryToScene(const QQuickItem * const item) const;
@ -97,8 +100,8 @@ private:
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 QuickHelperData getWindowData() const;
Q_NODISCARD QuickHelperData *getWindowDataMutable() const;
Q_NODISCARD const FramelessQuickHelperData *getWindowData() const;
Q_NODISCARD FramelessQuickHelperData *getWindowDataMutable() const;
void rebindWindow();
private:
@ -108,6 +111,7 @@ private:
std::optional<bool> m_extendIntoTitleBar = std::nullopt;
bool m_destroying = false;
bool m_qpaReady = false;
quint32 m_qpaWaitTime = 0;
};
FRAMELESSHELPER_END_NAMESPACE

View File

@ -31,7 +31,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessWidgetsHelper;
struct WidgetsHelperData;
struct FramelessWidgetsHelperData;
class WidgetsSharedHelper;
class MicaMaterial;
class WindowBorderPainter;
@ -90,7 +90,10 @@ public:
Q_NODISCARD bool isReady() const;
void waitForReady();
void repaintAllChildren(const int delay = 0) const;
void repaintAllChildren(const quint32 delay = 0) const;
Q_NODISCARD quint32 readyWaitTime() const;
void setReadyWaitTime(const quint32 time);
private:
Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const;
@ -99,8 +102,8 @@ private:
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 WidgetsHelperData getWindowData() const;
Q_NODISCARD WidgetsHelperData *getWindowDataMutable() const;
Q_NODISCARD const FramelessWidgetsHelperData *getWindowData() const;
Q_NODISCARD FramelessWidgetsHelperData *getWindowDataMutable() const;
private:
FramelessWidgetsHelper *q_ptr = nullptr;
@ -110,6 +113,7 @@ private:
bool m_destroying = false;
bool m_qpaReady = false;
QSizePolicy m_savedSizePolicy = {};
quint32 m_qpaWaitTime = 0;
};
FRAMELESSHELPER_END_NAMESPACE

View File

@ -34,10 +34,10 @@
#define _FRAMELESSHELPER_VERSION_DEFINED_
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_MAJOR = 2;
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_MINOR = 4;
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_PATCH = 2;
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_MINOR = 5;
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_PATCH = 0;
//[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_TWEAK = 0;
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_VERSION_STR[] = "2.4.2";
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_VERSION_STR[] = "2.5.0";
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_COMMIT_STR[] = "UNKNOWN";
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_COMPILE_DATETIME_STR[] = "UNKNOWN";

View File

@ -22,8 +22,6 @@
SOFTWARE.
]]
include(GNUInstallDirs)
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif()
@ -275,6 +273,7 @@ else()
)
endif()
include(GNUInstallDirs)
target_include_directories(${SUB_MODULE_TARGET} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}/../..>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}>"
@ -285,8 +284,13 @@ target_include_directories(${SUB_MODULE_TARGET} PUBLIC
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_MODULE_PATH}/private>"
)
if(NOT FRAMELESSHELPER_BUILD_STATIC)
setup_target_rpaths(TARGETS ${SUB_MODULE_TARGET})
endif()
setup_qt_stuff(TARGETS ${SUB_MODULE_TARGET})
set(__extra_flags)
set(__extra_flags "")
if(NOT FRAMELESSHELPER_NO_PERMISSIVE_CHECKS)
list(APPEND __extra_flags PERMISSIVE)
endif()
@ -309,6 +313,7 @@ if(FRAMELESSHELPER_FORCE_LTO)
list(APPEND __extra_flags FORCE_LTO)
endif()
setup_compile_params(TARGETS ${SUB_MODULE_TARGET} ${__extra_flags})
if(NOT FRAMELESSHELPER_NO_INSTALL)
setup_package_export(
TARGETS ${__export_targets}

View File

@ -53,8 +53,7 @@ ChromePalettePrivate::ChromePalettePrivate(ChromePalette *q) : QObject(q)
return;
}
q_ptr = q;
connect(FramelessManager::instance(),
&FramelessManager::systemThemeChanged, this, &ChromePalettePrivate::refresh);
connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &ChromePalettePrivate::refresh);
refresh();
}

View File

@ -24,6 +24,7 @@
#include "framelessconfig_p.h"
#include <array>
#include <memory>
#include <QtCore/qdir.h>
#include <QtCore/qsettings.h>
#include <QtCore/qcoreapplication.h>
@ -32,7 +33,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcFramelessConfig, "wangwenx190.framelesshelper.core.framelessconfig")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcFramelessConfig, "wangwenx190.framelesshelper.core.framelessconfig")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()
@ -54,7 +55,7 @@ struct FramelessConfigEntry
const char *cfg = nullptr;
};
static constexpr const std::array<FramelessConfigEntry, 10> FramelessOptionsTable =
static constexpr const std::array<FramelessConfigEntry, static_cast<int>(Option::Last) + 1> FramelessOptionsTable =
{
FramelessConfigEntry{ "FRAMELESSHELPER_USE_CROSS_PLATFORM_QT_IMPLEMENTATION", "Options/UseCrossPlatformQtImplementation" },
FramelessConfigEntry{ "FRAMELESSHELPER_FORCE_HIDE_WINDOW_FRAME_BORDER", "Options/ForceHideWindowFrameBorder" },
@ -73,7 +74,7 @@ static constexpr const auto OptionCount = std::size(FramelessOptionsTable);
struct FramelessConfigData
{
bool loaded = false;
bool options[OptionCount] = {};
std::array<bool, OptionCount> options = {};
bool disableEnvVar = false;
bool disableCfgFile = false;
};
@ -139,7 +140,7 @@ void FramelessConfig::reload(const bool force)
&& (qEnvironmentVariableIntValue(FramelessOptionsTable.at(i).env) > 0));
const bool cfgFile = (!g_framelessConfigData()->disableCfgFile && configFile
&& configFile->value(QUtf8String(FramelessOptionsTable.at(i).cfg), false).toBool());
g_framelessConfigData()->options[i] = (envVar || cfgFile);
g_framelessConfigData()->options.at(i) = (envVar || cfgFile);
}
g_framelessConfigData()->loaded = true;
@ -148,12 +149,12 @@ void FramelessConfig::reload(const bool force)
void FramelessConfig::set(const Option option, const bool on)
{
g_framelessConfigData()->options[static_cast<int>(option)] = on;
g_framelessConfigData()->options.at(static_cast<int>(option)) = on;
}
bool FramelessConfig::isSet(const Option option) const
{
return g_framelessConfigData()->options[static_cast<int>(option)];
return g_framelessConfigData()->options.at(static_cast<int>(option));
}
void FramelessConfig::setLoadFromEnvironmentVariablesDisabled(const bool on)

View File

@ -58,12 +58,9 @@ struct FramelessQtHelperData
bool leftButtonPressed = false;
};
struct FramelessQtHelper
{
QHash<WId, FramelessQtHelperData> data = {};
};
using FramelessQtHelperInternal = QHash<WId, FramelessQtHelperData>;
Q_GLOBAL_STATIC(FramelessQtHelper, g_framelessQtHelperData)
Q_GLOBAL_STATIC(FramelessQtHelperInternal, g_framelessQtHelperData)
FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent) {}
@ -76,8 +73,8 @@ void FramelessHelperQt::addWindow(FramelessParamsConst params)
return;
}
const WId windowId = params->getWindowId();
const auto it = g_framelessQtHelperData()->data.constFind(windowId);
if (it != g_framelessQtHelperData()->data.constEnd()) {
const auto it = g_framelessQtHelperData()->constFind(windowId);
if (it != g_framelessQtHelperData()->constEnd()) {
return;
}
FramelessQtHelperData data = {};
@ -85,7 +82,7 @@ void FramelessHelperQt::addWindow(FramelessParamsConst 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()->data.insert(windowId, data);
g_framelessQtHelperData()->insert(windowId, data);
const auto shouldApplyFramelessFlag = []() -> bool {
#ifdef Q_OS_MACOS
return false;
@ -117,11 +114,11 @@ void FramelessHelperQt::removeWindow(const WId windowId)
if (!windowId) {
return;
}
const auto it = g_framelessQtHelperData()->data.constFind(windowId);
if (it == g_framelessQtHelperData()->data.constEnd()) {
const auto it = g_framelessQtHelperData()->constFind(windowId);
if (it == g_framelessQtHelperData()->constEnd()) {
return;
}
g_framelessQtHelperData()->data.erase(it);
g_framelessQtHelperData()->erase(it);
#ifdef Q_OS_MACOS
Utils::removeWindowProxy(windowId);
#endif
@ -165,8 +162,8 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
}
const auto window = qobject_cast<QWindow *>(object);
const WId windowId = window->winId();
const auto it = g_framelessQtHelperData()->data.find(windowId);
if (it == g_framelessQtHelperData()->data.end()) {
const auto it = g_framelessQtHelperData()->find(windowId);
if (it == g_framelessQtHelperData()->end()) {
return QObject::eventFilter(object, event);
}
const FramelessQtHelperData &data = it.value();

View File

@ -31,6 +31,7 @@
#include "framelesshelper_windows.h"
#include "framelesshelpercore_global_p.h"
#include <optional>
#include <memory>
#include <QtCore/qhash.h>
#include <QtCore/qvariant.h>
#include <QtCore/qcoreapplication.h>
@ -40,7 +41,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcFramelessHelperWin, "wangwenx190.framelesshelper.core.impl.win")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcFramelessHelperWin, "wangwenx190.framelesshelper.core.impl.win")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()
@ -96,14 +97,14 @@ struct FramelessWin32HelperData
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
};
struct FramelessWin32Helper
struct FramelessWin32HelperInternal
{
std::unique_ptr<FramelessHelperWin> nativeEventFilter = nullptr;
QHash<WId, FramelessWin32HelperData> data = {};
QHash<WId, WId> fallbackTitleBarToParentWindowMapping = {};
};
Q_GLOBAL_STATIC(FramelessWin32Helper, g_framelessWin32HelperData)
Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData)
[[nodiscard]] extern bool operator==(const RECT &lhs, const RECT &rhs) noexcept;
[[nodiscard]] extern bool operator!=(const RECT &lhs, const RECT &rhs) noexcept;
@ -211,7 +212,10 @@ Q_GLOBAL_STATIC(FramelessWin32Helper, g_framelessWin32HelperData)
case SystemButtonType::Close:
return HTCLOSE;
case SystemButtonType::Unknown:
QT_WARNING_PUSH
QT_WARNING_DISABLE_MSVC(4702)
Q_UNREACHABLE_RETURN(HTNOWHERE);
QT_WARNING_POP
}
}
// Returns "HTTRANSPARENT" to let the mouse event pass through this invisible
@ -497,15 +501,19 @@ static inline void cleanupFallbackWindow()
return false;
}
const auto fallbackTitleBarWindowId = reinterpret_cast<WId>(fallbackTitleBarWindowHandle);
if (!resizeFallbackTitleBarWindow(parentWindowId, fallbackTitleBarWindowId, hide)) {
WARNING << "Failed to re-position the fallback title bar window.";
return false;
}
g_framelessWin32HelperData()->data[parentWindowId].fallbackTitleBarWindowId = fallbackTitleBarWindowId;
g_framelessWin32HelperData()->fallbackTitleBarToParentWindowMapping.insert(fallbackTitleBarWindowId, parentWindowId);
// ### Why do we need an extra resize here?
QTimer::singleShot(200, qApp, [parentWindowId, fallbackTitleBarWindowId, hide](){
std::ignore = resizeFallbackTitleBarWindow(parentWindowId, fallbackTitleBarWindowId, hide);
// We need some extra delay here. Experiments revealed that the time point
// is still too early when we call this function, and thus we failed to place
// the the fake title bar window in the correct position. Adding some delay
// fixes this issue. But when we are running in a slow environment (when we
// are debugging/the system overload is very high/the hardware is old), this
// delay may not be enough. But currently I haven't come up with a good solution
// that can perfectly fix this issue.
QTimer::singleShot(1000, qApp, [parentWindowId, fallbackTitleBarWindowId, hide]() -> void {
if (!resizeFallbackTitleBarWindow(parentWindowId, fallbackTitleBarWindowId, hide)) {
WARNING << "Failed to re-position the fallback title bar window.";
}
});
return true;
}

View File

@ -109,7 +109,7 @@ void framelesshelpercore_initResource()
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcCoreGlobal, "wangwenx190.framelesshelper.core.global")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcCoreGlobal, "wangwenx190.framelesshelper.core.global")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()

View File

@ -44,7 +44,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcFramelessManager, "wangwenx190.framelesshelper.core.framelessmanager")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcFramelessManager, "wangwenx190.framelesshelper.core.framelessmanager")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()

View File

@ -29,6 +29,7 @@
#include "framelessconfig_p.h"
#include "framelesshelpercore_global_p.h"
#include <optional>
#include <memory>
#include <QtCore/qsysinfo.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qmutex.h>
@ -45,7 +46,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcMicaMaterial, "wangwenx190.framelesshelper.core.micamaterial")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcMicaMaterial, "wangwenx190.framelesshelper.core.micamaterial")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()
@ -156,16 +157,12 @@ static inline void qt_blurrow(QImage &im, const int line, const int alpha)
int zR = 0, zG = 0, zB = 0, zA = 0;
#ifdef Q_CC_MSVC
# pragma warning(push)
# pragma warning(disable:4127) // false alarm.
#endif // Q_CC_MSVC
QT_WARNING_PUSH
QT_WARNING_DISABLE_MSVC(4127) // false alarm.
if (alphaOnly && (im.format() != QImage::Format_Indexed8)) {
bptr += alphaIndex;
}
#ifdef Q_CC_MSVC
# pragma warning(pop)
#endif // Q_CC_MSVC
QT_WARNING_POP
const int stride = (im.depth() >> 3);
const int im_width = im.width();
@ -415,8 +412,10 @@ static inline void expblur(QImage &img, qreal radius, const bool improvedQuality
if (p) {
p->save();
p->setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
// We need a blurry image anyway, we don't need high quality image processing.
p->setRenderHint(QPainter::Antialiasing, false);
p->setRenderHint(QPainter::TextAntialiasing, false);
p->setRenderHint(QPainter::SmoothPixmapTransform, false);
p->scale(scale, scale);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 0))
const QSize imageSize = blurImage.deviceIndependentSize().toSize();
@ -564,19 +563,23 @@ protected:
}
QSize newSize = image.size();
newSize.scale(imageSize, mode);
image = image.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
image = image.scaled(newSize);
}
static constexpr const QPoint desktopOriginPoint = {0, 0};
const QRect desktopRect = {desktopOriginPoint, imageSize};
if (aspectStyle == WallpaperAspectStyle::Tile) {
QPainter bufferPainter(&buffer);
bufferPainter.setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
// Same as above, we prefer speed than quality here.
bufferPainter.setRenderHint(QPainter::Antialiasing, false);
bufferPainter.setRenderHint(QPainter::TextAntialiasing, false);
bufferPainter.setRenderHint(QPainter::SmoothPixmapTransform, false);
bufferPainter.fillRect(desktopRect, QBrush(image));
} else {
QPainter bufferPainter(&buffer);
bufferPainter.setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
// Same here.
bufferPainter.setRenderHint(QPainter::Antialiasing, false);
bufferPainter.setRenderHint(QPainter::TextAntialiasing, false);
bufferPainter.setRenderHint(QPainter::SmoothPixmapTransform, false);
const QRect rect = alignedRect(Qt::LeftToRight, Qt::AlignCenter, image.size(), desktopRect);
bufferPainter.drawImage(rect.topLeft(), image);
}
@ -585,12 +588,14 @@ protected:
g_imageData()->blurredWallpaper = QPixmap(imageSize);
g_imageData()->blurredWallpaper.fill(kDefaultTransparentColor);
QPainter painter(&g_imageData()->blurredWallpaper);
painter.setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
// Same here.
painter.setRenderHint(QPainter::Antialiasing, false);
painter.setRenderHint(QPainter::TextAntialiasing, false);
painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
painter.drawImage(desktopOriginPoint, buffer);
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
qt_blurImage(&painter, buffer, kDefaultBlurRadius, true, false);
qt_blurImage(&painter, buffer, kDefaultBlurRadius, false, false);
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
}
Q_EMIT imageUpdated(transform);
@ -673,8 +678,10 @@ void MicaMaterialPrivate::updateMaterialBrush()
fillColor.setAlphaF(0.9f);
micaTexture.fill(fillColor);
QPainter painter(&micaTexture);
painter.setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
// Same as above. We need speed, not quality.
painter.setRenderHint(QPainter::Antialiasing, false);
painter.setRenderHint(QPainter::TextAntialiasing, false);
painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
painter.setOpacity(tintOpacity);
const QRect rect = {QPoint(0, 0), micaTexture.size()};
painter.fillRect(rect, tintColor);
@ -699,8 +706,10 @@ void MicaMaterialPrivate::paint(QPainter *painter, const QRect &rect, const bool
static constexpr const QPoint originPoint = {0, 0};
const QRect mappedRect = mapToWallpaper(rect);
painter->save();
painter->setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
// Same as above. Speed is more important here.
painter->setRenderHint(QPainter::Antialiasing, false);
painter->setRenderHint(QPainter::TextAntialiasing, false);
painter->setRenderHint(QPainter::SmoothPixmapTransform, false);
if (active) {
const QMutexLocker locker(&g_imageData()->mutex);
painter->drawPixmap(originPoint, g_imageData()->blurredWallpaper, mappedRect);

View File

@ -57,7 +57,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcSysApiLoader, "wangwenx190.framelesshelper.core.sysapiloader")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcSysApiLoader, "wangwenx190.framelesshelper.core.sysapiloader")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()
@ -71,14 +71,15 @@ static Q_LOGGING_CATEGORY(lcSysApiLoader, "wangwenx190.framelesshelper.core.sysa
# define CRITICAL qCCritical(lcSysApiLoader)
#endif
struct SysApiLoaderData
{
QHash<QString, QFunctionPointer> functionCache = {};
};
using SysApiLoaderData = QHash<QString, QFunctionPointer>;
Q_GLOBAL_STATIC(SysApiLoaderData, g_sysApiLoaderData)
static const bool LoaderDebugFlag = qEnvironmentVariableIntValue("FRAMELESSHELPER_SYSAPILOADER_DEBUG");
[[nodiscard]] static inline bool isDebug()
{
static const bool flag = qEnvironmentVariableIntValue("FRAMELESSHELPER_SYSAPILOADER_DEBUG");
return flag;
}
SysApiLoader::SysApiLoader(QObject *parent) : QObject(parent)
{
@ -113,11 +114,11 @@ QString SysApiLoader::platformSystemLibraryDirectory()
static const auto result = []() -> QString {
#ifdef Q_OS_WINDOWS
QVarLengthArray<wchar_t, MAX_PATH> buf = {};
const UINT len = GetSystemDirectoryW(buf.data(), MAX_PATH);
const UINT len = ::GetSystemDirectoryW(buf.data(), MAX_PATH);
if (len > MAX_PATH) {
// No need to +1 here, GetSystemDirectoryW() will always give us a null terminator.
buf.resize(len);
GetSystemDirectoryW(buf.data(), len);
::GetSystemDirectoryW(buf.data(), len);
}
return QString::fromWCharArray(buf.constData(), len);
#else
@ -184,16 +185,16 @@ bool SysApiLoader::isAvailable(const QString &library, const QString &function)
return false;
}
const QString key = generateUniqueKey(library, function);
const auto it = g_sysApiLoaderData()->functionCache.constFind(key);
if (it != g_sysApiLoaderData()->functionCache.constEnd()) {
if (LoaderDebugFlag) {
const auto it = g_sysApiLoaderData()->constFind(key);
if (it != g_sysApiLoaderData()->constEnd()) {
if (isDebug()) {
DEBUG << Q_FUNC_INFO << "Function cache found:" << key;
}
return (it.value() != nullptr);
} else {
const QFunctionPointer symbol = SysApiLoader::resolve(library, function);
g_sysApiLoaderData()->functionCache.insert(key, symbol);
if (LoaderDebugFlag) {
g_sysApiLoaderData()->insert(key, symbol);
if (isDebug()) {
DEBUG << Q_FUNC_INFO << "New function cache:" << key << (symbol ? "[VALID]" : "[NULL]");
}
if (symbol) {
@ -214,14 +215,14 @@ QFunctionPointer SysApiLoader::get(const QString &library, const QString &functi
return nullptr;
}
const QString key = generateUniqueKey(library, function);
const auto it = g_sysApiLoaderData()->functionCache.constFind(key);
if (it != g_sysApiLoaderData()->functionCache.constEnd()) {
if (LoaderDebugFlag) {
const auto it = g_sysApiLoaderData()->constFind(key);
if (it != g_sysApiLoaderData()->constEnd()) {
if (isDebug()) {
DEBUG << Q_FUNC_INFO << "Function cache found:" << key;
}
return it.value();
} else {
if (LoaderDebugFlag) {
if (isDebug()) {
DEBUG << Q_FUNC_INFO << "Function cache not found:" << key;
}
return nullptr;

View File

@ -46,7 +46,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcUtilsCommon, "wangwenx190.framelesshelper.core.utils.common")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcUtilsCommon, "wangwenx190.framelesshelper.core.utils.common")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()
@ -69,7 +69,7 @@ struct FONT_ICON
quint32 Fallback = 0;
};
static constexpr const std::array<FONT_ICON, 7> g_fontIconsTable =
static constexpr const std::array<FONT_ICON, static_cast<int>(SystemButtonType::Last) + 1> g_fontIconsTable =
{
FONT_ICON{ 0x0000, 0x0000 },
FONT_ICON{ 0xE756, 0x0000 },

View File

@ -54,7 +54,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcUtilsLinux, "wangwenx190.framelesshelper.core.utils.linux")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcUtilsLinux, "wangwenx190.framelesshelper.core.utils.linux")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()

View File

@ -27,6 +27,8 @@
#include "framelessmanager_p.h"
#include "framelessconfig_p.h"
#include "framelesshelpercore_global_p.h"
#include <functional>
#include <memory>
#include <QtCore/qhash.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qloggingcategory.h>
@ -65,7 +67,7 @@ FRAMELESSHELPER_END_NAMESPACE
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcUtilsMac, "wangwenx190.framelesshelper.core.utils.mac")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcUtilsMac, "wangwenx190.framelesshelper.core.utils.mac")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()
@ -467,11 +469,12 @@ private:
#if 0
const auto nswindow = reinterpret_cast<NSWindow *>(obj);
if (!instances.contains(nswindow)) {
const auto it = instances.find(nswindow);
if (it == instances.end()) {
return;
}
NSWindowProxy * const proxy = instances[nswindow];
NSWindowProxy * const proxy = it.value();
if (event.type == NSEventTypeLeftMouseDown) {
proxy->lastMouseDownEvent = event;
QCoreApplication::processEvents();
@ -510,10 +513,7 @@ private:
static inline sendEventPtr oldSendEvent = nil;
};
struct MacUtilsData
{
QHash<WId, NSWindowProxy *> hash = {};
};
using MacUtilsData = QHash<WId, NSWindowProxy *>;
Q_GLOBAL_STATIC(MacUtilsData, g_macUtilsData);
@ -533,17 +533,18 @@ Q_GLOBAL_STATIC(MacUtilsData, g_macUtilsData);
static inline void cleanupProxy()
{
if (g_macUtilsData()->hash.isEmpty()) {
if (g_macUtilsData()->isEmpty()) {
return;
}
for (auto &&proxy : std::as_const(g_macUtilsData()->hash)) {
const auto &data = *g_macUtilsData();
for (auto &&proxy : std::as_const(data)) {
Q_ASSERT(proxy);
if (!proxy) {
continue;
}
delete proxy;
}
g_macUtilsData()->hash.clear();
g_macUtilsData()->clear();
}
[[nodiscard]] static inline NSWindowProxy *ensureWindowProxy(const WId windowId)
@ -552,7 +553,8 @@ static inline void cleanupProxy()
if (!windowId) {
return nil;
}
if (!g_macUtilsData()->hash.contains(windowId)) {
auto it = g_macUtilsData()->find(windowId);
if (it == g_macUtilsData()->end()) {
QWindow * const qwindow = Utils::findWindow(windowId);
Q_ASSERT(qwindow);
if (!qwindow) {
@ -564,14 +566,14 @@ static inline void cleanupProxy()
return nil;
}
const auto proxy = new NSWindowProxy(qwindow, nswindow);
g_macUtilsData()->hash.insert(windowId, proxy);
it = g_macUtilsData()->insert(windowId, proxy);
}
static bool cleanerInstalled = false;
if (!cleanerInstalled) {
cleanerInstalled = true;
qAddPostRoutine(cleanupProxy);
}
return g_macUtilsData()->hash.value(windowId);
return it.value();
}
void Utils::setSystemTitleBarVisible(const WId windowId, const bool visible)
@ -733,15 +735,16 @@ void Utils::removeWindowProxy(const WId windowId)
if (!windowId) {
return;
}
if (!g_macUtilsData()->hash.contains(windowId)) {
const auto it = g_macUtilsData()->constFind(windowId);
if (it == g_macUtilsData()->constEnd()) {
return;
}
if (const auto proxy = g_macUtilsData()->hash.value(windowId)) {
if (const auto proxy = it.value()) {
// We'll restore everything to default in the destructor,
// so no need to do it manually here.
delete proxy;
}
g_macUtilsData()->hash.remove(windowId);
g_macUtilsData()->erase(it);
}
QColor Utils::getFrameBorderColor(const bool active)

View File

@ -57,7 +57,7 @@ Q_DECLARE_METATYPE(QMargins)
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcUtilsWin, "wangwenx190.framelesshelper.core.utils.win")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcUtilsWin, "wangwenx190.framelesshelper.core.utils.win")
#ifdef FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()
@ -191,13 +191,13 @@ struct Win32UtilsData
SystemParameters params = {};
};
struct Win32UtilsHelper
struct Win32UtilsInternal
{
QHash<WId, Win32UtilsData> data = {};
QList<WId> micaWindowIds = {};
};
Q_GLOBAL_STATIC(Win32UtilsHelper, g_win32UtilsData)
Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData)
[[nodiscard]] bool operator==(const RECT &lhs, const RECT &rhs) noexcept
{
@ -1675,7 +1675,10 @@ void Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle
case WindowCornerStyle::Round:
return _DWMWCP_ROUND;
}
QT_WARNING_PUSH
QT_WARNING_DISABLE_MSVC(4702)
Q_UNREACHABLE_RETURN(_DWMWCP_DEFAULT);
QT_WARNING_POP
}();
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmSetWindowAttribute,
hwnd, _DWMWA_WINDOW_CORNER_PREFERENCE, &wcp, sizeof(wcp));
@ -1728,7 +1731,10 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
}
return BlurMode::Windows_Aero;
}
QT_WARNING_PUSH
QT_WARNING_DISABLE_MSVC(4702)
Q_UNREACHABLE_RETURN(BlurMode::Default);
QT_WARNING_POP
}();
if (blurMode == BlurMode::Disable) {
bool result = true;
@ -1834,7 +1840,10 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
policy.AccentState = ACCENT_ENABLE_BLURBEHIND;
policy.AccentFlags = ACCENT_NONE;
} else {
QT_WARNING_PUSH
QT_WARNING_DISABLE_MSVC(4702)
Q_UNREACHABLE_RETURN(false);
QT_WARNING_POP
}
WINDOWCOMPOSITIONATTRIBDATA wcad;
SecureZeroMemory(&wcad, sizeof(wcad));

View File

@ -67,7 +67,7 @@ void WinVerHelper::initialize()
return;
}
for (int i = 0; i != size; ++i) {
m_flags[i] = (i <= no);
m_flags.at(i) = (i <= no);
}
};
#define ELIF(Version) \

View File

@ -22,8 +22,6 @@
SOFTWARE.
]]
include(GNUInstallDirs)
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif()
@ -260,6 +258,7 @@ target_link_libraries(${SUB_MODULE_TARGET} PUBLIC
${PROJECT_NAME}::Core
)
include(GNUInstallDirs)
target_include_directories(${SUB_MODULE_TARGET} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}/../..>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}>"
@ -269,8 +268,13 @@ target_include_directories(${SUB_MODULE_TARGET} PUBLIC
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_MODULE_PATH}/private>"
)
if(NOT FRAMELESSHELPER_BUILD_STATIC)
setup_target_rpaths(TARGETS ${SUB_MODULE_TARGET})
endif()
setup_qt_stuff(TARGETS ${SUB_MODULE_TARGET} ALLOW_KEYWORD)
set(__extra_flags)
set(__extra_flags "")
if(NOT FRAMELESSHELPER_NO_PERMISSIVE_CHECKS)
list(APPEND __extra_flags PERMISSIVE)
endif()
@ -293,6 +297,7 @@ if(FRAMELESSHELPER_FORCE_LTO)
list(APPEND __extra_flags FORCE_LTO)
endif()
setup_compile_params(TARGETS ${SUB_MODULE_TARGET} ${__extra_flags})
if(NOT FRAMELESSHELPER_NO_INSTALL)
setup_package_export(
TARGETS ${__export_targets}

View File

@ -53,7 +53,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcFramelessQuickHelper, "wangwenx190.framelesshelper.quick.framelessquickhelper")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcFramelessQuickHelper, "wangwenx190.framelesshelper.quick.framelessquickhelper")
#ifdef FRAMELESSHELPER_QUICK_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()
@ -69,7 +69,7 @@ static Q_LOGGING_CATEGORY(lcFramelessQuickHelper, "wangwenx190.framelesshelper.q
using namespace Global;
struct QuickHelperData
struct FramelessQuickHelperData
{
bool ready = false;
SystemParameters params = {};
@ -83,12 +83,9 @@ struct QuickHelperData
QList<QRect> hitTestVisibleRects = {};
};
struct QuickHelper
{
QHash<WId, QuickHelperData> data = {};
};
using FramelessQuickHelperInternal = QHash<WId, FramelessQuickHelperData>;
Q_GLOBAL_STATIC(QuickHelper, g_quickHelper)
Q_GLOBAL_STATIC(FramelessQuickHelperInternal, g_framelessQuickHelperData)
FramelessQuickHelperPrivate::FramelessQuickHelperPrivate(FramelessQuickHelper *q) : QObject(q)
{
@ -128,7 +125,8 @@ const FramelessQuickHelperPrivate *FramelessQuickHelperPrivate::get(const Framel
bool FramelessQuickHelperPrivate::isContentExtendedIntoTitleBar() const
{
return getWindowData().ready;
const FramelessQuickHelperData *data = getWindowData();
return (data ? data->ready : false);
}
void FramelessQuickHelperPrivate::extendsContentIntoTitleBar(const bool value)
@ -149,7 +147,8 @@ void FramelessQuickHelperPrivate::extendsContentIntoTitleBar(const bool value)
QQuickItem *FramelessQuickHelperPrivate::getTitleBarItem() const
{
return getWindowData().titleBarItem;
const FramelessQuickHelperData *data = getWindowData();
return (data ? data->titleBarItem : nullptr);
}
void FramelessQuickHelperPrivate::setTitleBarItem(QQuickItem *value)
@ -158,11 +157,8 @@ void FramelessQuickHelperPrivate::setTitleBarItem(QQuickItem *value)
if (!value) {
return;
}
QuickHelperData *data = getWindowDataMutable();
if (!data) {
return;
}
if (data->titleBarItem == value) {
FramelessQuickHelperData *data = getWindowDataMutable();
if (!data || (data->titleBarItem == value)) {
return;
}
data->titleBarItem = value;
@ -178,7 +174,7 @@ void FramelessQuickHelperPrivate::attach()
return;
}
QuickHelperData * const data = getWindowDataMutable();
FramelessQuickHelperData * const data = getWindowDataMutable();
if (!data || data->ready) {
return;
}
@ -230,7 +226,7 @@ void FramelessQuickHelperPrivate::attach()
// we reach here, and all the modifications from the Qt side will be lost
// due to QPA will reset the position and size of the window during it's
// initialization process.
QTimer::singleShot(0, this, [this](){
QTimer::singleShot(m_qpaWaitTime, this, [this](){
m_qpaReady = true;
if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) {
moveWindowToDesktopCenter();
@ -250,10 +246,11 @@ void FramelessQuickHelperPrivate::detach()
return;
}
const WId windowId = w->winId();
if (!g_quickHelper()->data.contains(windowId)) {
const auto it = g_framelessQuickHelperData()->constFind(windowId);
if (it == g_framelessQuickHelperData()->constEnd()) {
return;
}
g_quickHelper()->data.remove(windowId);
g_framelessQuickHelperData()->erase(it);
FramelessManager::instance()->removeWindow(windowId);
}
@ -264,7 +261,7 @@ void FramelessQuickHelperPrivate::setSystemButton(QQuickItem *item, const QuickG
if (!item || (buttonType == QuickGlobal::SystemButtonType::Unknown)) {
return;
}
QuickHelperData *data = getWindowDataMutable();
FramelessQuickHelperData *data = getWindowDataMutable();
if (!data) {
return;
}
@ -296,15 +293,13 @@ void FramelessQuickHelperPrivate::setHitTestVisible(QQuickItem *item, const bool
if (!item) {
return;
}
QuickHelperData *data = getWindowDataMutable();
FramelessQuickHelperData *data = getWindowDataMutable();
if (!data) {
return;
}
const bool exists = data->hitTestVisibleItems.contains(item);
if (visible && !exists) {
if (visible) {
data->hitTestVisibleItems.append(item);
}
if (!visible && exists) {
} else {
data->hitTestVisibleItems.removeAll(item);
}
}
@ -315,15 +310,13 @@ void FramelessQuickHelperPrivate::setHitTestVisible(const QRect &rect, const boo
if (!rect.isValid()) {
return;
}
QuickHelperData *data = getWindowDataMutable();
FramelessQuickHelperData *data = getWindowDataMutable();
if (!data) {
return;
}
const bool exists = data->hitTestVisibleRects.contains(rect);
if (visible && !exists) {
if (visible) {
data->hitTestVisibleRects.append(rect);
}
if (!visible && exists) {
} else {
data->hitTestVisibleRects.removeAll(rect);
}
}
@ -352,8 +345,7 @@ void FramelessQuickHelperPrivate::showSystemMenu(const QPoint &pos)
const WId windowId = window->winId();
const QPoint nativePos = Utils::toNativeGlobalPosition(window, pos);
#ifdef Q_OS_WINDOWS
const SystemParameters params = getWindowData().params;
Utils::showSystemMenu(windowId, nativePos, false, &params);
Utils::showSystemMenu(windowId, nativePos, false, &getWindowData()->params);
#elif defined(Q_OS_LINUX)
Utils::openSystemMenu(windowId, nativePos);
#else
@ -392,8 +384,7 @@ void FramelessQuickHelperPrivate::moveWindowToDesktopCenter()
if (!window) {
return;
}
const SystemParameters params = getWindowData().params;
Utils::moveWindowToDesktopCenter(&params, true);
Utils::moveWindowToDesktopCenter(&getWindowData()->params, true);
}
void FramelessQuickHelperPrivate::bringWindowToFront()
@ -677,7 +668,7 @@ void FramelessQuickHelperPrivate::waitForReady()
#endif
}
void FramelessQuickHelperPrivate::repaintAllChildren(const int delay) const
void FramelessQuickHelperPrivate::repaintAllChildren(const quint32 delay) const
{
Q_Q(const FramelessQuickHelper);
QQuickWindow * const window = q->window();
@ -709,6 +700,19 @@ void FramelessQuickHelperPrivate::repaintAllChildren(const int delay) const
}
}
quint32 FramelessQuickHelperPrivate::readyWaitTime() const
{
return m_qpaWaitTime;
}
void FramelessQuickHelperPrivate::setReadyWaitTime(const quint32 time)
{
if (m_qpaWaitTime == time) {
return;
}
m_qpaWaitTime = time;
}
QRect FramelessQuickHelperPrivate::mapItemGeometryToScene(const QQuickItem * const item) const
{
Q_ASSERT(item);
@ -730,34 +734,37 @@ bool FramelessQuickHelperPrivate::isInSystemButtons(const QPoint &pos, QuickGlob
if (!button) {
return false;
}
const FramelessQuickHelperData *data = getWindowData();
if (!data) {
return false;
}
*button = QuickGlobal::SystemButtonType::Unknown;
const QuickHelperData data = getWindowData();
if (data.windowIconButton && data.windowIconButton->isVisible() && data.windowIconButton->isEnabled()) {
if (mapItemGeometryToScene(data.windowIconButton).contains(pos)) {
if (data->windowIconButton && data->windowIconButton->isVisible() && data->windowIconButton->isEnabled()) {
if (mapItemGeometryToScene(data->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 (data->contextHelpButton && data->contextHelpButton->isVisible() && data->contextHelpButton->isEnabled()) {
if (mapItemGeometryToScene(data->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 (data->minimizeButton && data->minimizeButton->isVisible() && data->minimizeButton->isEnabled()) {
if (mapItemGeometryToScene(data->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 (data->maximizeButton && data->maximizeButton->isVisible() && data->maximizeButton->isEnabled()) {
if (mapItemGeometryToScene(data->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 (data->closeButton && data->closeButton->isVisible() && data->closeButton->isEnabled()) {
if (mapItemGeometryToScene(data->closeButton).contains(pos)) {
*button = QuickGlobal::SystemButtonType::Close;
return true;
}
@ -767,12 +774,15 @@ bool FramelessQuickHelperPrivate::isInSystemButtons(const QPoint &pos, QuickGlob
bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) const
{
const QuickHelperData data = getWindowData();
if (!data.titleBarItem) {
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()) {
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;
}
@ -784,29 +794,32 @@ bool FramelessQuickHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) c
return false;
}
const QRect windowRect = {QPoint(0, 0), window->size()};
const QRect titleBarRect = mapItemGeometryToScene(data.titleBarItem);
const QRect titleBarRect = mapItemGeometryToScene(data->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.
return false;
}
QRegion region = titleBarRect;
const auto systemButtons = {data.windowIconButton, data.contextHelpButton,
data.minimizeButton, data.maximizeButton, data.closeButton};
const auto systemButtons = {
data->windowIconButton, data->contextHelpButton,
data->minimizeButton, data->maximizeButton,
data->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 (!data->hitTestVisibleItems.isEmpty()) {
for (auto &&item : std::as_const(data->hitTestVisibleItems)) {
if (item && item->isVisible() && item->isEnabled()) {
region -= mapItemGeometryToScene(item);
}
}
}
if (!data.hitTestVisibleRects.isEmpty()) {
for (auto &&rect : std::as_const(data.hitTestVisibleRects)) {
if (!data->hitTestVisibleRects.isEmpty()) {
for (auto &&rect : std::as_const(data->hitTestVisibleRects)) {
if (rect.isValid()) {
region -= rect;
}
@ -848,41 +861,44 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System
if (button == QuickGlobal::SystemButtonType::Unknown) {
return;
}
const QuickHelperData data = getWindowData();
const FramelessQuickHelperData *data = getWindowData();
if (!data) {
return;
}
QQuickAbstractButton *quickButton = nullptr;
switch (button) {
case QuickGlobal::SystemButtonType::WindowIcon:
if (data.windowIconButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data.windowIconButton)) {
if (data->windowIconButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data->windowIconButton)) {
quickButton = btn;
}
}
break;
case QuickGlobal::SystemButtonType::Help:
if (data.contextHelpButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data.contextHelpButton)) {
if (data->contextHelpButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data->contextHelpButton)) {
quickButton = btn;
}
}
break;
case QuickGlobal::SystemButtonType::Minimize:
if (data.minimizeButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data.minimizeButton)) {
if (data->minimizeButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data->minimizeButton)) {
quickButton = btn;
}
}
break;
case QuickGlobal::SystemButtonType::Maximize:
case QuickGlobal::SystemButtonType::Restore:
if (data.maximizeButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data.maximizeButton)) {
if (data->maximizeButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data->maximizeButton)) {
quickButton = btn;
}
}
break;
case QuickGlobal::SystemButtonType::Close:
if (data.closeButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data.closeButton)) {
if (data->closeButton) {
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data->closeButton)) {
quickButton = btn;
}
}
@ -923,22 +939,7 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System
#endif // FRAMELESSHELPER_QUICK_NO_PRIVATE
}
QuickHelperData FramelessQuickHelperPrivate::getWindowData() const
{
Q_Q(const FramelessQuickHelper);
const QQuickWindow * const window = q->window();
//Q_ASSERT(window);
if (!window) {
return {};
}
const WId windowId = window->winId();
if (!g_quickHelper()->data.contains(windowId)) {
g_quickHelper()->data.insert(windowId, {});
}
return g_quickHelper()->data.value(windowId);
}
QuickHelperData *FramelessQuickHelperPrivate::getWindowDataMutable() const
const FramelessQuickHelperData *FramelessQuickHelperPrivate::getWindowData() const
{
Q_Q(const FramelessQuickHelper);
const QQuickWindow * const window = q->window();
@ -947,10 +948,27 @@ QuickHelperData *FramelessQuickHelperPrivate::getWindowDataMutable() const
return nullptr;
}
const WId windowId = window->winId();
if (!g_quickHelper()->data.contains(windowId)) {
g_quickHelper()->data.insert(windowId, {});
auto it = g_framelessQuickHelperData()->find(windowId);
if (it == g_framelessQuickHelperData()->end()) {
it = g_framelessQuickHelperData()->insert(windowId, {});
}
return &g_quickHelper()->data[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()

View File

@ -40,11 +40,11 @@
#include <QtCore/qloggingcategory.h>
#ifndef QUICK_URI_SHORT
# define QUICK_URI_SHORT FRAMELESSHELPER_QUICK_URI, 1
# define QUICK_URI_SHORT FRAMELESSHELPER_QUICK_URI, FRAMELESSHELPER_QUICK_VERSION_MAJOR
#endif
#ifndef QUICK_URI_FULL
# define QUICK_URI_FULL QUICK_URI_SHORT, 0
# define QUICK_URI_FULL QUICK_URI_SHORT, FRAMELESSHELPER_QUICK_VERSION_MINOR
#endif
#ifndef QUICK_URI_EXPAND

View File

@ -32,7 +32,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcQuickImageItem, "wangwenx190.framelesshelper.quick.quickimageitem")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcQuickImageItem, "wangwenx190.framelesshelper.quick.quickimageitem")
#ifdef FRAMELESSHELPER_QUICK_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()

View File

@ -27,6 +27,7 @@
#include <FramelessHelper/Core/micamaterial.h>
#include <FramelessHelper/Core/framelessmanager.h>
#include <FramelessHelper/Core/private/micamaterial_p.h>
#include <memory>
#include <QtCore/qloggingcategory.h>
#include <QtGui/qpainter.h>
#include <QtQuick/qquickwindow.h>
@ -73,7 +74,7 @@ private:
private:
QPointer<QuickMicaMaterial> m_item = nullptr;
QSGSimpleTextureNode *m_node = nullptr;
std::unique_ptr<QSGSimpleTextureNode> m_node = nullptr;
std::unique_ptr<QSGTexture> m_texture = nullptr;
QPointer<MicaMaterial> m_mica{ nullptr };
QPointer<MicaMaterialPrivate> m_micaPriv{ nullptr };
@ -101,14 +102,13 @@ void WallpaperImageNode::initialize()
m_mica = QuickMicaMaterialPrivate::get(m_item)->m_micaMaterial;
m_micaPriv = MicaMaterialPrivate::get(m_mica);
// QtQuick's render engine will free it when appropriate.
m_node = new QSGSimpleTextureNode;
m_node = std::make_unique<QSGSimpleTextureNode>();
m_node->setFiltering(QSGTexture::Linear);
maybeGenerateWallpaperImageCache();
maybeUpdateWallpaperImageClipRect();
appendChildNode(m_node);
appendChildNode(m_node.get());
connect(m_window, &QQuickWindow::beforeRendering, this,
&WallpaperImageNode::maybeUpdateWallpaperImageClipRect, Qt::DirectConnection);
@ -178,9 +178,14 @@ void QuickMicaMaterialPrivate::initialize()
{
Q_Q(QuickMicaMaterial);
// Without this flag, our QQuickItem won't paint anything.
// We MUST enable this flag manually if we want to create a visible item.
q->setFlag(QuickMicaMaterial::ItemHasContents);
q->setSmooth(true);
q->setAntialiasing(true);
// No smooth needed.
q->setSmooth(false);
// We don't need anti-aliasing.
q->setAntialiasing(false);
// Enable clipping, to improve performance in some certain cases.
q->setClip(true);
m_micaMaterial = new MicaMaterial(this);
@ -260,9 +265,6 @@ void QuickMicaMaterialPrivate::appendNode(WallpaperImageNode *node)
if (!node) {
return;
}
if (m_nodes.contains(node)) {
return;
}
m_nodes.append(node);
}
@ -272,9 +274,6 @@ void QuickMicaMaterialPrivate::removeNode(WallpaperImageNode *node)
if (!node) {
return;
}
if (!m_nodes.contains(node)) {
return;
}
m_nodes.removeAll(node);
}

View File

@ -41,7 +41,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcQuickStandardTitleBar, "wangwenx190.framelesshelper.quick.quickstandardtitlebar")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcQuickStandardTitleBar, "wangwenx190.framelesshelper.quick.quickstandardtitlebar")
#ifdef FRAMELESSHELPER_QUICK_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()

View File

@ -22,8 +22,6 @@
SOFTWARE.
]]
include(GNUInstallDirs)
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif()
@ -147,6 +145,7 @@ target_link_libraries(${SUB_MODULE_TARGET} PUBLIC
${PROJECT_NAME}::Core
)
include(GNUInstallDirs)
target_include_directories(${SUB_MODULE_TARGET} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}/../..>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}>"
@ -156,8 +155,13 @@ target_include_directories(${SUB_MODULE_TARGET} PUBLIC
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_MODULE_PATH}/private>"
)
if(NOT FRAMELESSHELPER_BUILD_STATIC)
setup_target_rpaths(TARGETS ${SUB_MODULE_TARGET})
endif()
setup_qt_stuff(TARGETS ${SUB_MODULE_TARGET})
set(__extra_flags)
set(__extra_flags "")
if(NOT FRAMELESSHELPER_NO_PERMISSIVE_CHECKS)
list(APPEND __extra_flags PERMISSIVE)
endif()
@ -180,6 +184,7 @@ if(FRAMELESSHELPER_FORCE_LTO)
list(APPEND __extra_flags FORCE_LTO)
endif()
setup_compile_params(TARGETS ${SUB_MODULE_TARGET} ${__extra_flags})
if(NOT FRAMELESSHELPER_NO_INSTALL)
setup_package_export(
TARGETS ${SUB_MODULE_TARGET}

View File

@ -49,7 +49,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcFramelessWidgetsHelper, "wangwenx190.framelesshelper.widgets.framelesswidgetshelper")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcFramelessWidgetsHelper, "wangwenx190.framelesshelper.widgets.framelesswidgetshelper")
#ifdef FRAMELESSHELPER_WIDGETS_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()
@ -65,7 +65,7 @@ static Q_LOGGING_CATEGORY(lcFramelessWidgetsHelper, "wangwenx190.framelesshelper
using namespace Global;
struct WidgetsHelperData
struct FramelessWidgetsHelperData
{
bool ready = false;
SystemParameters params = {};
@ -79,12 +79,9 @@ struct WidgetsHelperData
QList<QRect> hitTestVisibleRects = {};
};
struct WidgetsHelper
{
QHash<WId, WidgetsHelperData> data = {};
};
using FramelessWidgetsHelperInternal = QHash<WId, FramelessWidgetsHelperData>;
Q_GLOBAL_STATIC(WidgetsHelper, g_widgetsHelper)
Q_GLOBAL_STATIC(FramelessWidgetsHelperInternal, g_framelessWidgetsHelperData)
[[nodiscard]] static inline bool isWidgetFixedSize(const QWidget * const widget)
{
@ -408,7 +405,7 @@ void FramelessWidgetsHelperPrivate::waitForReady()
#endif
}
void FramelessWidgetsHelperPrivate::repaintAllChildren(const int delay) const
void FramelessWidgetsHelperPrivate::repaintAllChildren(const quint32 delay) const
{
if (!m_window) {
return;
@ -430,9 +427,23 @@ void FramelessWidgetsHelperPrivate::repaintAllChildren(const int delay) const
}
}
quint32 FramelessWidgetsHelperPrivate::readyWaitTime() const
{
return m_qpaWaitTime;
}
void FramelessWidgetsHelperPrivate::setReadyWaitTime(const quint32 time)
{
if (m_qpaWaitTime == time) {
return;
}
m_qpaWaitTime = time;
}
bool FramelessWidgetsHelperPrivate::isContentExtendedIntoTitleBar() const
{
return getWindowData().ready;
const FramelessWidgetsHelperData *data = getWindowData();
return (data ? data->ready : false);
}
void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
@ -441,11 +452,8 @@ void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
if (!widget) {
return;
}
WidgetsHelperData *data = getWindowDataMutable();
if (!data) {
return;
}
if (data->titleBarWidget == widget) {
FramelessWidgetsHelperData *data = getWindowDataMutable();
if (!data || (data->titleBarWidget == widget)) {
return;
}
data->titleBarWidget = widget;
@ -454,7 +462,8 @@ void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
QWidget *FramelessWidgetsHelperPrivate::getTitleBarWidget() const
{
return getWindowData().titleBarWidget;
const FramelessWidgetsHelperData *data = getWindowData();
return (data ? data->titleBarWidget : nullptr);
}
void FramelessWidgetsHelperPrivate::setHitTestVisible(QWidget *widget, const bool visible)
@ -463,15 +472,13 @@ void FramelessWidgetsHelperPrivate::setHitTestVisible(QWidget *widget, const boo
if (!widget) {
return;
}
WidgetsHelperData *data = getWindowDataMutable();
FramelessWidgetsHelperData *data = getWindowDataMutable();
if (!data) {
return;
}
const bool exists = data->hitTestVisibleWidgets.contains(widget);
if (visible && !exists) {
if (visible) {
data->hitTestVisibleWidgets.append(widget);
}
if (!visible && exists) {
} else {
data->hitTestVisibleWidgets.removeAll(widget);
}
}
@ -482,15 +489,13 @@ void FramelessWidgetsHelperPrivate::setHitTestVisible(const QRect &rect, const b
if (!rect.isValid()) {
return;
}
WidgetsHelperData *data = getWindowDataMutable();
FramelessWidgetsHelperData *data = getWindowDataMutable();
if (!data) {
return;
}
const bool exists = data->hitTestVisibleRects.contains(rect);
if (visible && !exists) {
if (visible) {
data->hitTestVisibleRects.append(rect);
}
if (!visible && exists) {
} else {
data->hitTestVisibleRects.removeAll(rect);
}
}
@ -528,7 +533,7 @@ void FramelessWidgetsHelperPrivate::attach()
window->setAttribute(Qt::WA_NativeWindow);
}
WidgetsHelperData * const data = getWindowDataMutable();
FramelessWidgetsHelperData * const data = getWindowDataMutable();
if (!data || data->ready) {
return;
}
@ -578,7 +583,7 @@ void FramelessWidgetsHelperPrivate::attach()
// we reach here, and all the modifications from the Qt side will be lost
// due to QPA will reset the position and size of the window during it's
// initialization process.
QTimer::singleShot(0, this, [this](){
QTimer::singleShot(m_qpaWaitTime, this, [this](){
m_qpaReady = true;
if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) {
moveWindowToDesktopCenter();
@ -597,10 +602,11 @@ void FramelessWidgetsHelperPrivate::detach()
return;
}
const WId windowId = m_window->winId();
if (!g_widgetsHelper()->data.contains(windowId)) {
const auto it = g_framelessWidgetsHelperData()->constFind(windowId);
if (it == g_framelessWidgetsHelperData()->constEnd()) {
return;
}
g_widgetsHelper()->data.remove(windowId);
g_framelessWidgetsHelperData()->erase(it);
FramelessManager::instance()->removeWindow(windowId);
m_window = nullptr;
emitSignalForAllInstances("windowChanged");
@ -634,30 +640,32 @@ QWidget *FramelessWidgetsHelperPrivate::findTopLevelWindow() const
return nullptr;
}
WidgetsHelperData FramelessWidgetsHelperPrivate::getWindowData() const
{
//Q_ASSERT(m_window);
if (!m_window) {
return {};
}
const WId windowId = m_window->winId();
if (!g_widgetsHelper()->data.contains(windowId)) {
g_widgetsHelper()->data.insert(windowId, {});
}
return g_widgetsHelper()->data.value(windowId);
}
WidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowDataMutable() const
const FramelessWidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowData() const
{
//Q_ASSERT(m_window);
if (!m_window) {
return nullptr;
}
const WId windowId = m_window->winId();
if (!g_widgetsHelper()->data.contains(windowId)) {
g_widgetsHelper()->data.insert(windowId, {});
auto it = g_framelessWidgetsHelperData()->find(windowId);
if (it == g_framelessWidgetsHelperData()->end()) {
it = g_framelessWidgetsHelperData()->insert(windowId, {});
}
return &g_widgetsHelper()->data[windowId];
return &it.value();
}
FramelessWidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowDataMutable() const
{
//Q_ASSERT(m_window);
if (!m_window) {
return nullptr;
}
const WId windowId = m_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
@ -680,34 +688,37 @@ bool FramelessWidgetsHelperPrivate::isInSystemButtons(const QPoint &pos, SystemB
if (!button) {
return false;
}
const FramelessWidgetsHelperData *data = getWindowData();
if (!data) {
return false;
}
*button = SystemButtonType::Unknown;
const WidgetsHelperData data = getWindowData();
if (data.windowIconButton && data.windowIconButton->isVisible() && data.windowIconButton->isEnabled()) {
if (data.windowIconButton->geometry().contains(pos)) {
if (data->windowIconButton && data->windowIconButton->isVisible() && data->windowIconButton->isEnabled()) {
if (data->windowIconButton->geometry().contains(pos)) {
*button = SystemButtonType::WindowIcon;
return true;
}
}
if (data.contextHelpButton && data.contextHelpButton->isVisible() && data.contextHelpButton->isEnabled()) {
if (data.contextHelpButton->geometry().contains(pos)) {
if (data->contextHelpButton && data->contextHelpButton->isVisible() && data->contextHelpButton->isEnabled()) {
if (data->contextHelpButton->geometry().contains(pos)) {
*button = SystemButtonType::Help;
return true;
}
}
if (data.minimizeButton && data.minimizeButton->isVisible() && data.minimizeButton->isEnabled()) {
if (data.minimizeButton->geometry().contains(pos)) {
if (data->minimizeButton && data->minimizeButton->isVisible() && data->minimizeButton->isEnabled()) {
if (data->minimizeButton->geometry().contains(pos)) {
*button = SystemButtonType::Minimize;
return true;
}
}
if (data.maximizeButton && data.maximizeButton->isVisible() && data.maximizeButton->isEnabled()) {
if (data.maximizeButton->geometry().contains(pos)) {
if (data->maximizeButton && data->maximizeButton->isVisible() && data->maximizeButton->isEnabled()) {
if (data->maximizeButton->geometry().contains(pos)) {
*button = SystemButtonType::Maximize;
return true;
}
}
if (data.closeButton && data.closeButton->isVisible() && data.closeButton->isEnabled()) {
if (data.closeButton->geometry().contains(pos)) {
if (data->closeButton && data->closeButton->isVisible() && data->closeButton->isEnabled()) {
if (data->closeButton->geometry().contains(pos)) {
*button = SystemButtonType::Close;
return true;
}
@ -717,12 +728,15 @@ bool FramelessWidgetsHelperPrivate::isInSystemButtons(const QPoint &pos, SystemB
bool FramelessWidgetsHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos) const
{
const WidgetsHelperData data = getWindowData();
if (!data.titleBarWidget) {
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()) {
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;
}
@ -732,29 +746,32 @@ bool FramelessWidgetsHelperPrivate::isInTitleBarDraggableArea(const QPoint &pos)
return false;
}
const QRect windowRect = {QPoint(0, 0), m_window->size()};
const QRect titleBarRect = mapWidgetGeometryToScene(data.titleBarWidget);
const QRect titleBarRect = mapWidgetGeometryToScene(data->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.
return false;
}
QRegion region = titleBarRect;
const auto systemButtons = {data.windowIconButton, data.contextHelpButton,
data.minimizeButton, data.maximizeButton, data.closeButton};
const auto systemButtons = {
data->windowIconButton, data->contextHelpButton,
data->minimizeButton, data->maximizeButton,
data->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 (!data->hitTestVisibleWidgets.isEmpty()) {
for (auto &&widget : std::as_const(data->hitTestVisibleWidgets)) {
if (widget && widget->isVisible() && widget->isEnabled()) {
region -= mapWidgetGeometryToScene(widget);
}
}
}
if (!data.hitTestVisibleRects.isEmpty()) {
for (auto &&rect : std::as_const(data.hitTestVisibleRects)) {
if (!data->hitTestVisibleRects.isEmpty()) {
for (auto &&rect : std::as_const(data->hitTestVisibleRects)) {
if (rect.isValid()) {
region -= rect;
}
@ -789,33 +806,36 @@ void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType
if (button == SystemButtonType::Unknown) {
return;
}
const WidgetsHelperData data = getWindowData();
const FramelessWidgetsHelperData *data = getWindowData();
if (!data) {
return;
}
QWidget *widgetButton = nullptr;
switch (button) {
case SystemButtonType::WindowIcon:
if (data.windowIconButton) {
widgetButton = data.windowIconButton;
if (data->windowIconButton) {
widgetButton = data->windowIconButton;
}
break;
case SystemButtonType::Help:
if (data.contextHelpButton) {
widgetButton = data.contextHelpButton;
if (data->contextHelpButton) {
widgetButton = data->contextHelpButton;
}
break;
case SystemButtonType::Minimize:
if (data.minimizeButton) {
widgetButton = data.minimizeButton;
if (data->minimizeButton) {
widgetButton = data->minimizeButton;
}
break;
case SystemButtonType::Maximize:
case SystemButtonType::Restore:
if (data.maximizeButton) {
widgetButton = data.maximizeButton;
if (data->maximizeButton) {
widgetButton = data->maximizeButton;
}
break;
case SystemButtonType::Close:
if (data.closeButton) {
widgetButton = data.closeButton;
if (data->closeButton) {
widgetButton = data->closeButton;
}
break;
case SystemButtonType::Unknown:
@ -866,8 +886,7 @@ void FramelessWidgetsHelperPrivate::moveWindowToDesktopCenter()
if (!m_window) {
return;
}
const SystemParameters params = getWindowData().params;
Utils::moveWindowToDesktopCenter(&params, true);
Utils::moveWindowToDesktopCenter(&getWindowData()->params, true);
}
void FramelessWidgetsHelperPrivate::bringWindowToFront()
@ -897,8 +916,7 @@ void FramelessWidgetsHelperPrivate::showSystemMenu(const QPoint &pos)
const WId windowId = m_window->winId();
const QPoint nativePos = Utils::toNativeGlobalPosition(m_window->windowHandle(), pos);
#ifdef Q_OS_WINDOWS
const SystemParameters params = getWindowData().params;
Utils::showSystemMenu(windowId, nativePos, false, &params);
Utils::showSystemMenu(windowId, nativePos, false, &getWindowData()->params);
#elif defined(Q_OS_LINUX)
Utils::openSystemMenu(windowId, nativePos);
#else
@ -933,7 +951,7 @@ void FramelessWidgetsHelperPrivate::setSystemButton(QWidget *widget, const Syste
if (!widget || (buttonType == SystemButtonType::Unknown)) {
return;
}
WidgetsHelperData *data = getWindowDataMutable();
FramelessWidgetsHelperData *data = getWindowDataMutable();
if (!data) {
return;
}

View File

@ -177,6 +177,7 @@ void StandardSystemButtonPrivate::setHovered(const bool value)
m_hovered = value;
Q_Q(StandardSystemButton);
q->update();
#if 0
if (m_hovered) {
const QString toolTip = q->toolTip();
if (!toolTip.isEmpty() && !QToolTip::isVisible()) {
@ -184,10 +185,10 @@ void StandardSystemButtonPrivate::setHovered(const bool value)
static const int h = kDefaultSystemButtonSize.height();
if (const QWidget * const window = q->window()) {
if (Utils::windowStatesToWindowState(window->windowState()) == Qt::WindowMaximized) {
return std::round(h * 0.5);
return std::round(qreal(h) * qreal(0.5));
}
}
return -std::round(h * 1.3);
return -std::round(qreal(h) * qreal(1.3));
}();
QToolTip::showText(q->mapToGlobal(QPoint(-2, yPos)), toolTip, q, q->geometry());
}
@ -196,6 +197,7 @@ void StandardSystemButtonPrivate::setHovered(const bool value)
QToolTip::hideText();
}
}
#endif
Q_EMIT q->hoveredChanged();
}

View File

@ -37,7 +37,7 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(lcStandardTitleBar, "wangwenx190.framelesshelper.widgets.standardtitlebar")
[[maybe_unused]] static Q_LOGGING_CATEGORY(lcStandardTitleBar, "wangwenx190.framelesshelper.widgets.standardtitlebar")
#ifdef FRAMELESSHELPER_WIDGETS_NO_DEBUG_OUTPUT
# define INFO QT_NO_QDEBUG_MACRO()

View File

@ -240,7 +240,7 @@ void WidgetsSharedHelper::handleScreenChanged(QScreen *screen)
this, [this](const qreal dpi){
Q_UNUSED(dpi);
const qreal currentDpr = m_screen->devicePixelRatio();
if (m_screenDpr == currentDpr) {
if (qFuzzyCompare(m_screenDpr, currentDpr)) {
return;
}
m_screenDpr = currentDpr;