From 6b2d31247dc2c2804e571b31a71c8a423c1db9d4 Mon Sep 17 00:00:00 2001 From: Sine Striker <trueful@163.com> Date: 周二, 26 12月 2023 01:44:03 +0800 Subject: [PATCH] Totally fix top border issue on Win10 for QtWidgets --- src/core/contexts/win32windowcontext.cpp | 189 ++++++++++++++++++++--------------------------- 1 files changed, 80 insertions(+), 109 deletions(-) diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp index 9b92b0d..bf25bdb 100644 --- a/src/core/contexts/win32windowcontext.cpp +++ b/src/core/contexts/win32windowcontext.cpp @@ -27,10 +27,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 { // The thickness of an auto-hide taskbar in pixels. @@ -69,55 +65,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) { @@ -699,8 +646,8 @@ QPoint{m_windowHandle->width(), 0} }); painter.restore(); - return; #endif + return; } case DrawWindows10BorderHook2: { @@ -735,21 +682,29 @@ AbstractWindowContext::virtual_hook(id, data); } - bool Win32WindowContext::needBorderPainter() const { - Q_UNUSED(this) - return isSystemBorderEnabled() && !isWin11OrGreater(); - } + QVariant Win32WindowContext::windowAttribute(const QString &key) const { + if (key == QStringLiteral("title-bar-rect")) { + if (!m_windowHandle) + return {}; - int Win32WindowContext::borderThickness() const { - return int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId))); - } + auto hwnd = reinterpret_cast<HWND>(windowId); + RECT frame{}; + ::AdjustWindowRectExForDpi(&frame, ::GetWindowLongPtrW(hwnd, GWL_STYLE), FALSE, 0, + getDpiForWindow(hwnd)); + return QVariant::fromValue(rect2qrect(frame)); + } - void Win32WindowContext::resume(const QByteArray &eventType, void *message, - QT_NATIVE_EVENT_RESULT_TYPE *result) { - const auto msg = static_cast<const MSG *>(message); - LRESULT res = - ::CallWindowProcW(g_qtWindowProc, msg->hwnd, msg->message, msg->wParam, msg->lParam); - *result = decltype(*result)(res); + 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() { @@ -768,13 +723,8 @@ auto hWnd = reinterpret_cast<HWND>(winId); if (!isSystemBorderEnabled()) { - static constexpr const MARGINS margins = {1, 1, 1, 1}; - DynamicApis::instance().pDwmExtendFrameIntoClientArea(hWnd, &margins); - } else if (isWin10OrGreater() && !isWin11OrGreater()) { - // https://github.com/microsoft/terminal/blob/71a6f26e6ece656084e87de1a528c4a8072eeabd/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp#L940 - // Must call DWM API to extend top frame to client area - static constexpr const MARGINS margins = {0, 0, 1, 0}; - DynamicApis::instance().pDwmExtendFrameIntoClientArea(hWnd, &margins); + setWindowAttribute(QStringLiteral("extra-margins"), + QVariant::fromValue(QMargins(1, 1, 1, 1))); } { @@ -839,7 +789,7 @@ msg.wParam = wParam; msg.lParam = lParam; QT_NATIVE_EVENT_RESULT_TYPE res = 0; - if (dispatch(QByteArrayLiteral("windows_generic_MSG"), &msg, &res)) { + if (nativeDispatch(QByteArrayLiteral("windows_generic_MSG"), &msg, &res)) { *result = LRESULT(res); return true; } @@ -849,11 +799,46 @@ 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 extendMargins = {-1, -1, -1, -1}; - static const auto defaultMargins = - isSystemBorderEnabled() ? MARGINS{0, 0, 0, 0} : MARGINS{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")) { + auto margins = qmargins2margins(attribute.value<QMargins>()); + DynamicApis::instance().pDwmExtendFrameIntoClientArea(hwnd, &margins); + return true; + } + + if (key == QStringLiteral("dark-mode")) { + if (!isWin101809OrGreater()) { + return false; + } + + BOOL enable = attribute.toBool(); + if (isWin101903OrGreater()) { + apis.pSetPreferredAppMode(enable ? PAM_AUTO : PAM_DEFAULT); + } else { + apis.pAllowDarkModeForApp(enable); + } + for (const auto attr : { + _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, + _DWMWA_USE_IMMERSIVE_DARK_MODE, + }) { + apis.pDwmSetWindowAttribute(hwnd, attr, &enable, sizeof(enable)); + } + + apis.pFlushMenuThemes(); + return true; + } + + // For Win11 or later if (key == QStringLiteral("mica")) { if (!isWin11OrGreater()) { return false; @@ -861,7 +846,7 @@ 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, &extendMargins); + apis.pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins); if (isWin1122H2OrGreater()) { // Use official DWM API to enable Mica, available since Windows 11 22H2 // (10.0.22621). @@ -883,17 +868,19 @@ const BOOL enable = FALSE; apis.pDwmSetWindowAttribute(hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable)); } - apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins); + restoreMargins(); } return true; - } else if (key == QStringLiteral("mica-alt")) { + } + + if (key == QStringLiteral("mica-alt")) { if (!isWin1122H2OrGreater()) { return false; } 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, &extendMargins); + apis.pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins); // Use official DWM API to enable Mica Alt, available since Windows 11 22H2 // (10.0.22621). const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_TABBEDWINDOW; @@ -903,17 +890,19 @@ const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_AUTO; apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType, sizeof(backdropType)); - apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins); + restoreMargins(); } return true; - } else if (key == QStringLiteral("acrylic-material")) { + } + + if (key == QStringLiteral("acrylic-material")) { if (!isWin11OrGreater()) { return false; } 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, &extendMargins); + apis.pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins); const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_TRANSIENTWINDOW; apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType, @@ -948,16 +937,18 @@ // wcad.cbData = sizeof(policy); // apis.pSetWindowCompositionAttribute(hwnd, &wcad); - apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins); + restoreMargins(); } return true; - } else if (key == QStringLiteral("dwm-blur")) { + } + + 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, &extendMargins); + apis.pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins); if (isWin8OrGreater()) { ACCENT_POLICY policy{}; policy.dwAccentState = ACCENT_ENABLE_BLURBEHIND; @@ -989,28 +980,8 @@ bb.dwFlags = DWM_BB_ENABLE; apis.pDwmEnableBlurBehindWindow(hwnd, &bb); } - apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins); + restoreMargins(); } - return true; - } else if (key == QStringLiteral("dark-mode")) { - if (!isWin101809OrGreater()) { - return false; - } - - BOOL enable = attribute.toBool(); - if (isWin101903OrGreater()) { - apis.pSetPreferredAppMode(enable ? PAM_AUTO : PAM_DEFAULT); - } else { - apis.pAllowDarkModeForApp(enable); - } - for (const auto attr : { - _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, - _DWMWA_USE_IMMERSIVE_DARK_MODE, - }) { - apis.pDwmSetWindowAttribute(hwnd, attr, &enable, sizeof(enable)); - } - - apis.pFlushMenuThemes(); return true; } return false; -- Gitblit v1.9.1