From 6eb2efea00eb07ce3a6b089b984885ce4a08c9ca Mon Sep 17 00:00:00 2001
From: Sine Striker <trueful@163.com>
Date: 周五, 29 12月 2023 20:55:09 +0800
Subject: [PATCH] Add WinRegKey support

---
 src/core/contexts/win32windowcontext.cpp |  212 ++++++++++++++++++-----------------------------------
 1 files changed, 72 insertions(+), 140 deletions(-)

diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp
index 6dec43f..17a42c1 100644
--- a/src/core/contexts/win32windowcontext.cpp
+++ b/src/core/contexts/win32windowcontext.cpp
@@ -9,7 +9,6 @@
 #include <QtGui/QGuiApplication>
 #include <QtGui/QPainter>
 #include <QtGui/QPalette>
-#include <QtGui/QStyleHints>
 
 #include <QtGui/private/qhighdpiscaling_p.h>
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
@@ -26,10 +25,6 @@
 
 #include "qwkglobal_p.h"
 #include "qwkwindowsextra_p.h"
-
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-Q_DECLARE_METATYPE(QMargins)
-#endif
 
 namespace QWK {
 
@@ -51,13 +46,13 @@
     static WNDPROC g_qtWindowProc = nullptr;
 
     static inline bool
-#if !QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
+#if !QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
         constexpr
 #endif
 
         isSystemBorderEnabled() {
         return
-#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
+#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
             isWin10OrGreater()
 #else
             false
@@ -69,55 +64,6 @@
         ::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
                        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER |
                            SWP_FRAMECHANGED);
-    }
-
-    static inline quint32 getDpiForWindow(HWND hwnd) {
-        const DynamicApis &apis = DynamicApis::instance();
-        if (apis.pGetDpiForWindow) {         // Win10
-            return apis.pGetDpiForWindow(hwnd);
-        } else if (apis.pGetDpiForMonitor) { // Win8.1
-            HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
-            UINT dpiX{0};
-            UINT dpiY{0};
-            apis.pGetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
-            return dpiX;
-        } else { // Win2K
-            HDC hdc = ::GetDC(nullptr);
-            const int dpiX = ::GetDeviceCaps(hdc, LOGPIXELSX);
-            // const int dpiY = ::GetDeviceCaps(hdc, LOGPIXELSY);
-            ::ReleaseDC(nullptr, hdc);
-            return quint32(dpiX);
-        }
-    }
-
-    static inline quint32 getSystemMetricsForDpi(int index, quint32 dpi) {
-        const DynamicApis &apis = DynamicApis::instance();
-        if (apis.pGetSystemMetricsForDpi) {
-            return ::GetSystemMetricsForDpi(index, dpi);
-        }
-        return ::GetSystemMetrics(index);
-    }
-
-    static inline quint32 getWindowFrameBorderThickness(HWND hwnd) {
-        const DynamicApis &apis = DynamicApis::instance();
-        if (UINT result = 0; SUCCEEDED(apis.pDwmGetWindowAttribute(
-                hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &result, sizeof(result)))) {
-            return result;
-        }
-        return getSystemMetricsForDpi(SM_CXBORDER, getDpiForWindow(hwnd));
-    }
-
-    static inline quint32 getResizeBorderThickness(HWND hwnd) {
-        const quint32 dpi = getDpiForWindow(hwnd);
-        return getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
-               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
-    }
-
-    static inline quint32 getTitleBarHeight(HWND hwnd) {
-        const quint32 dpi = getDpiForWindow(hwnd);
-        return getSystemMetricsForDpi(SM_CYCAPTION, dpi) +
-               getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
-               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
     }
 
     static void setInternalWindowFrameMargins(QWindow *window, const QMargins &margins) {
@@ -455,8 +401,8 @@
             return false;
         }
 
-        static WindowsNativeEventFilter *instance;
-        static Win32WindowContext *lastMessageContext;
+        static inline WindowsNativeEventFilter *instance = nullptr;
+        static inline Win32WindowContext *lastMessageContext = nullptr;
 
         static inline void install() {
             if (instance) {
@@ -473,9 +419,6 @@
             instance = nullptr;
         }
     };
-
-    WindowsNativeEventFilter *WindowsNativeEventFilter::instance = nullptr;
-    Win32WindowContext *WindowsNativeEventFilter::lastMessageContext = nullptr;
 
     // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025
     // We can see from the source code that Qt will filter out some messages first and then send the
