centralize how we handle global options

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-05-08 16:09:00 +08:00
parent 286811c9df
commit 053d6b104e
33 changed files with 438 additions and 166 deletions

View File

@ -1,5 +1,9 @@
# FramelessHelper 2.x # FramelessHelper 2.x
## Join with us :triangular_flag_on_post:
You can join our <a href="https://discord.gg/Rc6r9J3uZw">Discord Channel</a> to communicate with us. You can share your findings, thoughts and ideas on improving / implementing FramelessHelper functionalities on more platforms and apps!
## Highlights compared to 2.1 (TODO list) ## Highlights compared to 2.1 (TODO list)
- Common: Added cross-platform customizable system menu for both Qt Widgets and Qt Quick. Also supports both light and dark theme. - Common: Added cross-platform customizable system menu for both Qt Widgets and Qt Quick. Also supports both light and dark theme.

View File

@ -26,7 +26,7 @@
#include <QtCore/qdatetime.h> #include <QtCore/qdatetime.h>
#include <QtWidgets/qlabel.h> #include <QtWidgets/qlabel.h>
#include <QtWidgets/qboxlayout.h> #include <QtWidgets/qboxlayout.h>
#include <FramelessWindowsManager> #include <FramelessManager>
#include <Utils> #include <Utils>
#include <FramelessWidgetsHelper> #include <FramelessWidgetsHelper>
#include <StandardTitleBar> #include <StandardTitleBar>
@ -40,7 +40,7 @@ Widget::Widget(QWidget *parent) : FramelessWidget(parent)
{ {
initialize(); initialize();
startTimer(500); startTimer(500);
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &Widget::updateStyleSheet); connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &Widget::updateStyleSheet);
} }
Widget::~Widget() = default; Widget::~Widget() = default;

View File

@ -0,0 +1 @@
#include <framelessmanager.h>

View File

@ -1 +0,0 @@
#include <framelesswindowsmanager.h>

View File

@ -183,14 +183,15 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
[[maybe_unused]] static Q_CONSTEXPR2 const QColor kDefaultSystemButtonBackgroundColor = {204, 204, 204}; // #CCCCCC [[maybe_unused]] static Q_CONSTEXPR2 const QColor kDefaultSystemButtonBackgroundColor = {204, 204, 204}; // #CCCCCC
[[maybe_unused]] static Q_CONSTEXPR2 const QColor kDefaultSystemCloseButtonBackgroundColor = {232, 17, 35}; // #E81123 [[maybe_unused]] static Q_CONSTEXPR2 const QColor kDefaultSystemCloseButtonBackgroundColor = {232, 17, 35}; // #E81123
[[maybe_unused]] static constexpr const char kUsePureQtImplFlag[] = "FRAMELESSHELPER_PURE_QT_IMPLEMENTATION"; enum class Option
[[maybe_unused]] static constexpr const char kForceHideFrameBorderFlag[] = "FRAMELESSHELPER_FORCE_HIDE_FRAME_BORDER"; {
[[maybe_unused]] static constexpr const char kForceShowFrameBorderFlag[] = "FRAMELESSHELPER_FORCE_SHOW_FRAME_BORDER"; UseCrossPlatformQtImplementation = 0,
ForceHideWindowFrameBorder = 1,
FRAMELESSHELPER_STRING_CONSTANT2(ConfigFileName, ".framelesshelper.ini") ForceShowWindowFrameBorder = 2,
FRAMELESSHELPER_STRING_CONSTANT2(UsePureQtImplKeyPath, "Options/UsePureQtImplementation") DisableWindowsSnapLayouts = 3,
FRAMELESSHELPER_STRING_CONSTANT2(ForceHideFrameBorderKeyPath, "Options/ForceHideFrameBorder") WindowUseRoundCorners = 4
FRAMELESSHELPER_STRING_CONSTANT2(ForceShowFrameBorderKeyPath, "Options/ForceShowFrameBorder") };
Q_ENUM_NS(Option)
enum class SystemTheme enum class SystemTheme
{ {
@ -477,7 +478,7 @@ struct SystemParameters
{10, 0, 19044}, // Windows 10 Version 21H2 (November 2021 Update) (21H2) {10, 0, 19044}, // Windows 10 Version 21H2 (November 2021 Update) (21H2)
{10, 0, 22000}, // Windows 11 Version 21H2 (21H2) {10, 0, 22000}, // Windows 11 Version 21H2 (21H2)
}; };
static_assert((sizeof(WindowsVersions) / sizeof(WindowsVersions[0])) == (static_cast<int>(WindowsVersion::_11_21H2) + 1)); static_assert(std::size(WindowsVersions) == (static_cast<int>(WindowsVersion::_11_21H2) + 1));
} // namespace Global } // namespace Global

View File

