From 29901fc2a97eedd3c914f807d1819c9ea7e69973 Mon Sep 17 00:00:00 2001 From: Sine Striker <trueful@163.com> Date: 周一, 25 12月 2023 17:53:34 +0800 Subject: [PATCH] Optimize Windows 10 border handling --- src/core/contexts/win32windowcontext.cpp | 178 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 131 insertions(+), 47 deletions(-) diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp index d78ce81..6dec43f 100644 --- a/src/core/contexts/win32windowcontext.cpp +++ b/src/core/contexts/win32windowcontext.cpp @@ -5,6 +5,7 @@ #include <QtCore/QHash> #include <QtCore/QScopeGuard> #include <QtCore/QTimer> +#include <QtCore/QDateTime> #include <QtGui/QGuiApplication> #include <QtGui/QPainter> #include <QtGui/QPalette> @@ -658,6 +659,7 @@ } case DrawWindows10BorderHook: { +#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) if (!windowId) return; @@ -668,7 +670,7 @@ const auto hwnd = reinterpret_cast<HWND>(windowId); QPen pen; - pen.setWidth(getWindowFrameBorderThickness(hwnd) * 2); + pen.setWidth(int(getWindowFrameBorderThickness(hwnd)) * 2); const bool dark = isDarkThemeActive() && isDarkWindowFrameEnabled(hwnd); if (m_delegate->isWindowActive(m_host)) { @@ -688,7 +690,7 @@ } painter.save(); - // We needs anti-aliasing to give us better result. + // We need antialiasing to give us better result. painter.setRenderHint(QPainter::Antialiasing); painter.setPen(pen); @@ -698,21 +700,78 @@ }); painter.restore(); return; +#endif } + + case DrawWindows10BorderHook2: { +#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) + if (!m_windowHandle) + return; + + // https://github.com/microsoft/terminal/blob/71a6f26e6ece656084e87de1a528c4a8072eeabd/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp#L1025 + // https://docs.microsoft.com/en-us/windows/win32/dwm/customframe#extending-the-client-frame + // Draw a black rectangle to make Windows native top border show + + auto hWnd = reinterpret_cast<HWND>(windowId); + HDC hdc = ::GetDC(hWnd); + RECT windowRect{}; + ::GetClientRect(hWnd, &windowRect); + RECT rcTopBorder = { + 0, + 0, + RECT_WIDTH(windowRect), + int(getWindowFrameBorderThickness(hWnd)), + }; + ::FillRect(hdc, &rcTopBorder, + reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH))); + ::ReleaseDC(hWnd, hdc); +#endif + 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, ¶ms, + // &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); - } - - bool Win32WindowContext::needBorderPainter() const { - Q_UNUSED(this) - return isSystemBorderEnabled() && !isWin11OrGreater(); - } - - int Win32WindowContext::borderThickness() const { - return getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)); } void Win32WindowContext::winIdChanged() { @@ -731,8 +790,7 @@ auto hWnd = reinterpret_cast<HWND>(winId); if (!isSystemBorderEnabled()) { - static constexpr const MARGINS margins = {1, 1, 1, 1}; - DynamicApis::instance().pDwmExtendFrameIntoClientArea(hWnd, &margins); + setWindowAttribute("extra-margins", true); } { @@ -797,7 +855,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; } @@ -809,9 +867,43 @@ const QVariant &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 defaultEmptyMargins = {0, 0, 0, 0}; + static constexpr const MARGINS defaultExtraMargins = {1, 1, 1, 1}; + static constexpr const MARGINS extendedMargins = {-1, -1, -1, -1}; + if (key == QStringLiteral("extra-margins")) { + if (isWin11OrGreater()) + return false; + hasExtraMargins = attribute.toBool(); + DynamicApis::instance().pDwmExtendFrameIntoClientArea( + hwnd, hasExtraMargins ? &defaultExtraMargins : &defaultEmptyMargins); + 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 + static const auto &defaultMargins = + isSystemBorderEnabled() ? defaultExtraMargins : defaultEmptyMargins; if (key == QStringLiteral("mica")) { if (!isWin11OrGreater()) { return false; @@ -819,7 +911,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). @@ -844,14 +936,16 @@ apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins); } 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; @@ -864,14 +958,16 @@ apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins); } 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, @@ -909,13 +1005,15 @@ apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins); } 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; @@ -949,29 +1047,6 @@ } apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins); } - 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; @@ -2007,4 +2082,13 @@ 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