From c914992aa4db946be8945c36ccee05a9b8362e56 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Sat, 24 Sep 2022 17:57:38 +0800 Subject: [PATCH] adapt to latest qtbase Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- examples/dialog/dialog.cpp | 35 +++++++++++++++++++++++++++++++- examples/dialog/dialog.h | 3 +++ src/core/framelesshelper_qt.cpp | 2 ++ src/core/framelesshelper_win.cpp | 2 ++ src/core/framelessmanager.cpp | 11 ++++++++++ src/core/utils.cpp | 8 ++++++-- src/core/utils_win.cpp | 28 ++++++++++++++++++++----- 7 files changed, 81 insertions(+), 8 deletions(-) diff --git a/examples/dialog/dialog.cpp b/examples/dialog/dialog.cpp index de80b32..582fb42 100644 --- a/examples/dialog/dialog.cpp +++ b/examples/dialog/dialog.cpp @@ -2,6 +2,10 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include "dialog.h" +#include +#include +#include +#include #include #include #include @@ -19,6 +23,17 @@ FRAMELESSHELPER_USE_NAMESPACE using namespace Global; +FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry") + +[[nodiscard]] static inline QSettings *appConfigFile() +{ + const QFileInfo fileInfo(QCoreApplication::applicationFilePath()); + const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini"); + const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName; + const auto settings = new QSettings(iniFilePath, QSettings::IniFormat); + return settings; +} + Dialog::Dialog(QWidget *parent) : FramelessDialog(parent) { setupUi(); @@ -26,6 +41,13 @@ Dialog::Dialog(QWidget *parent) : FramelessDialog(parent) Dialog::~Dialog() = default; +void Dialog::closeEvent(QCloseEvent *event) +{ + const QScopedPointer settings(appConfigFile()); + settings->setValue(kIniKeyPath, saveGeometry()); + FramelessDialog::closeEvent(event); +} + void Dialog::setupUi() { setWindowTitle(tr("Qt Dialog demo")); @@ -109,6 +131,17 @@ void Dialog::setupUi() helper->setSystemButton(titleBar->maximizeButton(), SystemButtonType::Maximize); helper->setSystemButton(titleBar->closeButton(), SystemButtonType::Close); // Special hack to disable the overriding of the mouse cursor, it's totally different - // with making the window un-resizable, so we don't use setFixedSize() here. + // with making the window un-resizable: we still want the window be able to resize + // programatically, but we also want the user not able to resize the window manually. + // So apparently we can't use QWidget::setFixedWidth/Height/Size() here. FramelessWidgetsHelperPrivate::get(helper)->setProperty(FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_DONT_OVERRIDE_CURSOR"), true); + connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){ + const QScopedPointer settings(appConfigFile()); + const QByteArray data = settings->value(kIniKeyPath).toByteArray(); + if (data.isEmpty()) { + helper->moveWindowToDesktopCenter(); + } else { + restoreGeometry(data); + } + }); } diff --git a/examples/dialog/dialog.h b/examples/dialog/dialog.h index e4d2439..3d91e30 100644 --- a/examples/dialog/dialog.h +++ b/examples/dialog/dialog.h @@ -27,6 +27,9 @@ public: explicit Dialog(QWidget *parent = nullptr); ~Dialog() override; +protected: + void closeEvent(QCloseEvent *event) override; + private: void setupUi(); diff --git a/src/core/framelesshelper_qt.cpp b/src/core/framelesshelper_qt.cpp index 169d1c0..71dfc33 100644 --- a/src/core/framelesshelper_qt.cpp +++ b/src/core/framelesshelper_qt.cpp @@ -135,6 +135,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) if (!object || !event) { return false; } +#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) // First detect whether we got a theme change event or not, if so, // inform the user the system theme has changed. if (Utils::isThemeChangeEvent(event)) { @@ -146,6 +147,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) } return QObject::eventFilter(object, event); } +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) // We are only interested in events that are dispatched to top level windows. if (!object->isWindowType()) { return QObject::eventFilter(object, event); diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 04090b8..000a85a 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -1208,9 +1208,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // Sometimes the FramelessManager instance may be destroyed already. if (FramelessManager * const manager = FramelessManager::instance()) { if (FramelessManagerPrivate * const managerPriv = FramelessManagerPrivate::get(manager)) { +#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) if (systemThemeChanged) { managerPriv->notifySystemThemeHasChangedOrNot(); } +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) if (wallpaperChanged) { managerPriv->notifyWallpaperHasChangedOrNot(); } diff --git a/src/core/framelessmanager.cpp b/src/core/framelessmanager.cpp index a3d2619..2ed0190 100644 --- a/src/core/framelessmanager.cpp +++ b/src/core/framelessmanager.cpp @@ -28,6 +28,10 @@ #include #include #include +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) +# include +# include +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) #include "framelesshelper_qt.h" #include "framelessconfig_p.h" #include "utils.h" @@ -346,6 +350,13 @@ void FramelessManagerPrivate::initialize() #endif m_wallpaper = Utils::getWallpaperFilePath(); m_wallpaperAspectStyle = Utils::getWallpaperAspectStyle(); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + QStyleHints * const styleHints = QGuiApplication::styleHints(); + connect(styleHints, &QStyleHints::appearanceChanged, this, [this](const Qt::Appearance appearance){ + Q_UNUSED(appearance); + notifySystemThemeHasChangedOrNot(); + }); +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) } FramelessManager::FramelessManager(QObject *parent) : diff --git a/src/core/utils.cpp b/src/core/utils.cpp index 97e2414..60bb04a 100644 --- a/src/core/utils.cpp +++ b/src/core/utils.cpp @@ -27,7 +27,9 @@ #include #include #include -#if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1)) +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) +# include +#elif (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1)) # include # include #endif @@ -263,7 +265,9 @@ QColor Utils::calculateSystemButtonBackgroundColor(const SystemButtonType button bool Utils::shouldAppsUseDarkMode() { -#if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1)) +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + return (QGuiApplication::styleHints()->appearance() == Qt::Appearance::Dark); +#elif (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1)) if (const QPlatformTheme * const theme = QGuiApplicationPrivate::platformTheme()) { return (theme->appearance() == QPlatformTheme::Appearance::Dark); } diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 4789ad9..272aa1b 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -43,6 +43,7 @@ #include "sysapiloader_p.h" #include "registrykey_p.h" #include +#include EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API HRESULT WINAPI SetWindowThemeAttribute2(const HWND hWnd, const _WINDOWTHEMEATTRIBUTETYPE attrib, @@ -165,6 +166,9 @@ FRAMELESSHELPER_STRING_CONSTANT(DestroyWindow) FRAMELESSHELPER_STRING_CONSTANT(SetWindowThemeAttribute) FRAMELESSHELPER_STRING_CONSTANT(CreateDCW) FRAMELESSHELPER_STRING_CONSTANT(DeleteDC) +FRAMELESSHELPER_STRING_CONSTANT(d2d1) +FRAMELESSHELPER_STRING_CONSTANT(D2D1CreateFactory) +FRAMELESSHELPER_STRING_CONSTANT(ReloadSystemMetrics) struct Win32UtilsHelperData { @@ -843,7 +847,9 @@ bool Utils::isHighContrastModeEnabled() quint32 Utils::getPrimaryScreenDpi(const bool horizontal) { + // GetDesktopWindow(): The desktop window will always be in the primary monitor. if (const HMONITOR hMonitor = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTOPRIMARY)) { + // GetDpiForMonitor() is only available on Windows 8 and onwards. if (API_SHCORE_AVAILABLE(GetDpiForMonitor)) { UINT dpiX = 0, dpiY = 0; const HRESULT hr = API_CALL_FUNCTION(GetDpiForMonitor, hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); @@ -853,6 +859,7 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal) WARNING << __getSystemErrorMessage(kGetDpiForMonitor, hr); } } + // GetScaleFactorForMonitor() is only available on Windows 8 and onwards. if (API_SHCORE_AVAILABLE(GetScaleFactorForMonitor)) { DEVICE_SCALE_FACTOR factor = DEVICE_SCALE_FACTOR_INVALID; const HRESULT hr = API_CALL_FUNCTION(GetScaleFactorForMonitor, hMonitor, &factor); @@ -862,6 +869,7 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal) WARNING << __getSystemErrorMessage(kGetScaleFactorForMonitor, hr); } } + // This solution is supported on Windows 2000 and onwards. MONITORINFOEXW monitorInfo; SecureZeroMemory(&monitorInfo, sizeof(monitorInfo)); monitorInfo.cbSize = sizeof(monitorInfo); @@ -891,13 +899,14 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal) WARNING << getSystemErrorMessage(kMonitorFromWindow); } -#if 0 // The above solutions should be sufficient enough, no need to pull in a new dependency. + // Using Direct2D to get the primary monitor's DPI is only available on Windows 7 + // and onwards, but it has been marked as deprecated by Microsoft. if (API_D2D_AVAILABLE(D2D1CreateFactory)) { using D2D1CreateFactoryPtr = HRESULT(WINAPI *)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS *, void **); const auto pD2D1CreateFactory = reinterpret_cast(SysApiLoader::instance()->get(kD2D1CreateFactory)); - auto d2dFactory = CComPtr(nullptr); + ID2D1Factory *d2dFactory = nullptr; HRESULT hr = pD2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), nullptr, reinterpret_cast(&d2dFactory)); if (SUCCEEDED(hr)) { @@ -919,9 +928,14 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal) } else { WARNING << __getSystemErrorMessage(kD2D1CreateFactory, hr); } + if (d2dFactory) { + d2dFactory->Release(); + d2dFactory = nullptr; + } } -#endif + // Our last hope to get the DPI of the primary monitor, if all the above + // solutions failed, however, it won't happen in most cases. if (const HDC hdc = GetDC(nullptr)) { bool valid = false; const int dpiX = GetDeviceCaps(hdc, LOGPIXELSX); @@ -940,6 +954,9 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal) } else { WARNING << getSystemErrorMessage(kGetDC); } + + // We should never go here, but let's make it extra safe. Just assume we + // are not scaled (96 DPI) if we really can't get the real DPI. return USER_DEFAULT_SCREEN_DPI; } @@ -1124,11 +1141,12 @@ void Utils::maybeFixupQtInternals(const WId windowId) // necessary window styles in some cases (caused by misconfigured setWindowFlag(s) calls) // and this will also break the normal functionalities for our windows, so we do the // correction here unconditionally. + static constexpr const DWORD badWindowStyle = WS_POPUP; static constexpr const DWORD goodWindowStyle = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME); - if (!(windowStyle & goodWindowStyle)) { + if ((windowStyle & badWindowStyle) || !(windowStyle & goodWindowStyle)) { SetLastError(ERROR_SUCCESS); - if (SetWindowLongPtrW(hwnd, GWL_STYLE, ((windowStyle & ~WS_POPUP) | goodWindowStyle)) == 0) { + if (SetWindowLongPtrW(hwnd, GWL_STYLE, ((windowStyle & ~badWindowStyle) | goodWindowStyle)) == 0) { WARNING << getSystemErrorMessage(kSetWindowLongPtrW); } else { shouldUpdateFrame = true;