@ -29,24 +29,22 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessWindowsManagerPrivate; class FramelessManagerPrivate;
class FRAMELESSHELPER_CORE_API FramelessWindowsManager : public QObject class FRAMELESSHELPER_CORE_API FramelessManager : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_DECLARE_PRIVATE(FramelessWindowsManager) Q_DECLARE_PRIVATE(FramelessManager)
Q_DISABLE_COPY_MOVE(FramelessWindowsManager) Q_DISABLE_COPY_MOVE(FramelessManager)
Q_PROPERTY(bool usePureQtImplementation READ usePureQtImplementation CONSTANT FINAL)
Q_PROPERTY(Global::SystemTheme systemTheme READ systemTheme NOTIFY systemThemeChanged FINAL) Q_PROPERTY(Global::SystemTheme systemTheme READ systemTheme NOTIFY systemThemeChanged FINAL)
Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemThemeChanged FINAL) Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemThemeChanged FINAL)
public: public:
explicit FramelessWindowsManager(QObject *parent = nullptr); explicit FramelessManager(QObject *parent = nullptr);
~FramelessWindowsManager() override; ~FramelessManager() override;
Q_NODISCARD static FramelessWindowsManager *instance(); Q_NODISCARD static FramelessManager *instance();
Q_NODISCARD bool usePureQtImplementation() const;
Q_NODISCARD Global::SystemTheme systemTheme() const; Q_NODISCARD Global::SystemTheme systemTheme() const;
Q_NODISCARD QColor systemAccentColor() const; Q_NODISCARD QColor systemAccentColor() const;
@ -57,7 +55,7 @@ Q_SIGNALS:
void systemThemeChanged(); void systemThemeChanged();
private: private:
QScopedPointer<FramelessWindowsManagerPrivate> d_ptr; QScopedPointer<FramelessManagerPrivate> d_ptr;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -0,0 +1,49 @@
/*
* MIT License
*
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include "framelesshelpercore_global.h"
#include <QtCore/qobject.h>
FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_CORE_API FramelessConfig : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(FramelessConfig)
public:
explicit FramelessConfig(QObject *parent = nullptr);
~FramelessConfig() override;
Q_NODISCARD static FramelessConfig *instance();
void reload(const bool force = false);
void set(const Global::Option option, const bool on = true);
Q_NODISCARD bool isSet(const Global::Option option) const;
};
FRAMELESSHELPER_END_NAMESPACE

View File

@ -29,22 +29,21 @@
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessWindowsManager; class FramelessManager;
class FRAMELESSHELPER_CORE_API FramelessWindowsManagerPrivate : public QObject class FRAMELESSHELPER_CORE_API FramelessManagerPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_DECLARE_PUBLIC(FramelessWindowsManager) Q_DECLARE_PUBLIC(FramelessManager)
Q_DISABLE_COPY_MOVE(FramelessWindowsManagerPrivate) Q_DISABLE_COPY_MOVE(FramelessManagerPrivate)
public: public:
explicit FramelessWindowsManagerPrivate(FramelessWindowsManager *q); explicit FramelessManagerPrivate(FramelessManager *q);
~FramelessWindowsManagerPrivate() override; ~FramelessManagerPrivate() override;
Q_NODISCARD static FramelessWindowsManagerPrivate *get(FramelessWindowsManager *pub); Q_NODISCARD static FramelessManagerPrivate *get(FramelessManager *pub);
Q_NODISCARD static const FramelessWindowsManagerPrivate *get(const FramelessWindowsManager *pub); Q_NODISCARD static const FramelessManagerPrivate *get(const FramelessManager *pub);
Q_NODISCARD static bool usePureQtImplementation();
Q_NODISCARD Global::SystemTheme systemTheme() const; Q_NODISCARD Global::SystemTheme systemTheme() const;
Q_NODISCARD QColor systemAccentColor() const; Q_NODISCARD QColor systemAccentColor() const;
@ -55,7 +54,7 @@ private:
void initialize(); void initialize();
private: private:
FramelessWindowsManager *q_ptr = nullptr; FramelessManager *q_ptr = nullptr;
Global::SystemTheme m_systemTheme = Global::SystemTheme::Unknown; Global::SystemTheme m_systemTheme = Global::SystemTheme::Unknown;
QColor m_accentColor = {}; QColor m_accentColor = {};
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS

View File

@ -50,6 +50,7 @@ class FRAMELESSHELPER_QUICK_API QuickStandardTitleBar : public QQuickRectangle
Q_PROPERTY(QuickStandardMinimizeButton* minimizeButton READ minimizeButton CONSTANT FINAL) Q_PROPERTY(QuickStandardMinimizeButton* minimizeButton READ minimizeButton CONSTANT FINAL)
Q_PROPERTY(QuickStandardMaximizeButton* maximizeButton READ maximizeButton CONSTANT FINAL) Q_PROPERTY(QuickStandardMaximizeButton* maximizeButton READ maximizeButton CONSTANT FINAL)
Q_PROPERTY(QuickStandardCloseButton* closeButton READ closeButton CONSTANT FINAL) Q_PROPERTY(QuickStandardCloseButton* closeButton READ closeButton CONSTANT FINAL)
Q_PROPERTY(bool extended READ isExtended WRITE setExtended NOTIFY extendedChanged FINAL)
public: public:
explicit QuickStandardTitleBar(QQuickItem *parent = nullptr); explicit QuickStandardTitleBar(QQuickItem *parent = nullptr);
@ -62,6 +63,9 @@ public:
Q_NODISCARD QuickStandardMaximizeButton *maximizeButton() const; Q_NODISCARD QuickStandardMaximizeButton *maximizeButton() const;
Q_NODISCARD QuickStandardCloseButton *closeButton() const; Q_NODISCARD QuickStandardCloseButton *closeButton() const;
Q_NODISCARD bool isExtended() const;
void setExtended(const bool value);
protected: protected:
void itemChange(const ItemChange change, const ItemChangeData &value) override; void itemChange(const ItemChange change, const ItemChangeData &value) override;
@ -75,6 +79,7 @@ private Q_SLOTS:
Q_SIGNALS: Q_SIGNALS:
void titleLabelAlignmentChanged(); void titleLabelAlignmentChanged();
void extendedChanged();
private: private:
void initialize(); void initialize();
@ -90,6 +95,7 @@ private:
QMetaObject::Connection m_windowStateChangeConnection = {}; QMetaObject::Connection m_windowStateChangeConnection = {};
QMetaObject::Connection m_windowActiveChangeConnection = {}; QMetaObject::Connection m_windowActiveChangeConnection = {};
QMetaObject::Connection m_windowTitleChangeConnection = {}; QMetaObject::Connection m_windowTitleChangeConnection = {};
bool m_extended = false;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -50,6 +50,9 @@ public:
Q_NODISCARD static StandardTitleBarPrivate *get(StandardTitleBar *pub); Q_NODISCARD static StandardTitleBarPrivate *get(StandardTitleBar *pub);
Q_NODISCARD static const StandardTitleBarPrivate *get(const StandardTitleBar *pub); Q_NODISCARD static const StandardTitleBarPrivate *get(const StandardTitleBar *pub);
Q_NODISCARD bool isExtended() const;
void setExtended(const bool value);
public Q_SLOTS: public Q_SLOTS:
void updateMaximizeButton(); void updateMaximizeButton();
void updateTitleBarStyleSheet(); void updateTitleBarStyleSheet();
@ -67,6 +70,7 @@ private:
QScopedPointer<StandardSystemButton> m_maximizeButton; QScopedPointer<StandardSystemButton> m_maximizeButton;
QScopedPointer<StandardSystemButton> m_closeButton; QScopedPointer<StandardSystemButton> m_closeButton;
QPointer<QWidget> m_window = nullptr; QPointer<QWidget> m_window = nullptr;
bool m_extended = false;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -40,6 +40,7 @@ class FRAMELESSHELPER_WIDGETS_API StandardTitleBar : public QWidget
Q_PROPERTY(StandardSystemButton* minimizeButton READ minimizeButton CONSTANT FINAL) Q_PROPERTY(StandardSystemButton* minimizeButton READ minimizeButton CONSTANT FINAL)
Q_PROPERTY(StandardSystemButton* maximizeButton READ maximizeButton CONSTANT FINAL) Q_PROPERTY(StandardSystemButton* maximizeButton READ maximizeButton CONSTANT FINAL)
Q_PROPERTY(StandardSystemButton* closeButton READ closeButton CONSTANT FINAL) Q_PROPERTY(StandardSystemButton* closeButton READ closeButton CONSTANT FINAL)
Q_PROPERTY(bool extended READ isExtended WRITE setExtended NOTIFY extendedChanged FINAL)
public: public:
explicit StandardTitleBar(QWidget *parent = nullptr); explicit StandardTitleBar(QWidget *parent = nullptr);
@ -49,9 +50,15 @@ public:
Q_NODISCARD StandardSystemButton *maximizeButton() const; Q_NODISCARD StandardSystemButton *maximizeButton() const;
Q_NODISCARD StandardSystemButton *closeButton() const; Q_NODISCARD StandardSystemButton *closeButton() const;
Q_NODISCARD bool isExtended() const;
void setExtended(const bool value);
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
Q_SIGNALS:
void extendedChanged();
private: private:
QScopedPointer<StandardTitleBarPrivate> d_ptr; QScopedPointer<StandardTitleBarPrivate> d_ptr;
}; };

View File

@ -35,13 +35,15 @@ set(INCLUDE_PREFIX ../../include/FramelessHelper/Core)
set(SOURCES set(SOURCES
${INCLUDE_PREFIX}/framelesshelpercore_global.h ${INCLUDE_PREFIX}/framelesshelpercore_global.h
${INCLUDE_PREFIX}/framelesshelper_qt.h ${INCLUDE_PREFIX}/framelesshelper_qt.h
${INCLUDE_PREFIX}/framelesswindowsmanager.h ${INCLUDE_PREFIX}/framelessmanager.h
${INCLUDE_PREFIX}/utils.h ${INCLUDE_PREFIX}/utils.h
${INCLUDE_PREFIX}/private/framelesswindowsmanager_p.h ${INCLUDE_PREFIX}/private/framelessmanager_p.h
${INCLUDE_PREFIX}/private/framelessconfig_p.h
framelesshelpercore.qrc framelesshelpercore.qrc
utils.cpp utils.cpp
framelesshelper_qt.cpp framelesshelper_qt.cpp
framelesswindowsmanager.cpp framelessmanager.cpp
framelessconfig.cpp
) )
if(WIN32) if(WIN32)

View File

@ -0,0 +1,102 @@
/*
* MIT License
*
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "framelessconfig_p.h"
#include <QtCore/qmutex.h>
#include <QtCore/qdir.h>
#include <QtCore/qsettings.h>
#include <QtCore/qcoreapplication.h>
FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global;
FRAMELESSHELPER_STRING_CONSTANT2(ConfigFileName, ".framelesshelper.ini")
static constexpr const struct
{
const char *env = nullptr;
const char *ini = nullptr;
} OptionsTable[] = {
{"FRAMELESSHELPER_USE_CROSS_PLATFORM_QT_IMPLEMENTATION", "Options/UseCrossPlatformQtImplementation"},
{"FRAMELESSHELPER_FORCE_HIDE_WINDOW_FRAME_BORDER", "Options/ForceHideWindowFrameBorder"},
{"FRAMELESSHELPER_FORCE_SHOW_WINDOW_FRAME_BORDER", "Options/ForceShowWindowFrameBorder"},
{"FRAMELESSHELPER_DISABLE_WINDOWS_SNAP_LAYOUTS", "Options/DisableWindowsSnapLayouts"},
{"FRAMELESSHELPER_WINDOW_USE_ROUND_CORNERS", "Options/WindowUseRoundCorners"}
};
static constexpr const auto OptionCount = std::size(OptionsTable);
struct ConfigData
{
QMutex mutex;
bool loaded = false;
bool options[OptionCount] = {};
};
Q_GLOBAL_STATIC(ConfigData, g_data)
Q_GLOBAL_STATIC(FramelessConfig, g_config)
FramelessConfig::FramelessConfig(QObject *parent) : QObject(parent)
{
reload();
}
FramelessConfig::~FramelessConfig() = default;
FramelessConfig *FramelessConfig::instance()
{
return g_config();
}
void FramelessConfig::reload(const bool force)
{
QMutexLocker locker(&g_data()->mutex);
if (g_data()->loaded && !force) {
return;
}
const QDir appDir(QCoreApplication::applicationDirPath());
const QSettings configFile(appDir.filePath(kConfigFileName), QSettings::IniFormat);
for (int i = 0; i != OptionCount; ++i) {
const bool on = (qEnvironmentVariableIsSet(OptionsTable[i].env) && (qEnvironmentVariableIntValue(OptionsTable[i].env) > 0))
|| (configFile.value(QUtf8String(OptionsTable[i].ini), false).toBool());
g_data()->options[i] = on;
}
g_data()->loaded = true;
}
void FramelessConfig::set(const Option option, const bool on)
{
QMutexLocker locker(&g_data()->mutex);
g_data()->options[static_cast<int>(option)] = on;
}
bool FramelessConfig::isSet(const Option option) const
{
QMutexLocker locker(&g_data()->mutex);
return g_data()->options[static_cast<int>(option)];
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -0,0 +1 @@
#include "../../include/FramelessHelper/Core/private/framelessconfig_p.h"

View File

@ -26,8 +26,8 @@
#include <QtCore/qmutex.h> #include <QtCore/qmutex.h>
#include <QtGui/qevent.h> #include <QtGui/qevent.h>
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include "framelesswindowsmanager.h" #include "framelessmanager.h"
#include "framelesswindowsmanager_p.h" #include "framelessmanager_p.h"
#include "utils.h" #include "utils.h"
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -90,8 +90,8 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
// First detect whether we got a theme change event or not, if so, // First detect whether we got a theme change event or not, if so,
// inform the user the system theme has changed. // inform the user the system theme has changed.
if (Utils::isThemeChangeEvent(event)) { if (Utils::isThemeChangeEvent(event)) {
FramelessWindowsManager *manager = FramelessWindowsManager::instance(); FramelessManager *manager = FramelessManager::instance();
FramelessWindowsManagerPrivate *managerPriv = FramelessWindowsManagerPrivate::get(manager); FramelessManagerPrivate *managerPriv = FramelessManagerPrivate::get(manager);
managerPriv->notifySystemThemeHasChangedOrNot(); managerPriv->notifySystemThemeHasChangedOrNot();
return false; return false;
} }

View File

@ -30,8 +30,9 @@
#include <QtCore/qcoreapplication.h> #include <QtCore/qcoreapplication.h>
#include <QtCore/quuid.h> #include <QtCore/quuid.h>
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include "framelesswindowsmanager.h" #include "framelessmanager.h"
#include "framelesswindowsmanager_p.h" #include "framelessmanager_p.h"
#include "framelessconfig_p.h"
#include "utils.h" #include "utils.h"
#include "framelesshelper_windows.h" #include "framelesshelper_windows.h"
@ -353,7 +354,10 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
if (!parentWindowId) { if (!parentWindowId) {
return false; return false;
} }
if (!Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1507)) { static const bool isWin10OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1507);
}();
if (!isWin10OrGreater) {
qWarning() << "The drag bar window is only supported on Windows 10 and onwards."; qWarning() << "The drag bar window is only supported on Windows 10 and onwards.";
return false; return false;
} }
@ -437,17 +441,32 @@ void FramelessHelperWin::addWindow(const SystemParameters &params)
Utils::fixupQtInternals(windowId); Utils::fixupQtInternals(windowId);
Utils::updateInternalWindowFrameMargins(params.getWindowHandle(), true); Utils::updateInternalWindowFrameMargins(params.getWindowHandle(), true);
Utils::updateWindowFrameMargins(windowId, false); Utils::updateWindowFrameMargins(windowId, false);
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1507)) { static const bool isWin10OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1507);
}();
if (isWin10OrGreater) {
const FramelessConfig * const config = FramelessConfig::instance();
if (!config->isSet(Option::DisableWindowsSnapLayouts)) {
if (!createDragBarWindow(windowId)) { if (!createDragBarWindow(windowId)) {
qWarning() << "Failed to create the drag bar window."; qWarning() << "Failed to create the drag bar window.";
} }
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1607)) { }
static const bool isWin10RS1OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1607);
}();
if (isWin10RS1OrGreater) {
const bool dark = Utils::shouldAppsUseDarkMode(); const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(windowId, dark); Utils::updateWindowFrameBorderColor(windowId, dark);
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1809)) { static const bool isWin10RS5OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1809);
}();
if (isWin10RS5OrGreater) {
//Utils::updateGlobalWin32ControlsTheme(windowId, dark); // Causes some QtWidgets paint incorrectly. //Utils::updateGlobalWin32ControlsTheme(windowId, dark); // Causes some QtWidgets paint incorrectly.
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2)) { static const bool isWin11OrGreater = []() -> bool {
Utils::forceSquareCornersForWindow(windowId, true); return Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
}();
if (isWin11OrGreater) {
Utils::forceSquareCornersForWindow(windowId, !config->isSet(Option::WindowUseRoundCorners));
} }
} }
} }
@ -623,10 +642,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// First, check if we have an auto-hide taskbar at all: // First, check if we have an auto-hide taskbar at all:
if (taskbarState & ABS_AUTOHIDE) { if (taskbarState & ABS_AUTOHIDE) {
bool top = false, bottom = false, left = false, right = false; bool top = false, bottom = false, left = false, right = false;
// Due to ABM_GETAUTOHIDEBAREX only exists from Win8.1, // Due to ABM_GETAUTOHIDEBAREX was introduced in Windows 8.1,
// we have to use another way to judge this if we are // we have to use another way to judge this if we are running
// running on Windows 7 or Windows 8. // on Windows 7 or Windows 8.
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_8_1)) { static const bool isWin8Point1OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_8_1);
}();
if (isWin8Point1OrGreater) {
MONITORINFO monitorInfo; MONITORINFO monitorInfo;
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo)); SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo); monitorInfo.cbSize = sizeof(monitorInfo);
@ -1008,7 +1030,10 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
break; break;
} }
} }
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_8) && data.dragBarWindowId) { static const bool isWin10OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1507);
}();
if (isWin10OrGreater && data.dragBarWindowId) {
switch (uMsg) { switch (uMsg) {
case WM_SIZE: case WM_SIZE:
case WM_DISPLAYCHANGE: { case WM_DISPLAYCHANGE: {
@ -1022,22 +1047,28 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
} }
bool systemThemeChanged = ((uMsg == WM_THEMECHANGED) || (uMsg == WM_SYSCOLORCHANGE) bool systemThemeChanged = ((uMsg == WM_THEMECHANGED) || (uMsg == WM_SYSCOLORCHANGE)
|| (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED)); || (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED));
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1607)) { static const bool isWin10RS1OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1607);
}();
if (isWin10RS1OrGreater) {
if (uMsg == WM_SETTINGCHANGE) { if (uMsg == WM_SETTINGCHANGE) {
if ((wParam == 0) && (QString::fromWCharArray(reinterpret_cast<LPCWSTR>(lParam)) if ((wParam == 0) && (QString::fromWCharArray(reinterpret_cast<LPCWSTR>(lParam))
.compare(qThemeSettingChangeEventName, Qt::CaseInsensitive) == 0)) { .compare(qThemeSettingChangeEventName, Qt::CaseInsensitive) == 0)) {
systemThemeChanged = true; systemThemeChanged = true;
const bool dark = Utils::shouldAppsUseDarkMode(); const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(windowId, dark); Utils::updateWindowFrameBorderColor(windowId, dark);
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1809)) { static const bool isWin10RS5OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1809);
}();
if (isWin10RS5OrGreater) {
//Utils::updateGlobalWin32ControlsTheme(windowId, dark); // Causes some QtWidgets paint incorrectly. //Utils::updateGlobalWin32ControlsTheme(windowId, dark); // Causes some QtWidgets paint incorrectly.
} }
} }
} }
} }
if (systemThemeChanged) { if (systemThemeChanged) {
FramelessWindowsManager *manager = FramelessWindowsManager::instance(); FramelessManager *manager = FramelessManager::instance();
FramelessWindowsManagerPrivate *managerPriv = FramelessWindowsManagerPrivate::get(manager); FramelessManagerPrivate *managerPriv = FramelessManagerPrivate::get(manager);
managerPriv->notifySystemThemeHasChangedOrNot(); managerPriv->notifySystemThemeHasChangedOrNot();
} }
return false; return false;

View File

@ -22,15 +22,14 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "framelesswindowsmanager.h" #include "framelessmanager.h"
#include "framelesswindowsmanager_p.h" #include "framelessmanager_p.h"
#include <QtCore/qvariant.h>
#include <QtCore/qmutex.h> #include <QtCore/qmutex.h>
#include <QtCore/qsettings.h>
#include <QtGui/qguiapplication.h> #include <QtGui/qguiapplication.h>
#include <QtGui/qscreen.h> #include <QtGui/qscreen.h>
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include "framelesshelper_qt.h" #include "framelesshelper_qt.h"
#include "framelessconfig_p.h"
#include "utils.h" #include "utils.h"
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
# include "framelesshelper_win.h" # include "framelesshelper_win.h"
@ -40,15 +39,15 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
struct FramelessWindowsManagerHelper struct FramelessManagerHelper
{ {
QMutex mutex; QMutex mutex;
QList<WId> windowIds = {}; QList<WId> windowIds = {};
}; };
Q_GLOBAL_STATIC(FramelessWindowsManagerHelper, g_helper) Q_GLOBAL_STATIC(FramelessManagerHelper, g_helper)
Q_GLOBAL_STATIC(FramelessWindowsManager, g_manager) Q_GLOBAL_STATIC(FramelessManager, g_manager)
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
static constexpr const char QT_QPA_ENV_VAR[] = "QT_QPA_PLATFORM"; static constexpr const char QT_QPA_ENV_VAR[] = "QT_QPA_PLATFORM";
@ -60,7 +59,7 @@ static constexpr const char MAC_LAYER_ENV_VAR[] = "QT_MAC_WANTS_LAYER";
FRAMELESSHELPER_BYTEARRAY_CONSTANT2(ValueOne, "1") FRAMELESSHELPER_BYTEARRAY_CONSTANT2(ValueOne, "1")
#endif #endif
FramelessWindowsManagerPrivate::FramelessWindowsManagerPrivate(FramelessWindowsManager *q) : QObject(q) FramelessManagerPrivate::FramelessManagerPrivate(FramelessManager *q) : QObject(q)
{ {
Q_ASSERT(q); Q_ASSERT(q);
if (!q) { if (!q) {
@ -70,9 +69,9 @@ FramelessWindowsManagerPrivate::FramelessWindowsManagerPrivate(FramelessWindowsM
initialize(); initialize();
} }
FramelessWindowsManagerPrivate::~FramelessWindowsManagerPrivate() = default; FramelessManagerPrivate::~FramelessManagerPrivate() = default;
FramelessWindowsManagerPrivate *FramelessWindowsManagerPrivate::get(FramelessWindowsManager *pub) FramelessManagerPrivate *FramelessManagerPrivate::get(FramelessManager *pub)
{ {
Q_ASSERT(pub); Q_ASSERT(pub);
if (!pub) { if (!pub) {
@ -81,7 +80,7 @@ FramelessWindowsManagerPrivate *FramelessWindowsManagerPrivate::get(FramelessWin
return pub->d_func(); return pub->d_func();
} }
const FramelessWindowsManagerPrivate *FramelessWindowsManagerPrivate::get(const FramelessWindowsManager *pub) const FramelessManagerPrivate *FramelessManagerPrivate::get(const FramelessManager *pub)
{ {
Q_ASSERT(pub); Q_ASSERT(pub);
if (!pub) { if (!pub) {
@ -90,34 +89,17 @@ const FramelessWindowsManagerPrivate *FramelessWindowsManagerPrivate::get(const
return pub->d_func(); return pub->d_func();
} }
bool FramelessWindowsManagerPrivate::usePureQtImplementation() SystemTheme FramelessManagerPrivate::systemTheme() const
{
#ifdef Q_OS_WINDOWS
static const bool result = []() -> bool {
if (qEnvironmentVariableIntValue(kUsePureQtImplFlag) != 0) {
return true;
}
const QString iniFilePath = QCoreApplication::applicationDirPath() + QChar(u'/') + kConfigFileName;
QSettings settings(iniFilePath, QSettings::IniFormat);
return settings.value(kUsePureQtImplKeyPath, false).toBool();
}();
#else
static constexpr const bool result = true;
#endif
return result;
}
SystemTheme FramelessWindowsManagerPrivate::systemTheme() const
{ {
return m_systemTheme; return m_systemTheme;
} }
QColor FramelessWindowsManagerPrivate::systemAccentColor() const QColor FramelessManagerPrivate::systemAccentColor() const
{ {
return m_accentColor; return m_accentColor;
} }
void FramelessWindowsManagerPrivate::addWindow(const SystemParameters &params) void FramelessManagerPrivate::addWindow(const SystemParameters &params)
{ {
Q_ASSERT(params.isValid()); Q_ASSERT(params.isValid());
if (!params.isValid()) { if (!params.isValid()) {
@ -131,7 +113,13 @@ void FramelessWindowsManagerPrivate::addWindow(const SystemParameters &params)
} }
g_helper()->windowIds.append(windowId); g_helper()->windowIds.append(windowId);
g_helper()->mutex.unlock(); g_helper()->mutex.unlock();
static const bool pureQt = usePureQtImplementation(); static const bool pureQt = []() -> bool {
#ifdef Q_OS_WINDOWS
return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
#else
return true;
#endif
}();
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
if (!pureQt) { if (!pureQt) {
// Work-around Win32 multi-monitor artifacts. // Work-around Win32 multi-monitor artifacts.
@ -162,9 +150,9 @@ void FramelessWindowsManagerPrivate::addWindow(const SystemParameters &params)
#endif #endif
} }
void FramelessWindowsManagerPrivate::notifySystemThemeHasChangedOrNot() void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot()
{ {
Q_Q(FramelessWindowsManager); Q_Q(FramelessManager);
const SystemTheme currentSystemTheme = Utils::getSystemTheme(); const SystemTheme currentSystemTheme = Utils::getSystemTheme();
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
const DwmColorizationArea currentColorizationArea = Utils::getDwmColorizationArea(); const DwmColorizationArea currentColorizationArea = Utils::getDwmColorizationArea();
@ -196,7 +184,7 @@ void FramelessWindowsManagerPrivate::notifySystemThemeHasChangedOrNot()
} }
} }
void FramelessWindowsManagerPrivate::initialize() void FramelessManagerPrivate::initialize()
{ {
m_systemTheme = Utils::getSystemTheme(); m_systemTheme = Utils::getSystemTheme();
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -211,38 +199,32 @@ void FramelessWindowsManagerPrivate::initialize()
#endif #endif
} }
FramelessWindowsManager::FramelessWindowsManager(QObject *parent) : QObject(parent), d_ptr(new FramelessWindowsManagerPrivate(this)) FramelessManager::FramelessManager(QObject *parent) : QObject(parent), d_ptr(new FramelessManagerPrivate(this))
{ {
} }
FramelessWindowsManager::~FramelessWindowsManager() = default; FramelessManager::~FramelessManager() = default;
FramelessWindowsManager *FramelessWindowsManager::instance() FramelessManager *FramelessManager::instance()
{ {
return g_manager(); return g_manager();
} }
bool FramelessWindowsManager::usePureQtImplementation() const SystemTheme FramelessManager::systemTheme() const
{ {
Q_D(const FramelessWindowsManager); Q_D(const FramelessManager);
return d->usePureQtImplementation();
}
SystemTheme FramelessWindowsManager::systemTheme() const
{
Q_D(const FramelessWindowsManager);
return d->systemTheme(); return d->systemTheme();
} }
QColor FramelessWindowsManager::systemAccentColor() const QColor FramelessManager::systemAccentColor() const
{ {
Q_D(const FramelessWindowsManager); Q_D(const FramelessManager);
return d->systemAccentColor(); return d->systemAccentColor();
} }
void FramelessWindowsManager::addWindow(const SystemParameters &params) void FramelessManager::addWindow(const SystemParameters &params)
{ {
Q_D(FramelessWindowsManager); Q_D(FramelessManager);
d->addWindow(params); d->addWindow(params);
} }
@ -294,6 +276,7 @@ void FramelessHelper::Core::initialize()
// flicker and jitter during window resizing. // flicker and jitter during window resizing.
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round);
#endif #endif
qRegisterMetaType<Option>();
qRegisterMetaType<SystemTheme>(); qRegisterMetaType<SystemTheme>();
qRegisterMetaType<SystemButtonType>(); qRegisterMetaType<SystemButtonType>();
qRegisterMetaType<ResourceType>(); qRegisterMetaType<ResourceType>();

View File

@ -0,0 +1 @@
#include "../../include/FramelessHelper/Core/framelessmanager.h"

View File

@ -0,0 +1 @@
#include "../../include/FramelessHelper/Core/private/framelessmanager_p.h"

View File

@ -1 +0,0 @@
#include "../../include/FramelessHelper/Core/framelesswindowsmanager.h"

View File

@ -1 +0,0 @@
#include "../../include/FramelessHelper/Core/private/framelesswindowsmanager_p.h"

View File

@ -35,8 +35,9 @@
#else #else
# include <QtGui/qpa/qplatformwindow_p.h> # include <QtGui/qpa/qplatformwindow_p.h>
#endif #endif
#include "framelesswindowsmanager.h" #include "framelessmanager.h"
#include "framelesshelper_windows.h" #include "framelesshelper_windows.h"
#include "framelessconfig_p.h"
#include <atlbase.h> #include <atlbase.h>
#include <d2d1.h> #include <d2d1.h>
@ -258,7 +259,10 @@ FRAMELESSHELPER_STRING_CONSTANT2(HKEY_CURRENT_USER, "HKEY_CURRENT_USER")
return titleBarHeight; return titleBarHeight;
} }
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2)) { static const bool isWin11OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
}();
if (isWin11OrGreater) {
if (maxOrFull) { if (maxOrFull) {
return (titleBarHeight + frameSizeY); return (titleBarHeight + frameSizeY);
} }
@ -343,7 +347,10 @@ bool Utils::isWindowsVersionOrGreater(const WindowsVersion version)
bool Utils::isDwmCompositionEnabled() bool Utils::isDwmCompositionEnabled()
{ {
// DWM composition is always enabled and can't be disabled since Windows 8. // DWM composition is always enabled and can't be disabled since Windows 8.
if (isWindowsVersionOrGreater(WindowsVersion::_8)) { static const bool isWin8OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_8);
}();
if (isWin8OrGreater) {
return true; return true;
} }
const auto resultFromRegistry = []() -> bool { const auto resultFromRegistry = []() -> bool {
@ -493,7 +500,10 @@ QColor Utils::getDwmColorizationColor()
DwmColorizationArea Utils::getDwmColorizationArea() DwmColorizationArea Utils::getDwmColorizationArea()
{ {
// It's a Win10 only feature. (TO BE VERIFIED) // It's a Win10 only feature. (TO BE VERIFIED)
if (!isWindowsVersionOrGreater(WindowsVersion::_10_1507)) { static const bool isWin10OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1507);
}();
if (!isWin10OrGreater) {
return DwmColorizationArea::None_; return DwmColorizationArea::None_;
} }
const QSettings themeRegistry(kHKEY_CURRENT_USER + u'\\' + qPersonalizeRegistryKey, QSettings::NativeFormat); const QSettings themeRegistry(kHKEY_CURRENT_USER + u'\\' + qPersonalizeRegistryKey, QSettings::NativeFormat);
@ -852,7 +862,10 @@ quint32 Utils::getFrameBorderThickness(const WId windowId, const bool scaled)
return 0; return 0;
} }
// There's no window frame border before Windows 10. // There's no window frame border before Windows 10.
if (!isWindowsVersionOrGreater(WindowsVersion::_10_1507)) { static const bool isWin10OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1507);
}();
if (!isWin10OrGreater) {
return 0; return 0;
} }
static const auto pDwmGetWindowAttribute = static const auto pDwmGetWindowAttribute =
@ -878,7 +891,10 @@ QColor Utils::getFrameBorderColor(const bool active)
{ {
// There's no window frame border before Windows 10. // There's no window frame border before Windows 10.
// So we just return a default value which is based on most window managers. // So we just return a default value which is based on most window managers.
if (!isWindowsVersionOrGreater(WindowsVersion::_10_1507)) { static const bool isWin10OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1507);
}();
if (!isWin10OrGreater) {
return (active ? kDefaultBlackColor : kDefaultDarkGrayColor); return (active ? kDefaultBlackColor : kDefaultDarkGrayColor);
} }
const bool dark = shouldAppsUseDarkMode(); const bool dark = shouldAppsUseDarkMode();
@ -900,7 +916,10 @@ void Utils::updateWindowFrameBorderColor(const WId windowId, const bool dark)
return; return;
} }
// There's no global dark theme before Win10 1607. // There's no global dark theme before Win10 1607.
if (!isWindowsVersionOrGreater(WindowsVersion::_10_1607)) { static const bool isWin10RS1OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1607);
}();
if (!isWin10RS1OrGreater) {
return; return;
} }
static const auto pDwmSetWindowAttribute = static const auto pDwmSetWindowAttribute =
@ -910,7 +929,10 @@ void Utils::updateWindowFrameBorderColor(const WId windowId, const bool dark)
return; return;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = reinterpret_cast<HWND>(windowId);
const DWORD mode = (isWindowsVersionOrGreater(WindowsVersion::_10_2004) ? _DWMWA_USE_IMMERSIVE_DARK_MODE : _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1); static const bool isWin1020H1OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_2004);
}();
const DWORD mode = (isWin1020H1OrGreater ? _DWMWA_USE_IMMERSIVE_DARK_MODE : _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1);
const BOOL value = (dark ? TRUE : FALSE); const BOOL value = (dark ? TRUE : FALSE);
const HRESULT hr = pDwmSetWindowAttribute(hwnd, mode, &value, sizeof(value)); const HRESULT hr = pDwmSetWindowAttribute(hwnd, mode, &value, sizeof(value));
if (FAILED(hr)) { if (FAILED(hr)) {
@ -1012,36 +1034,28 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
bool Utils::isWindowFrameBorderVisible() bool Utils::isWindowFrameBorderVisible()
{ {
static const bool result = []() -> bool { static const bool result = []() -> bool {
if (FramelessWindowsManager::instance()->usePureQtImplementation()) { const FramelessConfig * const config = FramelessConfig::instance();
return false; if (config->isSet(Option::ForceShowWindowFrameBorder)) {
}
// If we preserve the window frame border on systems prior to Windows 10,
// the window will look rather ugly and I guess no one would like to see
// such weired windows. But for the ones who really want to see what the
// window look like, I still provide a way to enter such scenarios.
if (qEnvironmentVariableIntValue(kForceShowFrameBorderFlag) != 0) {
return true; return true;
} }
if (qEnvironmentVariableIntValue(kForceHideFrameBorderFlag) != 0) { if (config->isSet(Option::ForceHideWindowFrameBorder)) {
return false;
}
const QString iniFilePath = QCoreApplication::applicationDirPath() + QChar(u'/') + kConfigFileName;
QSettings settings(iniFilePath, QSettings::IniFormat);
if (settings.value(kForceShowFrameBorderKeyPath, false).toBool()) {
return true;
}
if (settings.value(kForceHideFrameBorderKeyPath, false).toBool()) {
return false; return false;
} }
static const bool isWin10OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1507); return isWindowsVersionOrGreater(WindowsVersion::_10_1507);
}(); }();
return isWin10OrGreater;
}();
return result; return result;
} }
bool Utils::isTitleBarColorized() bool Utils::isTitleBarColorized()
{ {
// CHECK: is it supported on win7? // CHECK: is it supported on win7?
if (!isWindowsVersionOrGreater(WindowsVersion::_10_1507)) { static const bool isWin10OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1507);
}();
if (!isWin10OrGreater) {
return false; return false;
} }
const DwmColorizationArea area = getDwmColorizationArea(); const DwmColorizationArea area = getDwmColorizationArea();
@ -1254,7 +1268,10 @@ SystemTheme Utils::getSystemTheme()
if (isHighContrastModeEnabled()) { if (isHighContrastModeEnabled()) {
return SystemTheme::HighContrast; return SystemTheme::HighContrast;
} }
if (isWindowsVersionOrGreater(WindowsVersion::_10_1607) && shouldAppsUseDarkMode()) { static const bool isWin10RS1OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1607);
}();
if (isWin10RS1OrGreater && shouldAppsUseDarkMode()) {
return SystemTheme::Dark; return SystemTheme::Dark;
} }
return SystemTheme::Light; return SystemTheme::Light;
@ -1267,7 +1284,10 @@ void Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
return; return;
} }
// There's no global dark theme for common Win32 controls before Win10 1809. // There's no global dark theme for common Win32 controls before Win10 1809.
if (!isWindowsVersionOrGreater(WindowsVersion::_10_1809)) { static const bool isWin10RS5OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1809);
}();
if (!isWin10RS5OrGreater) {
return; return;
} }
static const auto pSetWindowTheme = static const auto pSetWindowTheme =
@ -1286,7 +1306,10 @@ void Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
bool Utils::shouldAppsUseDarkMode_windows() bool Utils::shouldAppsUseDarkMode_windows()
{ {
// The global dark mode was first introduced in Windows 10 1607. // The global dark mode was first introduced in Windows 10 1607.
if (!isWindowsVersionOrGreater(WindowsVersion::_10_1607)) { static const bool isWin10RS1OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1607);
}();
if (!isWin10RS1OrGreater) {
return false; return false;
} }
const auto resultFromRegistry = []() -> bool { const auto resultFromRegistry = []() -> bool {
@ -1298,7 +1321,10 @@ bool Utils::shouldAppsUseDarkMode_windows()
static const auto pShouldAppsUseDarkMode = static const auto pShouldAppsUseDarkMode =
reinterpret_cast<BOOL(WINAPI *)(VOID)>( reinterpret_cast<BOOL(WINAPI *)(VOID)>(
QSystemLibrary::resolve(kuxtheme, MAKEINTRESOURCEA(132))); QSystemLibrary::resolve(kuxtheme, MAKEINTRESOURCEA(132)));
if (pShouldAppsUseDarkMode && !isWindowsVersionOrGreater(WindowsVersion::_10_1903)) { static const bool isWin1019H1OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_10_1903);
}();
if (pShouldAppsUseDarkMode && !isWin1019H1OrGreater) {
return (pShouldAppsUseDarkMode() != FALSE); return (pShouldAppsUseDarkMode() != FALSE);
} }
// Starting from Windows 10 1903, "ShouldAppsUseDarkMode()" always return "TRUE" // Starting from Windows 10 1903, "ShouldAppsUseDarkMode()" always return "TRUE"
@ -1319,7 +1345,10 @@ void Utils::forceSquareCornersForWindow(const WId windowId, const bool force)
return; return;
} }
// We cannot change the window corner style until Windows 11. // We cannot change the window corner style until Windows 11.
if (!isWindowsVersionOrGreater(WindowsVersion::_11_21H2)) { static const bool isWin11OrGreater = []() -> bool {
return isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
}();
if (!isWin11OrGreater) {
return; return;
} }
static const auto pDwmSetWindowAttribute = static const auto pDwmSetWindowAttribute =

View File

@ -32,7 +32,7 @@
#endif #endif
#include <QtQuick/qquickwindow.h> #include <QtQuick/qquickwindow.h>
#include <QtQuickTemplates2/private/qquickabstractbutton_p.h> #include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -208,7 +208,7 @@ void FramelessQuickHelperPrivate::attachToWindow()
data->attached = true; data->attached = true;
g_quickHelper()->mutex.unlock(); g_quickHelper()->mutex.unlock();
FramelessWindowsManager::instance()->addWindow(params); FramelessManager::instance()->addWindow(params);
} }
void FramelessQuickHelperPrivate::setSystemButton(QQuickItem *item, const QuickGlobal::SystemButtonType buttonType) void FramelessQuickHelperPrivate::setSystemButton(QQuickItem *item, const QuickGlobal::SystemButtonType buttonType)

View File

@ -23,7 +23,7 @@
*/ */
#include "framelessquickutils.h" #include "framelessquickutils.h"
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -32,7 +32,7 @@ using namespace Global;
FramelessQuickUtils::FramelessQuickUtils(QObject *parent) : QObject(parent) FramelessQuickUtils::FramelessQuickUtils(QObject *parent) : QObject(parent)
{ {
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, [this](){ connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, [this](){
Q_EMIT systemThemeChanged(); Q_EMIT systemThemeChanged();
Q_EMIT systemAccentColorChanged(); Q_EMIT systemAccentColorChanged();
Q_EMIT titleBarColorizedChanged(); Q_EMIT titleBarColorizedChanged();
@ -49,7 +49,10 @@ qreal FramelessQuickUtils::titleBarHeight() const
bool FramelessQuickUtils::frameBorderVisible() const bool FramelessQuickUtils::frameBorderVisible() const
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
return (Utils::isWindowFrameBorderVisible() && !Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2)); static const bool isWin11OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
}();
return (Utils::isWindowFrameBorderVisible() && !isWin11OrGreater);
#else #else
return false; return false;
#endif #endif

View File

@ -29,7 +29,7 @@
#include <QtQuick/private/qquickitem_p.h> #include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquickanchors_p.h> #include <QtQuick/private/qquickanchors_p.h>
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -180,13 +180,16 @@ void FramelessQuickWindowPrivate::initialize()
Q_EMIT q->fullScreenChanged(); Q_EMIT q->fullScreenChanged();
}); });
connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor); connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor); connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
} }
bool FramelessQuickWindowPrivate::shouldDrawFrameBorder() const bool FramelessQuickWindowPrivate::shouldDrawFrameBorder() const
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
return (Utils::isWindowFrameBorderVisible() && !Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2)); static const bool isWin11OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
}();
return (Utils::isWindowFrameBorderVisible() && !isWin11OrGreater);
#else #else
return false; return false;
#endif #endif