@@ -627,6 +570,7 @@
             case RaiseWindowHook: {
                 if (!windowId)
                     return;
+                m_delegate->setWindowVisible(m_host, true);
                 const auto hwnd = reinterpret_cast<HWND>(windowId);
                 bringWindowToFront(hwnd);
                 return;
@@ -659,7 +603,7 @@
             }
 
             case DrawWindows10BorderHook: {
-#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
+#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
                 if (!windowId)
                     return;
 
@@ -699,12 +643,12 @@
                     QPoint{m_windowHandle->width(), 0}
                 });
                 painter.restore();
-                return;
 #endif
+                return;
             }
 
             case DrawWindows10BorderHook2: {
-#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
+#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
                 if (!m_windowHandle)
                     return;
 
@@ -729,49 +673,43 @@
                 return;
             }
 
-                //            case AbstractWindowContext::DrawWindows10BackgroundHook: {
-                // #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
-                //                if (!m_windowHandle)
-                //                    return;
-                //
-                //                auto hWnd = reinterpret_cast<HWND>(windowId);
-                //                HDC hdc = ::GetDC(hWnd);
-                //                RECT windowRect{};
-                //                ::GetClientRect(hWnd, &windowRect);
-                //                RECT rcRest = {
-                //                    0,
-                //                    int(getWindowFrameBorderThickness(hWnd)),
-                //                    RECT_WIDTH(windowRect),
-                //                    RECT_HEIGHT(windowRect),
-                //                };
-                //                HBRUSH blueBrush = ::CreateSolidBrush(RGB(0, 0, 255));
-                //
-                //                // To hide the original title bar, we have to paint on top of it
-                //                with
-                //                // the alpha component set to 255. This is a hack to do it with
-                //                GDI.
-                //                // See NonClientIslandWindow::_UpdateFrameMargins for more
-                //                information. HDC opaqueDc; BP_PAINTPARAMS params =
-                //                {sizeof(params), BPPF_NOCLIP | BPPF_ERASE}; auto buf =
-                //                BeginBufferedPaint(hdc, &rcRest, BPBF_TOPDOWNDIB, &params,
-                //                &opaqueDc); if (!buf || !opaqueDc) {
-                //                    return;
-                //                }
-                //
-                //                ::FillRect(opaqueDc, &rcRest, blueBrush);
-                //                ::BufferedPaintSetAlpha(buf, nullptr, 255);
-                //                ::EndBufferedPaint(buf, TRUE);
-                //
-                //                ::DeleteObject(blueBrush);
-                //                ::ReleaseDC(hWnd, hdc);
-                // #endif
-                //                return;
-                //            }
-
             default:
                 break;
         }
         AbstractWindowContext::virtual_hook(id, data);
