Code refactor
1. Load dwmapi.dll and winmm.dll dynamically at runtime, to remove the dependency on those dlls 2. Use QSystemLibrary to load dlls, it can make the loading of system dlls safer, and avoid duplicating the code 3. Use QWinRegistryKey to access registry, no need to use QSettings in such scenarios 4. Adapt to new code when building against Qt 6.3 and newer. 5. Other minor tweaks. Fixes: #94
This commit is contained in:
parent
c3c5ef0d5d
commit
17601f386f
|
@ -17,8 +17,8 @@ set(CMAKE_AUTOUIC ON)
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Gui REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Gui REQUIRED)
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui REQUIRED)
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Quick)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick)
|
||||
|
||||
|
@ -83,13 +83,8 @@ if(TEST_UNIX)
|
|||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
dwmapi winmm
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::CorePrivate
|
||||
Qt${QT_VERSION_MAJOR}::GuiPrivate
|
||||
)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ RESOURCES += $$PWD/images.qrc
|
|||
win32 {
|
||||
CONFIG += windeployqt
|
||||
CONFIG -= embed_manifest_exe
|
||||
LIBS += -luser32 -lshell32 -ldwmapi -lwinmm
|
||||
LIBS += -luser32 -lshell32
|
||||
RC_FILE = $$PWD/example.rc
|
||||
OTHER_FILES += $$PWD/example.manifest
|
||||
}
|
||||
|
|
|
@ -33,9 +33,5 @@ target_compile_definitions(MainWindow PRIVATE
|
|||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060100
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060200
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(MainWindow PRIVATE dwmapi)
|
||||
endif()
|
||||
|
|
|
@ -31,9 +31,5 @@ target_compile_definitions(Quick PRIVATE
|
|||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060100
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060200
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(Quick PRIVATE dwmapi)
|
||||
endif()
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
TARGET = Quick
|
||||
TEMPLATE = app
|
||||
QT += quick quickcontrols2
|
||||
CONFIG(release, debug|release): CONFIG += qtquickcompiler
|
||||
SOURCES += main.cpp
|
||||
RESOURCES += qml.qrc
|
||||
include($$PWD/../common.pri)
|
||||
|
|
|
@ -31,9 +31,5 @@ target_compile_definitions(Widget PRIVATE
|
|||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060100
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060200
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(Widget PRIVATE dwmapi)
|
||||
endif()
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/private/qsystemlibrary_p.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include "utilities.h"
|
||||
#include "framelesshelper_windows.h"
|
||||
|
@ -140,7 +141,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
}
|
||||
#if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
|
||||
// Work-around a bug caused by typo which only exists in Qt 5.11.1
|
||||
const auto msg = *reinterpret_cast<MSG **>(message);
|
||||
const auto msg = *static_cast<MSG **>(message);
|
||||
#else
|
||||
const auto msg = static_cast<LPMSG>(message);
|
||||
#endif
|
||||
|
@ -377,62 +378,73 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
clientRect->bottom += 1;
|
||||
#endif
|
||||
if (Utilities::isDwmCompositionAvailable()) {
|
||||
// Dirty hack to workaround the resize flicker caused by DWM.
|
||||
LARGE_INTEGER freq = {};
|
||||
if (QueryPerformanceFrequency(&freq) == FALSE) {
|
||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("QueryPerformanceFrequency"));
|
||||
break;
|
||||
}
|
||||
TIMECAPS tc = {};
|
||||
if (timeGetDevCaps(&tc, sizeof(tc)) != MMSYSERR_NOERROR) {
|
||||
qWarning() << "timeGetDevCaps() failed.";
|
||||
break;
|
||||
}
|
||||
const UINT ms_granularity = tc.wPeriodMin;
|
||||
if (timeBeginPeriod(ms_granularity) != TIMERR_NOERROR) {
|
||||
qWarning() << "timeBeginPeriod() failed.";
|
||||
break;
|
||||
}
|
||||
LARGE_INTEGER now0 = {};
|
||||
if (QueryPerformanceCounter(&now0) == FALSE) {
|
||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("QueryPerformanceCounter"));
|
||||
break;
|
||||
}
|
||||
// ask DWM where the vertical blank falls
|
||||
DWM_TIMING_INFO dti;
|
||||
SecureZeroMemory(&dti, sizeof(dti));
|
||||
dti.cbSize = sizeof(dti);
|
||||
const HRESULT hr = DwmGetCompositionTimingInfo(nullptr, &dti);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("DwmGetCompositionTimingInfo"));
|
||||
break;
|
||||
}
|
||||
LARGE_INTEGER now1 = {};
|
||||
if (QueryPerformanceCounter(&now1) == FALSE) {
|
||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("QueryPerformanceCounter"));
|
||||
break;
|
||||
}
|
||||
// - DWM told us about SOME vertical blank
|
||||
// - past or future, possibly many frames away
|
||||
// - convert that into the NEXT vertical blank
|
||||
const LONGLONG period = dti.qpcRefreshPeriod;
|
||||
const LONGLONG dt = dti.qpcVBlank - now1.QuadPart;
|
||||
LONGLONG w = 0, m = 0;
|
||||
if (dt >= 0) {
|
||||
w = dt / period;
|
||||
} else {
|
||||
// reach back to previous period
|
||||
// - so m represents consistent position within phase
|
||||
w = -1 + dt / period;
|
||||
}
|
||||
m = dt - (period * w);
|
||||
Q_ASSERT(m >= 0);
|
||||
Q_ASSERT(m < period);
|
||||
const qreal m_ms = 1000.0 * static_cast<qreal>(m) / static_cast<qreal>(freq.QuadPart);
|
||||
Sleep(static_cast<DWORD>(qRound(m_ms)));
|
||||
if (timeEndPeriod(ms_granularity) != TIMERR_NOERROR) {
|
||||
qWarning() << "timeEndPeriod() failed.";
|
||||
break;
|
||||
const QString winmm = QStringLiteral("winmm");
|
||||
static const auto ptimeGetDevCaps =
|
||||
reinterpret_cast<MMRESULT(WINAPI *)(LPTIMECAPS, UINT)>(QSystemLibrary::resolve(winmm, "timeGetDevCaps"));
|
||||
static const auto ptimeBeginPeriod =
|
||||
reinterpret_cast<MMRESULT(WINAPI *)(UINT)>(QSystemLibrary::resolve(winmm, "timeBeginPeriod"));
|
||||
static const auto ptimeEndPeriod =
|
||||
reinterpret_cast<MMRESULT(WINAPI *)(UINT)>(QSystemLibrary::resolve(winmm, "timeEndPeriod"));
|
||||
static const auto pDwmGetCompositionTimingInfo =
|
||||
reinterpret_cast<HRESULT(WINAPI *)(HWND, DWM_TIMING_INFO *)>(QSystemLibrary::resolve(QStringLiteral("dwmapi"), "DwmGetCompositionTimingInfo"));
|
||||
if (ptimeGetDevCaps && ptimeBeginPeriod && ptimeEndPeriod && pDwmGetCompositionTimingInfo) {
|
||||
// Dirty hack to workaround the resize flicker caused by DWM.
|
||||
LARGE_INTEGER freq = {};
|
||||
if (QueryPerformanceFrequency(&freq) == FALSE) {
|
||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("QueryPerformanceFrequency"));
|
||||
break;
|
||||
}
|
||||
TIMECAPS tc = {};
|
||||
if (ptimeGetDevCaps(&tc, sizeof(tc)) != MMSYSERR_NOERROR) {
|
||||
qWarning() << "timeGetDevCaps() failed.";
|
||||
break;
|
||||
}
|
||||
const UINT ms_granularity = tc.wPeriodMin;
|
||||
if (ptimeBeginPeriod(ms_granularity) != TIMERR_NOERROR) {
|
||||
qWarning() << "timeBeginPeriod() failed.";
|
||||
break;
|
||||
}
|
||||
LARGE_INTEGER now0 = {};
|
||||
if (QueryPerformanceCounter(&now0) == FALSE) {
|
||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("QueryPerformanceCounter"));
|
||||
break;
|
||||
}
|
||||
// ask DWM where the vertical blank falls
|
||||
DWM_TIMING_INFO dti;
|
||||
SecureZeroMemory(&dti, sizeof(dti));
|
||||
dti.cbSize = sizeof(dti);
|
||||
const HRESULT hr = pDwmGetCompositionTimingInfo(nullptr, &dti);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("DwmGetCompositionTimingInfo"));
|
||||
break;
|
||||
}
|
||||
LARGE_INTEGER now1 = {};
|
||||
if (QueryPerformanceCounter(&now1) == FALSE) {
|
||||
qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("QueryPerformanceCounter"));
|
||||
break;
|
||||
}
|
||||
// - DWM told us about SOME vertical blank
|
||||
// - past or future, possibly many frames away
|
||||
// - convert that into the NEXT vertical blank
|
||||
const LONGLONG period = dti.qpcRefreshPeriod;
|
||||
const LONGLONG dt = dti.qpcVBlank - now1.QuadPart;
|
||||
LONGLONG w = 0, m = 0;
|
||||
if (dt >= 0) {
|
||||
w = dt / period;
|
||||
} else {
|
||||
// reach back to previous period
|
||||
// - so m represents consistent position within phase
|
||||
w = -1 + dt / period;
|
||||
}
|
||||
m = dt - (period * w);
|
||||
Q_ASSERT(m >= 0);
|
||||
Q_ASSERT(m < period);
|
||||
const qreal m_ms = 1000.0 * static_cast<qreal>(m) / static_cast<qreal>(freq.QuadPart);
|
||||
Sleep(static_cast<DWORD>(qRound(m_ms)));
|
||||
if (ptimeEndPeriod(ms_granularity) != TIMERR_NOERROR) {
|
||||
qWarning() << "timeEndPeriod() failed.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We cannot return WVR_REDRAW otherwise Windows exhibits bugs where
|
||||
|
|
|
@ -77,7 +77,6 @@
|
|||
#include <QtCore/qt_windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <dwmapi.h>
|
||||
#include <timeapi.h>
|
||||
|
||||
#ifndef WM_NCUAHDRAWCAPTION
|
||||
#define WM_NCUAHDRAWCAPTION (0x00AE)
|
||||
|
@ -115,13 +114,13 @@
|
|||
#define IsMaximized(window) (IsZoomed(window) != FALSE)
|
||||
#endif
|
||||
|
||||
[[maybe_unused]] constexpr UINT kAutoHideTaskbarThickness = 2; // The thickness of an auto-hide taskbar in pixels
|
||||
[[maybe_unused]] static constexpr UINT kAutoHideTaskbarThickness = 2; // The thickness of an auto-hide taskbar in pixels
|
||||
|
||||
[[maybe_unused]] constexpr char kDwmRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)";
|
||||
[[maybe_unused]] constexpr char kPersonalizeRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)";
|
||||
[[maybe_unused]] static constexpr char kDwmRegistryKey[] = R"(Software\Microsoft\Windows\DWM)";
|
||||
[[maybe_unused]] static constexpr char kPersonalizeRegistryKey[] = R"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)";
|
||||
|
||||
[[maybe_unused]] constexpr UINT kDefaultResizeBorderThicknessClassic = 4;
|
||||
[[maybe_unused]] constexpr UINT kDefaultResizeBorderThicknessAero = 8;
|
||||
[[maybe_unused]] constexpr UINT kDefaultCaptionHeight = 23;
|
||||
[[maybe_unused]] static constexpr UINT kDefaultResizeBorderThicknessClassic = 4;
|
||||
[[maybe_unused]] static constexpr UINT kDefaultResizeBorderThicknessAero = 8;
|
||||
[[maybe_unused]] static constexpr UINT kDefaultCaptionHeight = 23;
|
||||
|
||||
[[maybe_unused]] constexpr DWORD _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37;
|
||||
[[maybe_unused]] static constexpr DWORD _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37;
|
||||
|
|
4
lib.pro
4
lib.pro
|
@ -2,7 +2,7 @@ TARGET = $$qtLibraryTarget(FramelessHelper)
|
|||
TEMPLATE = lib
|
||||
win32: DLLDESTDIR = $$OUT_PWD/bin
|
||||
else: unix: DESTDIR = $$OUT_PWD/bin
|
||||
QT += gui-private
|
||||
QT += core-private gui-private
|
||||
CONFIG += c++17 strict_c++ utf8_source warn_on
|
||||
DEFINES += \
|
||||
QT_NO_CAST_FROM_ASCII \
|
||||
|
@ -32,6 +32,6 @@ win32 {
|
|||
SOURCES += \
|
||||
utilities_win32.cpp \
|
||||
framelesshelper_win32.cpp
|
||||
LIBS += -luser32 -lshell32 -ldwmapi -lwinmm
|
||||
LIBS += -luser32 -lshell32
|
||||
RC_FILE = framelesshelper.rc
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
|
||||
#include "utilities.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtCore/private/qwinregistry_p.h>
|
||||
#include <QtCore/private/qsystemlibrary_p.h>
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
#include <QtCore/qoperatingsystemversion.h>
|
||||
#else
|
||||
|
@ -49,10 +50,12 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
return QPointF(static_cast<qreal>(nativePos.x), static_cast<qreal>(nativePos.y));
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline bool isWin10RS1OrGreater()
|
||||
[[nodiscard]] static inline bool isWin10RS5OrGreater()
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393));
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
|
||||
static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10_1809);
|
||||
#elif (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 17763));
|
||||
#else
|
||||
static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10);
|
||||
#endif
|
||||
|
@ -61,7 +64,9 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
[[nodiscard]] static inline bool isWin1019H1OrGreater()
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
|
||||
static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10_1903);
|
||||
#elif (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 18362));
|
||||
#else
|
||||
static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10);
|
||||
|
@ -138,17 +143,23 @@ bool Utilities::isDwmCompositionAvailable()
|
|||
if (isWin8OrGreater()) {
|
||||
return true;
|
||||
}
|
||||
BOOL enabled = FALSE;
|
||||
const HRESULT hr = DwmIsCompositionEnabled(&enabled);
|
||||
if (SUCCEEDED(hr)) {
|
||||
return (enabled != FALSE);
|
||||
} else {
|
||||
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmIsCompositionEnabled"), hr);
|
||||
const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
|
||||
bool ok = false;
|
||||
const DWORD value = registry.value(QStringLiteral("Composition"), 0).toUInt(&ok);
|
||||
return (ok && (value != 0));
|
||||
const auto resultFromRegistry = []() -> bool {
|
||||
QWinRegistryKey registry(HKEY_CURRENT_USER, QString::fromUtf8(kDwmRegistryKey));
|
||||
const auto result = registry.dwordValue(QStringLiteral("Composition"));
|
||||
return (result.second && (result.first != 0));
|
||||
};
|
||||
static const auto pDwmIsCompositionEnabled =
|
||||
reinterpret_cast<HRESULT(WINAPI *)(BOOL *)>(QSystemLibrary::resolve(QStringLiteral("dwmapi"), "DwmIsCompositionEnabled"));
|
||||
if (!pDwmIsCompositionEnabled) {
|
||||
return resultFromRegistry();
|
||||
}
|
||||
BOOL enabled = FALSE;
|
||||
const HRESULT hr = pDwmIsCompositionEnabled(&enabled);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmIsCompositionEnabled"), hr);
|
||||
return resultFromRegistry();
|
||||
}
|
||||
return (enabled != FALSE);
|
||||
}
|
||||
|
||||
int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue)
|
||||
|
@ -248,9 +259,14 @@ void Utilities::updateFrameMargins(const WId winId, const bool reset)
|
|||
if (!winId) {
|
||||
return;
|
||||
}
|
||||
static const auto pDwmExtendFrameIntoClientArea =
|
||||
reinterpret_cast<HRESULT(WINAPI *)(HWND, const MARGINS *)>(QSystemLibrary::resolve(QStringLiteral("dwmapi"), "DwmExtendFrameIntoClientArea"));
|
||||
if (!pDwmExtendFrameIntoClientArea) {
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(winId);
|
||||
const MARGINS margins = reset ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1};
|
||||
const HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins);
|
||||
const HRESULT hr = pDwmExtendFrameIntoClientArea(hwnd, &margins);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmExtendFrameIntoClientArea"), hr);
|
||||
}
|
||||
|
@ -303,14 +319,22 @@ QString Utilities::getSystemErrorMessage(const QString &function)
|
|||
|
||||
QColor Utilities::getColorizationColor()
|
||||
{
|
||||
static const auto pDwmGetColorizationColor =
|
||||
reinterpret_cast<HRESULT(WINAPI *)(DWORD *, BOOL *)>(QSystemLibrary::resolve(QStringLiteral("dwmapi"), "DwmGetColorizationColor"));
|
||||
if (!pDwmGetColorizationColor) {
|
||||
return Qt::darkGray;
|
||||
}
|
||||
DWORD color = 0;
|
||||
BOOL opaque = FALSE;
|
||||
const HRESULT hr = DwmGetColorizationColor(&color, &opaque);
|
||||
const HRESULT hr = pDwmGetColorizationColor(&color, &opaque);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(QStringLiteral("DwmGetColorizationColor"), hr);
|
||||
const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
|
||||
bool ok = false;
|
||||
color = registry.value(QStringLiteral("ColorizationColor"), 0).toUInt(&ok);
|
||||
QWinRegistryKey registry(HKEY_CURRENT_USER, QString::fromUtf8(kDwmRegistryKey));
|
||||
const auto result = registry.dwordValue(QStringLiteral("ColorizationColor"));
|
||||
if (!result.second) {
|
||||
return Qt::darkGray;
|
||||
}
|
||||
return QColor::fromRgba(result.first);
|
||||
}
|
||||
return QColor::fromRgba(color);
|
||||
}
|
||||
|
@ -324,9 +348,14 @@ int Utilities::getWindowVisibleFrameBorderThickness(const WId winId)
|
|||
if (!isWin10OrGreater()) {
|
||||
return 1;
|
||||
}
|
||||
static const auto pDwmGetWindowAttribute =
|
||||
reinterpret_cast<HRESULT(WINAPI *)(HWND, DWORD, PVOID, DWORD)>(QSystemLibrary::resolve(QStringLiteral("dwmapi"), "DwmGetWindowAttribute"));
|
||||
if (!pDwmGetWindowAttribute) {
|
||||
return 1;
|
||||
}
|
||||
const auto hWnd = reinterpret_cast<HWND>(winId);
|
||||
UINT value = 0;
|
||||
const HRESULT hr = DwmGetWindowAttribute(hWnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value));
|
||||
const HRESULT hr = pDwmGetWindowAttribute(hWnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value));
|
||||
if (SUCCEEDED(hr)) {
|
||||
const QWindow *w = findWindow(winId);
|
||||
return static_cast<int>(qRound(static_cast<qreal>(value) / (w ? w->devicePixelRatio() : 1.0)));
|
||||
|
@ -340,43 +369,25 @@ int Utilities::getWindowVisibleFrameBorderThickness(const WId winId)
|
|||
|
||||
bool Utilities::shouldAppsUseDarkMode()
|
||||
{
|
||||
if (!isWin10RS1OrGreater()) {
|
||||
// The dark mode was introduced in Windows 10 1809.
|
||||
if (!isWin10RS5OrGreater()) {
|
||||
return false;
|
||||
}
|
||||
const auto resultFromRegistry = []() -> bool {
|
||||
const QSettings registry(QString::fromUtf8(kPersonalizeRegistryKey), QSettings::NativeFormat);
|
||||
bool ok = false;
|
||||
const DWORD value = registry.value(QStringLiteral("AppsUseLightTheme"), 0).toUInt(&ok);
|
||||
return (ok && (value == 0));
|
||||
QWinRegistryKey registry(HKEY_CURRENT_USER, QString::fromUtf8(kPersonalizeRegistryKey));
|
||||
const auto result = registry.dwordValue(QStringLiteral("AppsUseLightTheme"));
|
||||
return (result.second && (result.first == 0));
|
||||
};
|
||||
// Starting from Windows 10 19H1, ShouldAppsUseDarkMode() always return "TRUE"
|
||||
// Starting from Windows 10 1903, ShouldAppsUseDarkMode() always return "TRUE"
|
||||
// (actually, a random non-zero number at runtime), so we can't use it due to
|
||||
// this unreliability. In this case, we just simply read the user's setting from
|
||||
// the registry instead, it's not elegant but at least it works well.
|
||||
if (isWin1019H1OrGreater()) {
|
||||
return resultFromRegistry();
|
||||
} else {
|
||||
static bool tried = false;
|
||||
using sig = BOOL(WINAPI *)();
|
||||
static sig func = nullptr;
|
||||
if (!func) {
|
||||
if (tried) {
|
||||
return resultFromRegistry();
|
||||
} else {
|
||||
tried = true;
|
||||
const HMODULE dll = LoadLibraryExW(L"UxTheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (!dll) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("LoadLibraryExW"));
|
||||
return resultFromRegistry();
|
||||
}
|
||||
func = reinterpret_cast<sig>(GetProcAddress(dll, MAKEINTRESOURCEA(132)));
|
||||
if (!func) {
|
||||
qWarning() << getSystemErrorMessage(QStringLiteral("GetProcAddress"));
|
||||
return resultFromRegistry();
|
||||
}
|
||||
}
|
||||
}
|
||||
return (func() != FALSE);
|
||||
static const auto pShouldAppsUseDarkMode =
|
||||
reinterpret_cast<BOOL(WINAPI *)(VOID)>(QSystemLibrary::resolve(QStringLiteral("uxtheme"), MAKEINTRESOURCEA(132)));
|
||||
return (pShouldAppsUseDarkMode ? (pShouldAppsUseDarkMode() != FALSE) : resultFromRegistry());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,12 +397,12 @@ ColorizationArea Utilities::getColorizationArea()
|
|||
return ColorizationArea::None;
|
||||
}
|
||||
const QString keyName = QStringLiteral("ColorPrevalence");
|
||||
const QSettings themeRegistry(QString::fromUtf8(kPersonalizeRegistryKey), QSettings::NativeFormat);
|
||||
const DWORD themeValue = themeRegistry.value(keyName, 0).toUInt();
|
||||
const QSettings dwmRegistry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat);
|
||||
const DWORD dwmValue = dwmRegistry.value(keyName, 0).toUInt();
|
||||
const bool theme = (themeValue != 0);
|
||||
const bool dwm = (dwmValue != 0);
|
||||
QWinRegistryKey themeRegistry(HKEY_CURRENT_USER, QString::fromUtf8(kPersonalizeRegistryKey));
|
||||
const auto themeValue = themeRegistry.dwordValue(keyName);
|
||||
QWinRegistryKey dwmRegistry(HKEY_CURRENT_USER, QString::fromUtf8(kDwmRegistryKey));
|
||||
const auto dwmValue = dwmRegistry.dwordValue(keyName);
|
||||
const bool theme = themeValue.second && (themeValue.first != 0);
|
||||
const bool dwm = dwmValue.second && (dwmValue.first != 0);
|
||||
if (theme && dwm) {
|
||||
return ColorizationArea::All;
|
||||
} else if (theme) {
|
||||
|
|
Loading…
Reference in New Issue