View File

@ -24,7 +24,7 @@
#include "quickstandardclosebutton_p.h" #include "quickstandardclosebutton_p.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
#include <QtQuick/private/qquickimage_p.h> #include <QtQuick/private/qquickimage_p.h>
#include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickrectangle_p.h>
@ -84,7 +84,7 @@ void QuickStandardCloseButton::initialize()
imageAnchors->setCenterIn(m_contentItem.data()); imageAnchors->setCenterIn(m_contentItem.data());
connect(this, &QuickStandardCloseButton::hoveredChanged, this, &QuickStandardCloseButton::updateForeground); connect(this, &QuickStandardCloseButton::hoveredChanged, this, &QuickStandardCloseButton::updateForeground);
connect(this, &QuickStandardCloseButton::pressedChanged, this, &QuickStandardCloseButton::updateForeground); connect(this, &QuickStandardCloseButton::pressedChanged, this, &QuickStandardCloseButton::updateForeground);
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &QuickStandardCloseButton::updateForeground); connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &QuickStandardCloseButton::updateForeground);
m_backgroundItem.reset(new QQuickRectangle(this)); m_backgroundItem.reset(new QQuickRectangle(this));
QQuickPen * const border = m_backgroundItem->border(); QQuickPen * const border = m_backgroundItem->border();

