diff --git a/CMakeLists.txt b/CMakeLists.txt index 14ff718..6b5a69b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,7 +127,6 @@ if(WIN32) endif() target_link_libraries(${PROJECT_NAME} PRIVATE - Qt${QT_VERSION_MAJOR}::CorePrivate Qt${QT_VERSION_MAJOR}::GuiPrivate ) diff --git a/examples/mainwindow/main.cpp b/examples/mainwindow/main.cpp index f07ba48..1e6981a 100644 --- a/examples/mainwindow/main.cpp +++ b/examples/mainwindow/main.cpp @@ -27,6 +27,7 @@ int main(int argc, char *argv[]) { + QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); // High DPI scaling is enabled by default from Qt 6 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) // Windows: we are using the manifest file to get maximum compatibility diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index 8776c43..0ff2492 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -25,7 +25,6 @@ #include "mainwindow.h" #include #include "../../framelesswindowsmanager.h" -#include "../../utilities.h" MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) { @@ -131,7 +130,7 @@ void MainWindow::paintEvent(QPaintEvent *event) {0, h, 0, 0} }; painter.save(); - painter.setPen({Utilities::getNativeWindowFrameColor(isActiveWindow()), 1}); + painter.setPen({isActiveWindow() ? Qt::black : Qt::darkGray, 1}); painter.drawLines(lines); painter.restore(); } diff --git a/examples/quick/main.cpp b/examples/quick/main.cpp index 244fa75..a72d505 100644 --- a/examples/quick/main.cpp +++ b/examples/quick/main.cpp @@ -26,10 +26,10 @@ #include #include #include -#include int main(int argc, char *argv[]) { + QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); // High DPI scaling is enabled by default from Qt 6 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) // Windows: we are using the manifest file to get maximum compatibility @@ -55,10 +55,8 @@ int main(int argc, char *argv[]) QQmlApplicationEngine engine; #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - QQuickWindow::setGraphicsApi(QSGRendererInterface::Software); QQuickStyle::setStyle(QStringLiteral("Basic")); #else - QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software); QQuickStyle::setStyle(QStringLiteral("Default")); #endif diff --git a/examples/quick/qml/main.qml b/examples/quick/qml/main.qml index 2768ab3..75ab5d1 100644 --- a/examples/quick/qml/main.qml +++ b/examples/quick/qml/main.qml @@ -117,7 +117,7 @@ Window { anchors.fill: parent color: "transparent" border { - color: framelessHelper.nativeFrameColor + color: window.active ? "black" : "darkGray" width: window._flh_margin } } diff --git a/examples/widget/main.cpp b/examples/widget/main.cpp index b7f2455..929ed11 100644 --- a/examples/widget/main.cpp +++ b/examples/widget/main.cpp @@ -27,6 +27,7 @@ int main(int argc, char *argv[]) { + QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); // High DPI scaling is enabled by default from Qt 6 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) // Windows: we are using the manifest file to get maximum compatibility diff --git a/examples/widget/widget.cpp b/examples/widget/widget.cpp index b643655..72fbd71 100644 --- a/examples/widget/widget.cpp +++ b/examples/widget/widget.cpp @@ -103,7 +103,7 @@ void Widget::paintEvent(QPaintEvent *event) {0, h, 0, 0} }; painter.save(); - painter.setPen({Utilities::getNativeWindowFrameColor(isActiveWindow()), 1}); + painter.setPen({isActiveWindow() ? Qt::black : Qt::darkGray, 1}); painter.drawLines(lines); painter.restore(); } diff --git a/framelesshelper.cpp b/framelesshelper.cpp index 9c78152..229baa6 100644 --- a/framelesshelper.cpp +++ b/framelesshelper.cpp @@ -67,8 +67,8 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event) return false; } const auto currentWindow = qobject_cast(object); - const int m_borderWidth = FramelessWindowsManager::getBorderWidth(currentWindow); - const int m_borderHeight = FramelessWindowsManager::getBorderHeight(currentWindow); + const int m_borderWidth = FramelessWindowsManager::getResizeBorderWidth(currentWindow); + const int m_borderHeight = FramelessWindowsManager::getResizeBorderHeight(currentWindow); const int m_titleBarHeight = FramelessWindowsManager::getTitleBarHeight(currentWindow); const bool m_resizable = FramelessWindowsManager::getResizable(currentWindow); const auto getWindowEdges = diff --git a/framelesshelper_global.h b/framelesshelper_global.h index 5e79de4..b398d86 100644 --- a/framelesshelper_global.h +++ b/framelesshelper_global.h @@ -60,8 +60,8 @@ namespace _flh_global { [[maybe_unused]] const char _flh_framelessEnabled_flag[] = "_FRAMELESSHELPER_FRAMELESS_MODE_ENABLED"; -[[maybe_unused]] const char _flh_borderWidth_flag[] = "_FRAMELESSHELPER_WINDOW_BORDER_WIDTH"; -[[maybe_unused]] const char _flh_borderHeight_flag[] = "_FRAMELESSHELPER_WINDOW_BORDER_HEIGHT"; +[[maybe_unused]] const char _flh_borderWidth_flag[] = "_FRAMELESSHELPER_WINDOW_RESIZE_BORDER_WIDTH"; +[[maybe_unused]] const char _flh_borderHeight_flag[] = "_FRAMELESSHELPER_WINDOW_RESIZE_BORDER_HEIGHT"; [[maybe_unused]] const char _flh_titleBarHeight_flag[] = "_FRAMELESSHELPER_WINDOW_TITLE_BAR_HEIGHT"; [[maybe_unused]] const char _flh_hitTestVisibleInChrome_flag[] = "_FRAMELESSHELPER_HIT_TEST_VISIBLE_IN_CHROME"; [[maybe_unused]] const char _flh_useNativeTitleBar_flag[] = "_FRAMELESSHELPER_USE_NATIVE_TITLE_BAR"; diff --git a/framelesshelper_win32.cpp b/framelesshelper_win32.cpp index 3ea3f19..d6e42c9 100644 --- a/framelesshelper_win32.cpp +++ b/framelesshelper_win32.cpp @@ -22,14 +22,6 @@ * SOFTWARE. */ -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - #include "framelesshelper_win32.h" #include #include @@ -281,11 +273,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // The value of border width and border height should be // identical in most cases, when the scale factor is 1.0, it // should be eight pixels. - const int bh = getSystemMetric(window, Utilities::SystemMetric::BorderHeight, true); + const int bh = getSystemMetric(window, Utilities::SystemMetric::ResizeBorderHeight, true); clientRect->top += bh; if (!shouldHaveWindowFrame()) { clientRect->bottom -= bh; - const int bw = getSystemMetric(window, Utilities::SystemMetric::BorderWidth, true); + const int bw = getSystemMetric(window, Utilities::SystemMetric::ResizeBorderWidth, true); clientRect->left += bw; clientRect->right -= bw; } @@ -420,7 +412,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me case WM_NCPAINT: { // 边框阴影处于非客户区的范围,因此如果直接阻止非客户区的绘制,会导致边框阴影丢失 - if (!Utilities::isDwmBlurAvailable() && !shouldHaveWindowFrame()) { + if (!Utilities::isDwmCompositionAvailable() && !shouldHaveWindowFrame()) { // Only block WM_NCPAINT when DWM composition is disabled. If // it's blocked when DWM composition is enabled, the frame // shadow won't be drawn. @@ -434,7 +426,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me if (shouldHaveWindowFrame()) { break; } else { - if (Utilities::isDwmBlurAvailable()) { + if (Utilities::isDwmCompositionAvailable()) { // DefWindowProc won't repaint the window border if lParam // (normally a HRGN) is -1. See the following link's "lParam" // section: @@ -526,7 +518,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me POINT winLocalMouse = {qRound(globalMouse.x()), qRound(globalMouse.y())}; ScreenToClient(msg->hwnd, &winLocalMouse); const QPointF localMouse = {static_cast(winLocalMouse.x), static_cast(winLocalMouse.y)}; - const int bh = getSystemMetric(window, Utilities::SystemMetric::BorderHeight, true); + const int bh = getSystemMetric(window, Utilities::SystemMetric::ResizeBorderHeight, true); const int tbh = getSystemMetric(window, Utilities::SystemMetric::TitleBarHeight, true); const bool isTitleBar = (localMouse.y() <= tbh) && !Utilities::isHitTestVisibleInChrome(window); const bool isTop = localMouse.y() <= bh; @@ -560,7 +552,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me GetClientRect(msg->hwnd, &clientRect); const LONG ww = clientRect.right; const LONG wh = clientRect.bottom; - const int bw = getSystemMetric(window, Utilities::SystemMetric::BorderWidth, true); + const int bw = getSystemMetric(window, Utilities::SystemMetric::ResizeBorderWidth, true); if (IsMaximized(msg->hwnd)) { if (isTitleBar) { return HTCAPTION; diff --git a/framelessquickhelper.cpp b/framelessquickhelper.cpp index bf3c238..72d133c 100644 --- a/framelessquickhelper.cpp +++ b/framelessquickhelper.cpp @@ -25,40 +25,31 @@ #include "framelessquickhelper.h" #include "framelesswindowsmanager.h" #include -#include "utilities.h" FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent) : QQuickItem(parent) { - connect(this, &FramelessQuickHelper::windowChanged, this, [this](QQuickWindow *win){ - if (m_frameColorConnection) { - disconnect(m_frameColorConnection); - } - if (win) { - m_frameColorConnection = connect(win, &QQuickWindow::activeChanged, this, &FramelessQuickHelper::nativeFrameColorChanged); - } - }); } -int FramelessQuickHelper::borderWidth() const +int FramelessQuickHelper::resizeBorderWidth() const { - return FramelessWindowsManager::getBorderWidth(window()); + return FramelessWindowsManager::getResizeBorderWidth(window()); } -void FramelessQuickHelper::setBorderWidth(const int val) +void FramelessQuickHelper::setResizeBorderWidth(const int val) { - FramelessWindowsManager::setBorderWidth(window(), val); - Q_EMIT borderWidthChanged(); + FramelessWindowsManager::setResizeBorderWidth(window(), val); + Q_EMIT resizeBorderWidthChanged(); } -int FramelessQuickHelper::borderHeight() const +int FramelessQuickHelper::resizeBorderHeight() const { - return FramelessWindowsManager::getBorderHeight(window()); + return FramelessWindowsManager::getResizeBorderHeight(window()); } -void FramelessQuickHelper::setBorderHeight(const int val) +void FramelessQuickHelper::setResizeBorderHeight(const int val) { - FramelessWindowsManager::setBorderHeight(window(), val); - Q_EMIT borderHeightChanged(); + FramelessWindowsManager::setResizeBorderHeight(window(), val); + Q_EMIT resizeBorderHeightChanged(); } int FramelessQuickHelper::titleBarHeight() const @@ -83,15 +74,6 @@ void FramelessQuickHelper::setResizable(const bool val) Q_EMIT resizableChanged(); } -QColor FramelessQuickHelper::nativeFrameColor() const -{ - const auto win = window(); - if (!win) { - return Qt::black; - } - return Utilities::getNativeWindowFrameColor(win->isActive()); -} - void FramelessQuickHelper::removeWindowFrame() { FramelessWindowsManager::addWindow(window()); diff --git a/framelessquickhelper.h b/framelessquickhelper.h index 80b9b47..3502d05 100644 --- a/framelessquickhelper.h +++ b/framelessquickhelper.h @@ -34,21 +34,20 @@ class FRAMELESSHELPER_API FramelessQuickHelper : public QQuickItem #ifdef QML_NAMED_ELEMENT QML_NAMED_ELEMENT(FramelessHelper) #endif - Q_PROPERTY(int borderWidth READ borderWidth WRITE setBorderWidth NOTIFY borderWidthChanged) - Q_PROPERTY(int borderHeight READ borderHeight WRITE setBorderHeight NOTIFY borderHeightChanged) + Q_PROPERTY(int resizeBorderWidth READ resizeBorderWidth WRITE setResizeBorderWidth NOTIFY resizeBorderWidthChanged) + Q_PROPERTY(int resizeBorderHeight READ resizeBorderHeight WRITE setResizeBorderHeight NOTIFY resizeBorderHeightChanged) Q_PROPERTY(int titleBarHeight READ titleBarHeight WRITE setTitleBarHeight NOTIFY titleBarHeightChanged) Q_PROPERTY(bool resizable READ resizable WRITE setResizable NOTIFY resizableChanged) - Q_PROPERTY(QColor nativeFrameColor READ nativeFrameColor NOTIFY nativeFrameColorChanged) public: explicit FramelessQuickHelper(QQuickItem *parent = nullptr); ~FramelessQuickHelper() override = default; - [[nodiscard]] int borderWidth() const; - void setBorderWidth(const int val); + [[nodiscard]] int resizeBorderWidth() const; + void setResizeBorderWidth(const int val); - [[nodiscard]] int borderHeight() const; - void setBorderHeight(const int val); + [[nodiscard]] int resizeBorderHeight() const; + void setResizeBorderHeight(const int val); [[nodiscard]] int titleBarHeight() const; void setTitleBarHeight(const int val); @@ -56,8 +55,6 @@ public: [[nodiscard]] bool resizable() const; void setResizable(const bool val); - [[nodiscard]] QColor nativeFrameColor() const; - public Q_SLOTS: void removeWindowFrame(); void bringBackWindowFrame(); @@ -65,12 +62,8 @@ public Q_SLOTS: void setHitTestVisibleInChrome(QQuickItem *item, const bool visible); Q_SIGNALS: - void borderWidthChanged(); - void borderHeightChanged(); + void resizeBorderWidthChanged(); + void resizeBorderHeightChanged(); void titleBarHeightChanged(); void resizableChanged(); - void nativeFrameColorChanged(); - -private: - QMetaObject::Connection m_frameColorConnection = {}; }; diff --git a/framelesswindowsmanager.cpp b/framelesswindowsmanager.cpp index d54bf4e..47ced69 100644 --- a/framelesswindowsmanager.cpp +++ b/framelesswindowsmanager.cpp @@ -84,7 +84,7 @@ void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject window->setProperty(_flh_global::_flh_hitTestVisibleInChrome_flag, QVariant::fromValue(objList)); } -int FramelessWindowsManager::getBorderWidth(const QWindow *window) +int FramelessWindowsManager::getResizeBorderWidth(const QWindow *window) { Q_ASSERT(window); if (!window) { @@ -94,11 +94,11 @@ int FramelessWindowsManager::getBorderWidth(const QWindow *window) const int value = window->property(_flh_global::_flh_borderWidth_flag).toInt(); return value <= 0 ? 8 : value; #else - return Utilities::getSystemMetric(window, Utilities::SystemMetric::BorderWidth, false); + return Utilities::getSystemMetric(window, Utilities::SystemMetric::ResizeBorderWidth, false); #endif } -void FramelessWindowsManager::setBorderWidth(QWindow *window, const int value) +void FramelessWindowsManager::setResizeBorderWidth(QWindow *window, const int value) { Q_ASSERT(window); if (!window || (value <= 0)) { @@ -107,7 +107,7 @@ void FramelessWindowsManager::setBorderWidth(QWindow *window, const int value) window->setProperty(_flh_global::_flh_borderWidth_flag, value); } -int FramelessWindowsManager::getBorderHeight(const QWindow *window) +int FramelessWindowsManager::getResizeBorderHeight(const QWindow *window) { Q_ASSERT(window); if (!window) { @@ -117,11 +117,11 @@ int FramelessWindowsManager::getBorderHeight(const QWindow *window) const int value = window->property(_flh_global::_flh_borderHeight_flag).toInt(); return value <= 0 ? 8 : value; #else - return Utilities::getSystemMetric(window, Utilities::SystemMetric::BorderHeight, false); + return Utilities::getSystemMetric(window, Utilities::SystemMetric::ResizeBorderHeight, false); #endif } -void FramelessWindowsManager::setBorderHeight(QWindow *window, const int value) +void FramelessWindowsManager::setResizeBorderHeight(QWindow *window, const int value) { Q_ASSERT(window); if (!window || (value <= 0)) { diff --git a/framelesswindowsmanager.h b/framelesswindowsmanager.h index a8c5135..724057c 100644 --- a/framelesswindowsmanager.h +++ b/framelesswindowsmanager.h @@ -31,16 +31,17 @@ QT_FORWARD_DECLARE_CLASS(QObject) QT_FORWARD_DECLARE_CLASS(QWindow) QT_END_NAMESPACE -namespace FramelessWindowsManager { +namespace FramelessWindowsManager +{ FRAMELESSHELPER_API void addWindow(QWindow *window); FRAMELESSHELPER_API void removeWindow(QWindow *window); [[nodiscard]] FRAMELESSHELPER_API bool isWindowFrameless(const QWindow *window); FRAMELESSHELPER_API void setHitTestVisibleInChrome(QWindow *window, QObject *object, const bool value = true); -[[nodiscard]] FRAMELESSHELPER_API int getBorderWidth(const QWindow *window); -FRAMELESSHELPER_API void setBorderWidth(QWindow *window, const int value); -[[nodiscard]] FRAMELESSHELPER_API int getBorderHeight(const QWindow *window); -FRAMELESSHELPER_API void setBorderHeight(QWindow *window, const int value); +[[nodiscard]] FRAMELESSHELPER_API int getResizeBorderWidth(const QWindow *window); +FRAMELESSHELPER_API void setResizeBorderWidth(QWindow *window, const int value); +[[nodiscard]] FRAMELESSHELPER_API int getResizeBorderHeight(const QWindow *window); +FRAMELESSHELPER_API void setResizeBorderHeight(QWindow *window, const int value); [[nodiscard]] FRAMELESSHELPER_API int getTitleBarHeight(const QWindow *window); FRAMELESSHELPER_API void setTitleBarHeight(QWindow *window, const int value); [[nodiscard]] FRAMELESSHELPER_API bool getResizable(const QWindow *window); diff --git a/utilities.h b/utilities.h index 4340933..474fdc3 100644 --- a/utilities.h +++ b/utilities.h @@ -25,45 +25,33 @@ #pragma once #include "framelesshelper_global.h" -#include #include namespace Utilities { enum class SystemMetric { - BorderWidth, - BorderHeight, + ResizeBorderWidth, + ResizeBorderHeight, TitleBarHeight }; -// Common -[[nodiscard]] FRAMELESSHELPER_API int getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiAware, const bool forceSystemValue = false); -[[nodiscard]] FRAMELESSHELPER_API bool isLightThemeEnabled(); -[[nodiscard]] FRAMELESSHELPER_API bool isDarkThemeEnabled(); +[[nodiscard]] FRAMELESSHELPER_API int getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue = false); [[nodiscard]] FRAMELESSHELPER_API QWindow *findWindow(const WId winId); [[nodiscard]] FRAMELESSHELPER_API bool shouldUseNativeTitleBar(); [[nodiscard]] FRAMELESSHELPER_API bool isWindowFixedSize(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_API QPointF getGlobalMousePosition(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_API bool isHitTestVisibleInChrome(const QWindow *window); -[[nodiscard]] FRAMELESSHELPER_API QColor getNativeWindowFrameColor(const bool isActive = true); [[nodiscard]] FRAMELESSHELPER_API QPointF mapOriginPointToWindow(const QObject *object); #ifdef Q_OS_WINDOWS -// Windows specific [[nodiscard]] FRAMELESSHELPER_API bool isWin8OrGreater(); [[nodiscard]] FRAMELESSHELPER_API bool isWin8Point1OrGreater(); [[nodiscard]] FRAMELESSHELPER_API bool isWin10OrGreater(); -[[nodiscard]] FRAMELESSHELPER_API bool isWin10OrGreater(const int subVer); -[[nodiscard]] FRAMELESSHELPER_API bool isDwmBlurAvailable(); -[[nodiscard]] FRAMELESSHELPER_API bool isColorizationEnabled(); -[[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor(); +[[nodiscard]] FRAMELESSHELPER_API bool isDwmCompositionAvailable(); FRAMELESSHELPER_API void triggerFrameChange(const QWindow *window); FRAMELESSHELPER_API void updateFrameMargins(const QWindow *window, const bool reset); FRAMELESSHELPER_API void updateQtFrameMargins(QWindow *window, const bool enable); -[[nodiscard]] quint32 getWindowDpi(const QWindow *window); -[[nodiscard]] FRAMELESSHELPER_API QMargins getWindowNativeFrameMargins(const QWindow *window); -FRAMELESSHELPER_API void displaySystemMenu(const QWindow *window, const QPointF &pos = {}); #endif } diff --git a/utilities_win32.cpp b/utilities_win32.cpp index c20dee7..336cc3b 100644 --- a/utilities_win32.cpp +++ b/utilities_win32.cpp @@ -22,17 +22,7 @@ * SOFTWARE. */ -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - #include "utilities.h" -#include -#include #include #include #include @@ -51,85 +41,15 @@ Q_DECLARE_METATYPE(QMargins) -#ifndef USER_DEFAULT_SCREEN_DPI -// Only available since Windows Vista -#define USER_DEFAULT_SCREEN_DPI 96 -#endif - #ifndef SM_CXPADDEDBORDER // Only available since Windows Vista #define SM_CXPADDEDBORDER 92 #endif -static const QString g_dwmRegistryKey = QStringLiteral(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)"); -static const QString g_personalizeRegistryKey = QStringLiteral(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"); +// The standard values of resize border width, resize border height and title bar height when DPI is 96. +static const int g_defaultResizeBorderWidth = 8, g_defaultResizeBorderHeight = 8, g_defaultTitleBarHeight = 31; -// The standard values of border width, border height and title bar height when DPI is 96. -static const int g_defaultBorderWidth = 8, g_defaultBorderHeight = 8, g_defaultTitleBarHeight = 31; - -using MONITOR_DPI_TYPE = enum _MONITOR_DPI_TYPE -{ - MDT_EFFECTIVE_DPI = 0 -}; - -using PROCESS_DPI_AWARENESS = enum _PROCESS_DPI_AWARENESS -{ - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, - PROCESS_PER_MONITOR_DPI_AWARE = 2 -}; - -struct Win32Data -{ - using ShouldAppsUseDarkModePtr = BOOL(WINAPI *)(); - using ShouldSystemUseDarkModePtr = BOOL(WINAPI *)(); - - using GetDpiForMonitorPtr = HRESULT(WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *); - using GetProcessDpiAwarenessPtr = HRESULT(WINAPI *)(HANDLE, PROCESS_DPI_AWARENESS *); - using GetSystemDpiForProcessPtr = UINT(WINAPI *)(HANDLE); - using GetDpiForWindowPtr = UINT(WINAPI *)(HWND); - using GetDpiForSystemPtr = UINT(WINAPI *)(); - using GetSystemMetricsForDpiPtr = int(WINAPI *)(int, UINT); - using AdjustWindowRectExForDpiPtr = BOOL(WINAPI *)(LPRECT, DWORD, BOOL, DWORD, UINT); - - ShouldAppsUseDarkModePtr ShouldAppsUseDarkModePFN = nullptr; - ShouldSystemUseDarkModePtr ShouldSystemUseDarkModePFN = nullptr; - - GetDpiForMonitorPtr GetDpiForMonitorPFN = nullptr; - GetProcessDpiAwarenessPtr GetProcessDpiAwarenessPFN = nullptr; - GetSystemDpiForProcessPtr GetSystemDpiForProcessPFN = nullptr; - GetDpiForWindowPtr GetDpiForWindowPFN = nullptr; - GetDpiForSystemPtr GetDpiForSystemPFN = nullptr; - GetSystemMetricsForDpiPtr GetSystemMetricsForDpiPFN = nullptr; - AdjustWindowRectExForDpiPtr AdjustWindowRectExForDpiPFN = nullptr; - - explicit Win32Data() - { - load(); - } - - void load() - { - QSystemLibrary User32Dll(QStringLiteral("User32.dll")); - GetDpiForWindowPFN = reinterpret_cast(User32Dll.resolve("GetDpiForWindow")); - GetDpiForSystemPFN = reinterpret_cast(User32Dll.resolve("GetDpiForSystem")); - GetSystemMetricsForDpiPFN = reinterpret_cast(User32Dll.resolve("GetSystemMetricsForDpi")); - AdjustWindowRectExForDpiPFN = reinterpret_cast(User32Dll.resolve("AdjustWindowRectExForDpi")); - GetSystemDpiForProcessPFN = reinterpret_cast(User32Dll.resolve("GetSystemDpiForProcess")); - - QSystemLibrary UxThemeDll(QStringLiteral("UxTheme.dll")); - ShouldAppsUseDarkModePFN = reinterpret_cast(UxThemeDll.resolve(MAKEINTRESOURCEA(132))); - ShouldSystemUseDarkModePFN = reinterpret_cast(UxThemeDll.resolve(MAKEINTRESOURCEA(138))); - - QSystemLibrary SHCoreDll(QStringLiteral("SHCore.dll")); - GetDpiForMonitorPFN = reinterpret_cast(SHCoreDll.resolve("GetDpiForMonitor")); - GetProcessDpiAwarenessPFN = reinterpret_cast(SHCoreDll.resolve("GetProcessDpiAwareness")); - } -}; - -Q_GLOBAL_STATIC(Win32Data, win32Data) - -bool Utilities::isDwmBlurAvailable() +bool Utilities::isDwmCompositionAvailable() { // DWM Composition is always enabled and can't be disabled since Windows 8. if (isWin8OrGreater()) { @@ -137,132 +57,86 @@ bool Utilities::isDwmBlurAvailable() } BOOL enabled = FALSE; if (FAILED(DwmIsCompositionEnabled(&enabled))) { - qWarning() << "DwmIsCompositionEnabled failed."; + qWarning() << "DwmIsCompositionEnabled() failed."; return false; } return (enabled != FALSE); } -int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiAware, const bool forceSystemValue) +int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue) { Q_ASSERT(window); if (!window) { return 0; } - const qreal dpr = dpiAware ? window->devicePixelRatio() : 1.0; - const auto getSystemMetricsForWindow = [dpr](const int index, const bool dpiAware) -> int { - if (win32Data()->GetSystemMetricsForDpiPFN) { - const quint32 dpi = dpiAware ? qRound(USER_DEFAULT_SCREEN_DPI * dpr) : USER_DEFAULT_SCREEN_DPI; - return win32Data()->GetSystemMetricsForDpiPFN(index, dpi); - } else { - const int value = GetSystemMetrics(index); - return dpiAware ? value : qRound(value / dpr); - } - }; - int ret = 0; switch (metric) { - case SystemMetric::BorderWidth: { + case SystemMetric::ResizeBorderWidth: { const int bw = window->property(_flh_global::_flh_borderWidth_flag).toInt(); if ((bw > 0) && !forceSystemValue) { - ret = qRound(bw * dpr); + return qRound(static_cast(bw) * (dpiScale ? window->devicePixelRatio() : 1.0)); } else { - const int result_nondpi = getSystemMetricsForWindow(SM_CXSIZEFRAME, false) - + getSystemMetricsForWindow(SM_CXPADDEDBORDER, false); - const int result_dpi = getSystemMetricsForWindow(SM_CXSIZEFRAME, true) - + getSystemMetricsForWindow(SM_CXPADDEDBORDER, true); - const int result = dpiAware ? result_dpi : result_nondpi; - ret = result > 0 ? result : qRound(g_defaultBorderWidth * dpr); + const int result = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); + if (result > 0) { + if (dpiScale) { + return result; + } else { + return qRound(static_cast(result) / window->devicePixelRatio()); + } + } else { + if (dpiScale) { + return qRound(static_cast(g_defaultResizeBorderWidth) * window->devicePixelRatio()); + } else { + return g_defaultResizeBorderWidth; + } + } } - } break; - case SystemMetric::BorderHeight: { + } + case SystemMetric::ResizeBorderHeight: { const int bh = window->property(_flh_global::_flh_borderHeight_flag).toInt(); if ((bh > 0) && !forceSystemValue) { - ret = qRound(bh * dpr); + return qRound(static_cast(bh) * (dpiScale ? window->devicePixelRatio() : 1.0)); } else { - const int result_nondpi = getSystemMetricsForWindow(SM_CYSIZEFRAME, false) - + getSystemMetricsForWindow(SM_CXPADDEDBORDER, false); - const int result_dpi = getSystemMetricsForWindow(SM_CYSIZEFRAME, true) - + getSystemMetricsForWindow(SM_CXPADDEDBORDER, true); - const int result = dpiAware ? result_dpi : result_nondpi; - ret = result > 0 ? result : qRound(g_defaultBorderHeight * dpr); + // There is no "SM_CYPADDEDBORDER". + const int result = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); + if (result > 0) { + if (dpiScale) { + return result; + } else { + return qRound(static_cast(result) / window->devicePixelRatio()); + } + } else { + if (dpiScale) { + return qRound(static_cast(g_defaultResizeBorderHeight) * window->devicePixelRatio()); + } else { + return g_defaultResizeBorderHeight; + } + } } - } break; + } case SystemMetric::TitleBarHeight: { const int tbh = window->property(_flh_global::_flh_titleBarHeight_flag).toInt(); if ((tbh > 0) && !forceSystemValue) { - // Special case: this is the user defined value, - // don't change it and just return it untouched. - return qRound(tbh * dpr); + return qRound(static_cast(tbh) * (dpiScale ? window->devicePixelRatio() : 1.0)); } else { - const int result_nondpi = getSystemMetricsForWindow(SM_CYCAPTION, false); - const int result_dpi = getSystemMetricsForWindow(SM_CYCAPTION, true); - const int result = dpiAware ? result_dpi : result_nondpi; - ret = result > 0 ? result : qRound(g_defaultTitleBarHeight * dpr); + // There is no "SM_CYPADDEDBORDER". + const int result = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); + if (result > 0) { + if (dpiScale) { + return result; + } else { + return qRound(static_cast(result) / window->devicePixelRatio()); + } + } else { + if (dpiScale) { + return qRound(static_cast(g_defaultTitleBarHeight) * window->devicePixelRatio()); + } else { + return g_defaultTitleBarHeight; + } + } } - } break; } - // When dpr = 1.0 (DPI = 96): - // SM_CXSIZEFRAME = SM_CYSIZEFRAME = 4px - // SM_CXPADDEDBORDER = 4px - // SM_CYCAPTION = 23px - // Border Width = Border Height = SM_C(X|Y)SIZEFRAME + SM_CXPADDEDBORDER = 8px - // Title Bar Height = Border Height + SM_CYCAPTION = 31px - // dpr = 1.25 --> Title Bar Height = 38px - // dpr = 1.5 --> Title Bar Height = 45px - // dpr = 1.75 --> Title Bar Height = 51px - ret += (metric == SystemMetric::TitleBarHeight) ? getSystemMetric(window, SystemMetric::BorderHeight, dpiAware) : 0; - return ret; -} - -bool Utilities::isColorizationEnabled() -{ - if (!isWin10OrGreater()) { - return false; } - // TODO: Is there an official Win32 API to do this? - bool ok = false; - const QSettings registry(g_dwmRegistryKey, QSettings::NativeFormat); - const bool colorPrevalence = registry.value(QStringLiteral("ColorPrevalence"), 0).toULongLong(&ok) != 0; - return (ok && colorPrevalence); -} - -QColor Utilities::getColorizationColor() -{ - DWORD color = 0; - BOOL opaqueBlend = FALSE; - if (SUCCEEDED(DwmGetColorizationColor(&color, &opaqueBlend))) { - return QColor::fromRgba(color); - } - qWarning() << "DwmGetColorizationColor failed, reading from the registry instead."; - bool ok = false; - const QSettings settings(g_dwmRegistryKey, QSettings::NativeFormat); - const DWORD value = settings.value(QStringLiteral("ColorizationColor"), 0).toULongLong(&ok); - return ok ? QColor::fromRgba(value) : Qt::darkGray; -} - -bool Utilities::isLightThemeEnabled() -{ - return !isDarkThemeEnabled(); -} - -bool Utilities::isDarkThemeEnabled() -{ - if (!isWin10OrGreater()) { - return false; - } - // We can't use ShouldAppsUseDarkMode due to the following reason: - // it's not exported publicly so we can only load it dynamically through its ordinal name, - // however, its ordinal name has changed in some unknown system versions so we can't find - // the actual function now. But ShouldSystemUseDarkMode is not affected, we can still - // use it in the latest version of Windows. - if (win32Data()->ShouldSystemUseDarkModePFN) { - return win32Data()->ShouldSystemUseDarkModePFN(); - } - qDebug() << "ShouldSystemUseDarkMode() not available, reading from the registry instead."; - bool ok = false; - const QSettings settings(g_personalizeRegistryKey, QSettings::NativeFormat); - const bool lightThemeEnabled = settings.value(QStringLiteral("AppsUseLightTheme"), 0).toULongLong(&ok) != 0; - return (ok && !lightThemeEnabled); + return 0; } void Utilities::triggerFrameChange(const QWindow *window) @@ -272,12 +146,8 @@ void Utilities::triggerFrameChange(const QWindow *window) return; } const auto hwnd = reinterpret_cast(window->winId()); - Q_ASSERT(hwnd); - if (!hwnd) { - return; - } if (SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER) == FALSE) { - qWarning() << "SetWindowPos failed."; + qWarning() << "SetWindowPos() failed."; } } @@ -285,7 +155,7 @@ void Utilities::updateFrameMargins(const QWindow *window, const bool reset) { // DwmExtendFrameIntoClientArea() will always fail if DWM Composition is disabled. // No need to try in this case. - if (!isDwmBlurAvailable()) { + if (!isDwmCompositionAvailable()) { return; } Q_ASSERT(window); @@ -293,101 +163,12 @@ void Utilities::updateFrameMargins(const QWindow *window, const bool reset) return; } const auto hwnd = reinterpret_cast(window->winId()); - Q_ASSERT(hwnd); - if (!hwnd) { - return; - } const MARGINS margins = reset ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1}; if (FAILED(DwmExtendFrameIntoClientArea(hwnd, &margins))) { - qWarning() << "DwmExtendFrameIntoClientArea failed."; + qWarning() << "DwmExtendFrameIntoClientArea() failed."; } } -quint32 Utilities::getWindowDpi(const QWindow *window) -{ - Q_ASSERT(window); - if (!window) { - return USER_DEFAULT_SCREEN_DPI; - } - const auto hwnd = reinterpret_cast(window->winId()); - Q_ASSERT(hwnd); - if (!hwnd) { - return USER_DEFAULT_SCREEN_DPI; - } - if (QCoreApplication::testAttribute(Qt::AA_Use96Dpi)) { - return USER_DEFAULT_SCREEN_DPI; - } - if (win32Data()->GetDpiForWindowPFN) { - return win32Data()->GetDpiForWindowPFN(hwnd); - } else if (win32Data()->GetSystemDpiForProcessPFN) { - return win32Data()->GetSystemDpiForProcessPFN(GetCurrentProcess()); - } else if (win32Data()->GetDpiForSystemPFN) { - return win32Data()->GetDpiForSystemPFN(); - } else if (win32Data()->GetDpiForMonitorPFN) { - const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); - if (monitor) { - UINT dpiX = USER_DEFAULT_SCREEN_DPI, dpiY = USER_DEFAULT_SCREEN_DPI; - if (SUCCEEDED(win32Data()->GetDpiForMonitorPFN(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) { - return dpiX; - } else { - qWarning() << "GetDpiForMonitor failed"; - } - } else { - qWarning() << "MonitorFromWindow failed."; - } - } - // We can use Direct2D to get DPI since Win7 or Vista, but it's marked as deprecated by Microsoft - // in the latest SDK and we'll get compilation warnings because of that, so we just don't use it here. - const HDC hdc = GetDC(nullptr); - if (hdc) { - const int dpiX = GetDeviceCaps(hdc, LOGPIXELSX); - ReleaseDC(nullptr, hdc); - if (dpiX > 0) { - return dpiX; - } else { - qWarning() << "GetDeviceCaps failed."; - } - } - return USER_DEFAULT_SCREEN_DPI; -} - -QMargins Utilities::getWindowNativeFrameMargins(const QWindow *window) -{ - Q_ASSERT(window); - if (!window) { - return {}; - } - const auto hwnd = reinterpret_cast(window->winId()); - Q_ASSERT(hwnd); - if (!hwnd) { - return {}; - } - RECT rect = {0, 0, 0, 0}; - const LONG_PTR style = GetWindowLongPtrW(hwnd, GWL_STYLE); - const LONG_PTR exStyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); - if (win32Data()->AdjustWindowRectExForDpiPFN) { - if (win32Data()->AdjustWindowRectExForDpiPFN(&rect, style, FALSE, exStyle, getWindowDpi(window)) == FALSE) { - qWarning() << "AdjustWindowRectExForDpiPFN failed."; - } - } else { - if (AdjustWindowRectEx(&rect, style, FALSE, exStyle) == FALSE) { - qWarning() << "AdjustWindowRectEx failed."; - } - } - return {qAbs(rect.left), qAbs(rect.top), qAbs(rect.right), qAbs(rect.bottom)}; -} - -QColor Utilities::getNativeWindowFrameColor(const bool isActive) -{ - if (!isActive) { - return Qt::darkGray; - } - if (!isWin10OrGreater()) { - return Qt::black; - } - return isColorizationEnabled() ? getColorizationColor() : (isDarkThemeEnabled() ? Qt::white : Qt::black); -} - void Utilities::updateQtFrameMargins(QWindow *window, const bool enable) { Q_ASSERT(window); @@ -395,8 +176,8 @@ void Utilities::updateQtFrameMargins(QWindow *window, const bool enable) return; } const int tbh = enable ? Utilities::getSystemMetric(window, Utilities::SystemMetric::TitleBarHeight, true, true) : 0; - const int bw = enable ? Utilities::getSystemMetric(window, Utilities::SystemMetric::BorderWidth, true, true) : 0; - const int bh = enable ? Utilities::getSystemMetric(window, Utilities::SystemMetric::BorderHeight, true, true) : 0; + const int bw = enable ? Utilities::getSystemMetric(window, Utilities::SystemMetric::ResizeBorderWidth, true, true) : 0; + const int bh = enable ? Utilities::getSystemMetric(window, Utilities::SystemMetric::ResizeBorderHeight, true, true) : 0; const QMargins margins = {-bw, -tbh, -bw, -bh}; // left, top, right, bottom const QVariant marginsVar = QVariant::fromValue(margins); window->setProperty("_q_windowsCustomMargins", marginsVar); @@ -440,79 +221,3 @@ bool Utilities::isWin10OrGreater() return QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10; #endif } - -bool Utilities::isWin10OrGreater(const int subVer) -{ -#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) - return QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, subVer); -#else - Q_UNUSED(ver); - return QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10; -#endif -} - -void Utilities::displaySystemMenu(const QWindow *window, const QPointF &pos) -{ - Q_ASSERT(window); - if (!window) { - return; - } - const auto hwnd = reinterpret_cast(window->winId()); - Q_ASSERT(hwnd); - if (!hwnd) { - return; - } - const HMENU hMenu = GetSystemMenu(hwnd, FALSE); - if (!hMenu) { - qWarning() << "Failed to acquire the system menu."; - return; - } - MENUITEMINFOW mii; - SecureZeroMemory(&mii, sizeof(mii)); - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STATE; - mii.fType = 0; - mii.fState = MF_ENABLED; - SetMenuItemInfoW(hMenu, SC_RESTORE, FALSE, &mii); - SetMenuItemInfoW(hMenu, SC_SIZE, FALSE, &mii); - SetMenuItemInfoW(hMenu, SC_MOVE, FALSE, &mii); - SetMenuItemInfoW(hMenu, SC_MAXIMIZE, FALSE, &mii); - SetMenuItemInfoW(hMenu, SC_MINIMIZE, FALSE, &mii); - mii.fState = MF_GRAYED; - const bool isMin = [window]{ - return (window->windowState() == Qt::WindowMinimized); - }(); - const bool isMax = [window]{ - return (window->windowState() == Qt::WindowMaximized); - }(); - const bool isFull = [window]{ - return (window->windowState() == Qt::WindowFullScreen); - }(); - const bool isNormal = [window]{ - return (window->windowState() == Qt::WindowNoState); - }(); - const bool isFix = isWindowFixedSize(window); - if (isFix || isMax || isFull) { - SetMenuItemInfoW(hMenu, SC_SIZE, FALSE, &mii); - SetMenuItemInfoW(hMenu, SC_MAXIMIZE, FALSE, &mii); - } - if (isFix || isFull || isNormal) { - SetMenuItemInfoW(hMenu, SC_RESTORE, FALSE, &mii); - } - if (isMax || isFull) { - SetMenuItemInfoW(hMenu, SC_MOVE, FALSE, &mii); - } - if (isMin) { - SetMenuItemInfoW(hMenu, SC_MINIMIZE, FALSE, &mii); - } - const bool isRtl = QGuiApplication::isRightToLeft(); - const qreal dpr = window->devicePixelRatio(); - const QPointF point = pos.isNull() ? QPointF(QCursor::pos(window->screen())) * dpr : QPointF(window->mapToGlobal(pos.toPoint())) * dpr; - const LPARAM cmd = TrackPopupMenu(hMenu, - (TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_TOPALIGN | - (isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), - qRound(point.x()), qRound(point.y()), 0, hwnd, nullptr); - if (cmd) { - PostMessageW(hwnd, WM_SYSCOMMAND, cmd, 0); - } -}