+    }
+
+    QVariant Win32WindowContext::windowAttribute(const QString &key) const {
+        if (key == QStringLiteral("window-rect")) {
+            if (!m_windowHandle)
+                return {};
+
+            RECT frame{};
+            auto hwnd = reinterpret_cast<HWND>(windowId);
+            // According to MSDN, WS_OVERLAPPED is not allowed for AdjustWindowRect.
+            auto style = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_STYLE) & ~WS_OVERLAPPED);
+            auto exStyle = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_EXSTYLE));
+            const DynamicApis &apis = DynamicApis::instance();
+            if (apis.pAdjustWindowRectExForDpi) {
+                apis.pAdjustWindowRectExForDpi(&frame, style, FALSE, exStyle,
+                                               getDpiForWindow(hwnd));
+            } else {
+                ::AdjustWindowRectEx(&frame, style, FALSE, exStyle);
+            }
+            return QVariant::fromValue(rect2qrect(frame));
+        }
+
+        if (key == QStringLiteral("win10-border-needed")) {
+            return isSystemBorderEnabled() && !isWin11OrGreater();
+        }
+
+        if (key == QStringLiteral("border-thickness")) {
+            return m_windowHandle
+                       ? int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)))
+                       : 0;
+        }
+
+        return AbstractWindowContext::windowAttribute(key);
     }
 
     void Win32WindowContext::winIdChanged() {
@@ -790,17 +728,24 @@
         auto hWnd = reinterpret_cast<HWND>(winId);
 
         if (!isSystemBorderEnabled()) {
-            setWindowAttribute("extra-margins", true);
+            static auto margins = QVariant::fromValue(QMargins(1, 1, 1, 1));
+
+            // If we remove the system border, the window will lose its shadow. If dwm is enabled,
+            // then we need to set at least 1px margins, otherwise the following operation will
+            // fail with no effect.
+            setWindowAttribute(QStringLiteral("extra-margins"), margins);
         }
 
+        // We should disable WS_SYSMENU, otherwise the system button icons will be visible if mica
+        // is enabled and the title bar is transparent.
         {
             auto style = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
-#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
-            ::SetWindowLongPtrW(hWnd, GWL_STYLE, style & (~WS_SYSMENU));
-#else
-            ::SetWindowLongPtrW(hWnd, GWL_STYLE,
-                                (style | WS_THICKFRAME | WS_CAPTION) & (~WS_SYSMENU));
-#endif
+            if (isSystemBorderEnabled()) {
+                ::SetWindowLongPtrW(hWnd, GWL_STYLE, style & (~WS_SYSMENU));
+            } else {
+                ::SetWindowLongPtrW(hWnd, GWL_STYLE,
+                                    (style | WS_THICKFRAME | WS_CAPTION) & (~WS_SYSMENU));
+            }
         }
 
         // Add managed window
@@ -865,18 +810,20 @@
 
     bool Win32WindowContext::windowAttributeChanged(const QString &key, const QVariant &attribute,
                                                     const QVariant &oldAttribute) {
+        Q_UNUSED(oldAttribute)
+
         const auto hwnd = reinterpret_cast<HWND>(m_windowHandle->winId());
         const DynamicApis &apis = DynamicApis::instance();
-        static constexpr const MARGINS defaultEmptyMargins = {0, 0, 0, 0};
-        static constexpr const MARGINS defaultExtraMargins = {1, 1, 1, 1};
         static constexpr const MARGINS extendedMargins = {-1, -1, -1, -1};
+        const auto &restoreMargins = [this, &apis, hwnd]() {
+            auto margins = qmargins2margins(
+                m_windowAttributes.value(QStringLiteral("extra-margins")).value<QMargins>());
+            apis.pDwmExtendFrameIntoClientArea(hwnd, &margins);
+        };
+
         if (key == QStringLiteral("extra-margins")) {
-            if (isWin11OrGreater())
-                return false;
-            hasExtraMargins = attribute.toBool();
-            DynamicApis::instance().pDwmExtendFrameIntoClientArea(
-                hwnd, hasExtraMargins ? &defaultExtraMargins : &defaultEmptyMargins);
-            return true;
+            auto margins = qmargins2margins(attribute.value<QMargins>());
+            return apis.pDwmExtendFrameIntoClientArea(hwnd, &margins) == S_OK;
         }
 
         if (key == QStringLiteral("dark-mode")) {
@@ -902,8 +849,6 @@
         }
 
         // For Win11 or later
-        static const auto &defaultMargins =
-            isSystemBorderEnabled() ? defaultExtraMargins : defaultEmptyMargins;
         if (key == QStringLiteral("mica")) {
             if (!isWin11OrGreater()) {
                 return false;
@@ -933,7 +878,7 @@
                     const BOOL enable = FALSE;
                     apis.pDwmSetWindowAttribute(hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable));
                 }
-                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
+                restoreMargins();
             }
             return true;
         }
@@ -955,7 +900,7 @@
                 const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_AUTO;
                 apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType,
                                             sizeof(backdropType));
-                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
+                restoreMargins();
             }
             return true;
         }
@@ -1002,18 +947,15 @@
                 //     wcad.cbData = sizeof(policy);
                 //     apis.pSetWindowCompositionAttribute(hwnd, &wcad);
 
-                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
+                restoreMargins();
             }
             return true;
         }
 
         if (key == QStringLiteral("dwm-blur")) {
-            // TODO: Optimize
-            // Currently not available!!!
             if (attribute.toBool()) {
-                // We need to extend the window frame into the whole client area to be able
-                // to see the blurred window background.
-                apis.pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
+                // We can't extend the window frame for this effect.
+                restoreMargins();
                 if (isWin8OrGreater()) {
                     ACCENT_POLICY policy{};
                     policy.dwAccentState = ACCENT_ENABLE_BLURBEHIND;
@@ -1045,7 +987,6 @@
                     bb.dwFlags = DWM_BB_ENABLE;
                     apis.pDwmEnableBlurBehindWindow(hwnd, &bb);
                 }
-                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
             }
             return true;
         }
@@ -1384,12 +1325,12 @@
                                                  LPARAM lParam, LRESULT *result) {
         switch (message) {
             case WM_SHOWWINDOW: {
-                if (!centered) {
+                if (!initialCentered) {
                     // If wParam is TRUE, the window is being shown.
                     // If lParam is zero, the message was sent because of a call to the ShowWindow
                     // function.
                     if (wParam && !lParam) {
-                        centered = true;
+                        initialCentered = true;
                         moveWindowToDesktopCenter(hWnd);
                     }
                 }
@@ -2080,15 +2021,6 @@
             return true;
         }
         return false;
-    }
-
-    bool Win32WindowContext::needBorderPainter() const {
-        Q_UNUSED(this)
-        return isSystemBorderEnabled() && !isWin11OrGreater();
-    }
-
-    int Win32WindowContext::borderThickness() const {
-        return int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)));
     }
 
 }

--
Gitblit v1.9.1