View File

@ -24,7 +24,7 @@
#include "quickstandardmaximizebutton_p.h" #include "quickstandardmaximizebutton_p.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
#include <QtQuick/private/qquickimage_p.h> #include <QtQuick/private/qquickimage_p.h>
#include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickrectangle_p.h>
@ -99,7 +99,7 @@ void QuickStandardMaximizeButton::initialize()
m_image.reset(new QQuickImage(m_contentItem.data())); m_image.reset(new QQuickImage(m_contentItem.data()));
const auto imageAnchors = new QQuickAnchors(m_image.data(), m_image.data()); const auto imageAnchors = new QQuickAnchors(m_image.data(), m_image.data());
imageAnchors->setCenterIn(m_contentItem.data()); imageAnchors->setCenterIn(m_contentItem.data());
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &QuickStandardMaximizeButton::updateForeground); connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &QuickStandardMaximizeButton::updateForeground);
connect(this, &QuickStandardMaximizeButton::maximizedChanged, this, &QuickStandardMaximizeButton::updateForeground); connect(this, &QuickStandardMaximizeButton::maximizedChanged, this, &QuickStandardMaximizeButton::updateForeground);
m_backgroundItem.reset(new QQuickRectangle(this)); m_backgroundItem.reset(new QQuickRectangle(this));

