diff --git a/include/FramelessHelper/Core/framelesshelpercore_global.h b/include/FramelessHelper/Core/framelesshelpercore_global.h index 5cf471d..71e50dc 100644 --- a/include/FramelessHelper/Core/framelesshelpercore_global.h +++ b/include/FramelessHelper/Core/framelesshelpercore_global.h @@ -348,6 +348,23 @@ enum class WallpaperAspectStyle }; Q_ENUM_NS(WallpaperAspectStyle) +#ifdef Q_OS_WINDOWS +enum class RegistryRootKey +{ + ClassesRoot = 0, + CurrentUser = 1, + LocalMachine = 2, + Users = 3, + PerformanceData = 4, + CurrentConfig = 5, + DynData = 6, + CurrentUserLocalSettings = 7, + PerformanceText = 8, + PerformanceNlsText = 9 +}; +Q_ENUM_NS(RegistryRootKey) +#endif // Q_OS_WINDOWS + struct VersionNumber { int major = 0; diff --git a/include/FramelessHelper/Core/private/registry_p.h b/include/FramelessHelper/Core/private/registry_p.h new file mode 100644 index 0000000..a445d85 --- /dev/null +++ b/include/FramelessHelper/Core/private/registry_p.h @@ -0,0 +1,66 @@ +/* + * 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 + +QT_BEGIN_NAMESPACE +class QWinRegistryKey; +class QSettings; +QT_END_NAMESPACE + +FRAMELESSHELPER_BEGIN_NAMESPACE + +class FRAMELESSHELPER_CORE_API Registry : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY_MOVE(Registry) + +public: + explicit Registry(const Global::RegistryRootKey root, const QString &key, QObject *parent = nullptr); + ~Registry() override; + + Q_NODISCARD Global::RegistryRootKey rootKey() const; + Q_NODISCARD QString subKey() const; + + Q_NODISCARD bool isValid() const; + + Q_NODISCARD QVariant value(const QString &name) const; + +private: + Global::RegistryRootKey m_rootKey = Global::RegistryRootKey::CurrentUser; + QString m_subKey = {}; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QScopedPointer m_registry; +#else + QScopedPointer m_settings; + bool m_valid = false; +#endif +}; + +FRAMELESSHELPER_END_NAMESPACE + +Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(Registry)) diff --git a/include/FramelessHelper/Quick/framelesshelperquick_global.h b/include/FramelessHelper/Quick/framelesshelperquick_global.h index b7bbbd4..1d06f3e 100644 --- a/include/FramelessHelper/Quick/framelesshelperquick_global.h +++ b/include/FramelessHelper/Quick/framelesshelperquick_global.h @@ -154,7 +154,6 @@ struct FRAMELESSHELPER_QUICK_API QuickGlobal FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowsVersion, Latest) }; Q_ENUM(WindowsVersion) - static_assert(static_cast(WindowsVersion::Latest) == static_cast(Global::WindowsVersion::Latest)); #endif // Q_OS_WINDOWS enum class ApplicationType diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7c50a23..2e021e4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -85,7 +85,11 @@ if(WIN32) ${INCLUDE_PREFIX}/FramelessHelper_Windows ${INCLUDE_PREFIX}/FramelessHelper_Win ) + list(APPEND PRIVATE_HEADERS + ${INCLUDE_PREFIX}/private/registry_p.h + ) list(APPEND SOURCES + registry.cpp utils_win.cpp framelesshelper_win.cpp ) diff --git a/src/core/global.cpp b/src/core/global.cpp index 20500c9..3a1c735 100644 --- a/src/core/global.cpp +++ b/src/core/global.cpp @@ -36,6 +36,9 @@ #include "framelessconfig_p.h" #include "chromepalette_p.h" #include "micamaterial_p.h" +#ifdef Q_OS_WINDOWS +# include "registry_p.h" +#endif #include #ifndef COMPILER_STRING @@ -153,6 +156,9 @@ void initialize() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); +# ifdef Q_OS_WINDOWS + qRegisterMetaType(); +# endif qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); @@ -169,6 +175,9 @@ void initialize() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); +# ifdef Q_OS_WINDOWS + qRegisterMetaType(); +# endif #endif } diff --git a/src/core/registry.cpp b/src/core/registry.cpp new file mode 100644 index 0000000..bb848bc --- /dev/null +++ b/src/core/registry.cpp @@ -0,0 +1,131 @@ +/* + * 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 "registry_p.h" +#include +#include +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) +# include +#else +# include +#endif + +FRAMELESSHELPER_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcCoreRegistry, "wangwenx190.framelesshelper.core.registry") +#define INFO qCInfo(lcCoreRegistry) +#define DEBUG qCDebug(lcCoreRegistry) +#define WARNING qCWarning(lcCoreRegistry) +#define CRITICAL qCCritical(lcCoreRegistry) + +using namespace Global; + +static const HKEY g_keyMap[] = { + HKEY_CLASSES_ROOT, + HKEY_CURRENT_USER, + HKEY_LOCAL_MACHINE, + HKEY_USERS, + HKEY_PERFORMANCE_DATA, + HKEY_CURRENT_CONFIG, + HKEY_DYN_DATA, + HKEY_CURRENT_USER_LOCAL_SETTINGS, + HKEY_PERFORMANCE_TEXT, + HKEY_PERFORMANCE_NLSTEXT +}; +static_assert(std::size(g_keyMap) == (static_cast(RegistryRootKey::PerformanceNlsText) + 1)); + +static const QString g_strMap[] = { + FRAMELESSHELPER_STRING_LITERAL("HKEY_CLASSES_ROOT"), + FRAMELESSHELPER_STRING_LITERAL("HKEY_CURRENT_USER"), + FRAMELESSHELPER_STRING_LITERAL("HKEY_LOCAL_MACHINE"), + FRAMELESSHELPER_STRING_LITERAL("HKEY_USERS"), + FRAMELESSHELPER_STRING_LITERAL("HKEY_PERFORMANCE_DATA"), + FRAMELESSHELPER_STRING_LITERAL("HKEY_CURRENT_CONFIG"), + FRAMELESSHELPER_STRING_LITERAL("HKEY_DYN_DATA"), + FRAMELESSHELPER_STRING_LITERAL("HKEY_CURRENT_USER_LOCAL_SETTINGS"), + FRAMELESSHELPER_STRING_LITERAL("HKEY_PERFORMANCE_TEXT"), + FRAMELESSHELPER_STRING_LITERAL("HKEY_PERFORMANCE_NLSTEXT") +}; +static_assert(std::size(g_strMap) == std::size(g_keyMap)); + +Registry::Registry(const RegistryRootKey root, const QString &key, QObject *parent) : QObject(parent) +{ + Q_ASSERT(!key.isEmpty()); + if (key.isEmpty()) { + return; + } + m_rootKey = root; + m_subKey = key; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + m_registry.reset(new QWinRegistryKey(g_keyMap[static_cast(m_rootKey)], m_subKey)); +#else + const QString rootKey = g_strMap[static_cast(m_rootKey)]; + m_settings.reset(new QSettings(rootKey, QSettings::NativeFormat)); + if (m_settings->contains(m_subKey)) { + m_settings.reset(new QSettings(rootKey + u'\\' + m_subKey, QSettings::NativeFormat)); + m_valid = true; + } +#endif +} + +Registry::~Registry() = default; + +RegistryRootKey Registry::rootKey() const +{ + return m_rootKey; +} + +QString Registry::subKey() const +{ + return m_subKey; +} + +bool Registry::isValid() const +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + return m_registry->isValid(); +#else + return m_valid; +#endif +} + +QVariant Registry::value(const QString &name) const +{ + Q_ASSERT(!name.isEmpty()); + Q_ASSERT(isValid()); + if (name.isEmpty() || !isValid()) { + return {}; + } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + const QPair dwValue = m_registry->dwordValue(name); + if (dwValue.second) { + return qulonglong(dwValue.first); + } + return m_registry->stringValue(name); +#else + return m_settings->value(name); +#endif +} + +FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/registry_p.h b/src/core/registry_p.h new file mode 100644 index 0000000..5a51446 --- /dev/null +++ b/src/core/registry_p.h @@ -0,0 +1 @@ +#include "../../include/FramelessHelper/Core/private/registry_p.h" diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 8bb7eb3..9f801c6 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -26,8 +26,11 @@ #include #include #include -#include +#include #include +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +# include +#endif #include #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) # include @@ -38,6 +41,7 @@ #include "framelesshelper_windows.h" #include "framelessconfig_p.h" #include "sysapiloader_p.h" +#include "registry_p.h" #include #include @@ -270,27 +274,21 @@ private: const std::wstring _Class = {}; }; -[[nodiscard]] static inline QString hkcuRegistryKey() -{ - static const QString key = FRAMELESSHELPER_STRING_LITERAL("HKEY_CURRENT_USER"); - return key; -} - [[nodiscard]] static inline QString dwmRegistryKey() { - static const QString key = (hkcuRegistryKey() + u'\\' + QString::fromWCharArray(kDwmRegistryKey)); + static const QString key = QString::fromWCharArray(kDwmRegistryKey); return key; } [[nodiscard]] static inline QString personalizeRegistryKey() { - static const QString key = (hkcuRegistryKey() + u'\\' + QString::fromWCharArray(kPersonalizeRegistryKey)); + static const QString key = QString::fromWCharArray(kPersonalizeRegistryKey); return key; } [[nodiscard]] static inline QString desktopRegistryKey() { - static const QString key = (hkcuRegistryKey() + u'\\' + QString::fromWCharArray(kDesktopRegistryKey)); + static const QString key = QString::fromWCharArray(kDesktopRegistryKey); return key; } @@ -377,6 +375,7 @@ private: if (code == ERROR_SUCCESS) { return kSuccessMessageText; } +#if 0 LPWSTR buf = nullptr; if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&buf), 0, nullptr) == 0) { @@ -385,6 +384,9 @@ private: const QString errorText = QString::fromWCharArray(buf).trimmed(); LocalFree(buf); buf = nullptr; +#else + const QString errorText = QSystemError::windowsString(code); +#endif return kErrorMessageTemplate.arg(function, QString::number(code), errorText); } @@ -605,7 +607,10 @@ bool Utils::isDwmCompositionEnabled() return true; } const auto resultFromRegistry = []() -> bool { - const QSettings registry(dwmRegistryKey(), QSettings::NativeFormat); + const Registry registry(RegistryRootKey::CurrentUser, dwmRegistryKey()); + if (!registry.isValid()) { + return false; + } bool ok = false; const DWORD value = registry.value(kComposition).toULongLong(&ok); return (ok && (value != 0)); @@ -691,7 +696,12 @@ void Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable) window->setProperty("_q_windowsCustomMargins", marginsVar); #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) if (QPlatformWindow *platformWindow = window->handle()) { - QGuiApplication::platformNativeInterface()->setWindowProperty(platformWindow, kWindowsCustomMargins, marginsVar); + if (const auto ni = QGuiApplication::platformNativeInterface()) { + ni->setWindowProperty(platformWindow, kWindowsCustomMargins, marginsVar); + } else { + WARNING << "Failed to retrieve the platform native interface."; + return; + } } else { WARNING << "Failed to retrieve the platform window."; return; @@ -723,7 +733,10 @@ QString Utils::getSystemErrorMessage(const QString &function) QColor Utils::getDwmColorizationColor() { const auto resultFromRegistry = []() -> QColor { - const QSettings registry(dwmRegistryKey(), QSettings::NativeFormat); + const Registry registry(RegistryRootKey::CurrentUser, dwmRegistryKey()); + if (!registry.isValid()) { + return kDefaultDarkGrayColor; + } bool ok = false; const DWORD value = registry.value(kColorizationColor).toULongLong(&ok); return (ok ? QColor::fromRgba(value) : kDefaultDarkGrayColor); @@ -748,12 +761,12 @@ DwmColorizationArea Utils::getDwmColorizationArea() if (!isWin10OrGreater) { return DwmColorizationArea::None_; } - const QSettings themeRegistry(personalizeRegistryKey(), QSettings::NativeFormat); + const Registry themeRegistry(RegistryRootKey::CurrentUser, personalizeRegistryKey()); bool themeOk = false; - const DWORD themeValue = themeRegistry.value(qDwmColorKeyName).toULongLong(&themeOk); - const QSettings dwmRegistry(dwmRegistryKey(), QSettings::NativeFormat); + const DWORD themeValue = themeRegistry.isValid() ? themeRegistry.value(qDwmColorKeyName).toULongLong(&themeOk) : 0; + const Registry dwmRegistry(RegistryRootKey::CurrentUser, dwmRegistryKey()); bool dwmOk = false; - const DWORD dwmValue = dwmRegistry.value(qDwmColorKeyName).toULongLong(&dwmOk); + const DWORD dwmValue = dwmRegistry.isValid() ? dwmRegistry.value(qDwmColorKeyName).toULongLong(&dwmOk) : 0; const bool theme = (themeOk && (themeValue != 0)); const bool dwm = (dwmOk && (dwmValue != 0)); if (theme && dwm) { @@ -1548,8 +1561,24 @@ bool Utils::shouldAppsUseDarkMode_windows() if (!isWin10RS1OrGreater) { return false; } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (const auto app = qApp->nativeInterface()) { + return app->isDarkMode(); + } else { + WARNING << "QWindowsApplication is not available."; + } +#elif (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + if (const auto ni = QGuiApplication::platformNativeInterface()) { + return ni->property("darkMode").toBool(); + } else { + WARNING << "Failed to retrieve the platform native interface."; + } +#endif const auto resultFromRegistry = []() -> bool { - const QSettings registry(personalizeRegistryKey(), QSettings::NativeFormat); + const Registry registry(RegistryRootKey::CurrentUser, personalizeRegistryKey()); + if (!registry.isValid()) { + return false; + } bool ok = false; const DWORD value = registry.value(kAppsUseLightTheme).toULongLong(&ok); return (ok && (value == 0)); @@ -1780,7 +1809,10 @@ QColor Utils::getDwmAccentColor() // so we'd better also do the same thing. // There's no Windows API to get this value, so we can only read it // directly from the registry. - const QSettings registry(dwmRegistryKey(), QSettings::NativeFormat); + const Registry registry(RegistryRootKey::CurrentUser, dwmRegistryKey()); + if (!registry.isValid()) { + return kDefaultDarkGrayColor; + } bool ok = false; const DWORD value = registry.value(kAccentColor).toULongLong(&ok); if (!ok) { @@ -1805,7 +1837,10 @@ QString Utils::getWallpaperFilePath() WallpaperAspectStyle Utils::getWallpaperAspectStyle() { static constexpr const auto defaultStyle = WallpaperAspectStyle::Fill; - const QSettings registry(desktopRegistryKey(), QSettings::NativeFormat); + const Registry registry(RegistryRootKey::CurrentUser, desktopRegistryKey()); + if (!registry.isValid()) { + return defaultStyle; + } bool ok = false; const DWORD wallpaperStyle = registry.value(kWallpaperStyle).toULongLong(&ok); if (!ok) { diff --git a/src/quick/framelessquickmodule.cpp b/src/quick/framelessquickmodule.cpp index 7498a45..0e531ff 100644 --- a/src/quick/framelessquickmodule.cpp +++ b/src/quick/framelessquickmodule.cpp @@ -88,14 +88,21 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); #endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))