View File

@ -24,7 +24,7 @@
#include "quickstandardminimizebutton_p.h" #include "quickstandardminimizebutton_p.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
#include <QtQuick/private/qquickimage_p.h> #include <QtQuick/private/qquickimage_p.h>
#include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickrectangle_p.h>
@ -82,7 +82,7 @@ void QuickStandardMinimizeButton::initialize()
m_image.reset(new QQuickImage(m_contentItem.data())); m_image.reset(new QQuickImage(m_contentItem.data()));
const auto imageAnchors = new QQuickAnchors(m_image.data(), m_image.data()); const auto imageAnchors = new QQuickAnchors(m_image.data(), m_image.data());
imageAnchors->setCenterIn(m_contentItem.data()); imageAnchors->setCenterIn(m_contentItem.data());
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &QuickStandardMinimizeButton::updateForeground); connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &QuickStandardMinimizeButton::updateForeground);
m_backgroundItem.reset(new QQuickRectangle(this)); m_backgroundItem.reset(new QQuickRectangle(this));
QQuickPen * const border = m_backgroundItem->border(); QQuickPen * const border = m_backgroundItem->border();

View File

@ -27,7 +27,7 @@
#include "quickstandardminimizebutton_p.h" #include "quickstandardminimizebutton_p.h"
#include "quickstandardmaximizebutton_p.h" #include "quickstandardmaximizebutton_p.h"
#include "quickstandardclosebutton_p.h" #include "quickstandardclosebutton_p.h"
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
#include <QtQuick/private/qquickitem_p.h> #include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickanchors_p.h> #include <QtQuick/private/qquickanchors_p.h>
@ -103,6 +103,21 @@ QuickStandardCloseButton *QuickStandardTitleBar::closeButton() const
return m_closeBtn.data(); return m_closeBtn.data();
} }
bool QuickStandardTitleBar::isExtended() const
{
return m_extended;
}
void QuickStandardTitleBar::setExtended(const bool value)
{
if (m_extended == value) {
return;
}
m_extended = value;
setHeight(m_extended ? kDefaultExtendedTitleBarHeight : kDefaultTitleBarHeight);
Q_EMIT extendedChanged();
}
void QuickStandardTitleBar::updateMaximizeButton() void QuickStandardTitleBar::updateMaximizeButton()
{ {
const QQuickWindow * const w = window(); const QQuickWindow * const w = window();
@ -217,7 +232,7 @@ void QuickStandardTitleBar::initialize()
m_closeBtn.reset(new QuickStandardCloseButton(m_row.data())); m_closeBtn.reset(new QuickStandardCloseButton(m_row.data()));
connect(m_closeBtn.data(), &QuickStandardCloseButton::clicked, this, &QuickStandardTitleBar::clickCloseButton); connect(m_closeBtn.data(), &QuickStandardCloseButton::clicked, this, &QuickStandardTitleBar::clickCloseButton);
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, &QuickStandardTitleBar::updateTitleBarColor); connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &QuickStandardTitleBar::updateTitleBarColor);
setTitleLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter); setTitleLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);

View File

@ -27,8 +27,9 @@
#include <QtCore/qmutex.h> #include <QtCore/qmutex.h>
#include <QtCore/qhash.h> #include <QtCore/qhash.h>
#include <QtCore/qpointer.h> #include <QtCore/qpointer.h>
#include <QtGui/qwindow.h>
#include <QtWidgets/qwidget.h> #include <QtWidgets/qwidget.h>
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -236,7 +237,7 @@ void FramelessWidgetsHelperPrivate::attachToWindow()
data->attached = true; data->attached = true;
g_widgetsHelper()->mutex.unlock(); g_widgetsHelper()->mutex.unlock();
FramelessWindowsManager::instance()->addWindow(params); FramelessManager::instance()->addWindow(params);
} }
QWidget *FramelessWidgetsHelperPrivate::getWindow() const QWidget *FramelessWidgetsHelperPrivate::getWindow() const

View File

@ -26,7 +26,7 @@
#include "standardsystembutton_p.h" #include "standardsystembutton_p.h"
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
#include <QtGui/qpainter.h> #include <QtGui/qpainter.h>
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -307,7 +307,7 @@ void StandardSystemButtonPrivate::initialize()
q->setIconSize(kDefaultSystemButtonIconSize); q->setIconSize(kDefaultSystemButtonIconSize);
connect(q, &StandardSystemButton::pressed, this, [this](){ setPressed(true); }); connect(q, &StandardSystemButton::pressed, this, [this](){ setPressed(true); });
connect(q, &StandardSystemButton::released, this, [this](){ setPressed(false); }); connect(q, &StandardSystemButton::released, this, [this](){ setPressed(false); });
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged,
this, [this](){ refreshButtonTheme(false); }); this, [this](){ refreshButtonTheme(false); });
} }

View File

@ -31,7 +31,7 @@
#include <QtWidgets/qboxlayout.h> #include <QtWidgets/qboxlayout.h>
#include <QtWidgets/qstyle.h> #include <QtWidgets/qstyle.h>
#include <QtWidgets/qstyleoption.h> #include <QtWidgets/qstyleoption.h>
#include <framelesswindowsmanager.h> #include <framelessmanager.h>
#include <utils.h> #include <utils.h>
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -71,6 +71,22 @@ const StandardTitleBarPrivate *StandardTitleBarPrivate::get(const StandardTitleB
return pub->d_func(); return pub->d_func();
} }
bool StandardTitleBarPrivate::isExtended() const
{
return m_extended;
}
void StandardTitleBarPrivate::setExtended(const bool value)
{
if (m_extended == value) {
return;
}
m_extended = value;
Q_Q(StandardTitleBar);
q->setFixedHeight(m_extended ? kDefaultExtendedTitleBarHeight : kDefaultTitleBarHeight);
Q_EMIT q->extendedChanged();
}
void StandardTitleBarPrivate::updateMaximizeButton() void StandardTitleBarPrivate::updateMaximizeButton()
{ {
const bool zoomed = (m_window->isMaximized() || m_window->isFullScreen()); const bool zoomed = (m_window->isMaximized() || m_window->isFullScreen());
@ -172,6 +188,9 @@ void StandardTitleBarPrivate::initialize()
m_closeButton.reset(new StandardSystemButton(SystemButtonType::Close, q)); m_closeButton.reset(new StandardSystemButton(SystemButtonType::Close, q));
m_closeButton->setToolTip(tr("Close")); m_closeButton->setToolTip(tr("Close"));
connect(m_closeButton.data(), &StandardSystemButton::clicked, m_window, &QWidget::close); connect(m_closeButton.data(), &StandardSystemButton::clicked, m_window, &QWidget::close);
// According to the title bar design guidance, the system buttons should always be
// placed on the top-right corner of the window, so we need the following additional
// layouts to ensure this.
const auto systemButtonsInnerLayout = new QHBoxLayout; const auto systemButtonsInnerLayout = new QHBoxLayout;
systemButtonsInnerLayout->setSpacing(0); systemButtonsInnerLayout->setSpacing(0);
systemButtonsInnerLayout->setContentsMargins(0, 0, 0, 0); systemButtonsInnerLayout->setContentsMargins(0, 0, 0, 0);
@ -192,7 +211,7 @@ void StandardTitleBarPrivate::initialize()
titleBarLayout->addLayout(systemButtonsOuterLayout); titleBarLayout->addLayout(systemButtonsOuterLayout);
q->setLayout(titleBarLayout); q->setLayout(titleBarLayout);
updateTitleBarStyleSheet(); updateTitleBarStyleSheet();
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged,
this, &StandardTitleBarPrivate::updateTitleBarStyleSheet); this, &StandardTitleBarPrivate::updateTitleBarStyleSheet);
m_window->installEventFilter(this); m_window->installEventFilter(this);
} }
@ -222,6 +241,18 @@ StandardSystemButton *StandardTitleBar::closeButton() const
return d->m_closeButton.data(); return d->m_closeButton.data();
} }
bool StandardTitleBar::isExtended() const
{
Q_D(const StandardTitleBar);
return d->isExtended();
}
void StandardTitleBar::setExtended(const bool value)
{
Q_D(StandardTitleBar);
d->setExtended(value);
}
void StandardTitleBar::paintEvent(QPaintEvent *event) void StandardTitleBar::paintEvent(QPaintEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);

View File

@ -127,7 +127,10 @@ void WidgetsSharedHelper::paintEventHandler(QPaintEvent *event)
bool WidgetsSharedHelper::shouldDrawFrameBorder() const bool WidgetsSharedHelper::shouldDrawFrameBorder() const
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
return (Utils::isWindowFrameBorderVisible() && !Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2) static const bool isWin11OrGreater = []() -> bool {
return Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
}();
return (Utils::isWindowFrameBorderVisible() && !isWin11OrGreater
&& (Utils::windowStatesToWindowState(m_targetWidget->windowState()) == Qt::WindowNoState)); && (Utils::windowStatesToWindowState(m_targetWidget->windowState()) == Qt::WindowNoState));
#else #else
return false; return false;