From 9b1599d82e86d2d0463b60fe6fa61f94be50f983 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <zhaoyuhang@rankyee.com> Date: 周二, 05 12月 2023 14:48:52 +0800 Subject: [PATCH] port some more code (for os < win10) --- examples/shared/widgetframe/windowbar.cpp | 2 src/core/qwindowkit_windows.h | 8 ++++ examples/mainwindow/mainwindow.cpp | 6 +++ src/core/contexts/win32windowcontext.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index 65c4b12..7246fdd 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -54,11 +54,17 @@ return menuBar; }(); + static const auto buttonStyleSheet = QLatin1String{ "QPushButton{color:black;};QPushButton:hover{background-color:black;color:white;}" }; + auto iconButton = new QPushButton("I"); + iconButton->setStyleSheet(buttonStyleSheet); auto minButton = new QPushButton("鈥�"); + minButton->setStyleSheet(buttonStyleSheet); auto maxButton = new QPushButton("馃棖"); + maxButton->setStyleSheet(buttonStyleSheet); maxButton->setCheckable(true); auto closeButton = new QPushButton("鉁�"); + closeButton->setStyleSheet(buttonStyleSheet); auto windowBar = new QWK::WindowBar(); windowBar->setIconButton(iconButton); diff --git a/examples/shared/widgetframe/windowbar.cpp b/examples/shared/widgetframe/windowbar.cpp index fba9a49..a39ab4f 100644 --- a/examples/shared/widgetframe/windowbar.cpp +++ b/examples/shared/widgetframe/windowbar.cpp @@ -18,7 +18,7 @@ void WindowBarPrivate::init() { Q_Q(WindowBar); layout = new QHBoxLayout(); - layout->setMargin(0); + layout->setContentsMargins(QMargins()); layout->setSpacing(0); for (int i = IconButton; i <= CloseButton; ++i) { insertDefaultSpace(i); diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp index 82bf47c..49a6d69 100644 --- a/src/core/contexts/win32windowcontext.cpp +++ b/src/core/contexts/win32windowcontext.cpp @@ -28,6 +28,7 @@ struct DynamicApis { decltype(&::DwmFlush) pDwmFlush = nullptr; + decltype(&::DwmIsCompositionEnabled) pDwmIsCompositionEnabled = nullptr; decltype(&::GetDpiForWindow) pGetDpiForWindow = nullptr; decltype(&::GetSystemMetricsForDpi) pGetSystemMetricsForDpi = nullptr; decltype(&::GetDpiForMonitor) pGetDpiForMonitor = nullptr; @@ -45,6 +46,7 @@ QSystemLibrary dwmapi(QStringLiteral("dwmapi.dll")); pDwmFlush = reinterpret_cast<decltype(pDwmFlush)>(dwmapi.resolve("DwmFlush")); + pDwmIsCompositionEnabled = reinterpret_cast<decltype(pDwmIsCompositionEnabled)>(dwmapi.resolve("DwmIsCompositionEnabled")); } ~DynamicApis() = default; @@ -138,6 +140,12 @@ return hwnd2str(reinterpret_cast<WId>(hwnd)); } + static inline bool isWin8OrGreater() { + static const bool result = + QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8; + return result; + } + static inline bool isWin8Point1OrGreater() { static const bool result = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8_1; @@ -148,6 +156,26 @@ static const bool result = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10; return result; + } + + static inline bool isDwmCompositionEnabled() { + if (isWin8OrGreater()) { + return true; + } + const DynamicApis &apis = DynamicApis::instance(); + if (!apis.pDwmIsCompositionEnabled) { + return false; + } + BOOL enabled = FALSE; + return SUCCEEDED(apis.pDwmIsCompositionEnabled(&enabled)) && enabled; + } + + static inline void triggerFrameChange(HWND hwnd) { + Q_ASSERT(hwnd); + if (!hwnd) { + return; + } + ::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) { @@ -1087,7 +1115,7 @@ // window can behave just like a normal Win32 window even if we now // doesn't have a title bar at all. Most importantly, the flicker and // jitter during window resizing is totally gone now. The disadvantage - // is we have to draw a top frame border ourself. Previously I thought + // is we have to draw a top frame border ourselves. Previously I thought // we have to do the black magic in WM_PAINT just like what Windows // Terminal does, however, later I found that if we choose a proper // color, our homemade top border can almost have exactly the same @@ -1293,6 +1321,66 @@ default: break; } + if (!isWin10OrGreater()) { + switch (message) { + case WM_NCUAHDRAWCAPTION: + case WM_NCUAHDRAWFRAME: { + // These undocumented messages are sent to draw themed window + // borders. Block them to prevent drawing borders over the client + // area. + *result = FALSE; + return true; + } + case WM_NCPAINT: { + // 杈规闃村奖澶勪簬闈炲鎴峰尯鐨勮寖鍥达紝鍥犳濡傛灉鐩存帴闃绘闈炲鎴峰尯鐨勭粯鍒讹紝浼氬鑷磋竟妗嗛槾褰变涪澶� + + if (!isDwmCompositionEnabled()) { + // 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. + *result = FALSE; + return true; + } else { + break; + } + } + case WM_NCACTIVATE: { + if (isDwmCompositionEnabled()) { + // DefWindowProc won't repaint the window border if lParam (normally a HRGN) + // is -1. See the following link's "lParam" section: + // https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-ncactivate + // Don't use "*result = 0" here, otherwise the window won't respond to the + // window activation state change. + *result = ::DefWindowProcW(hWnd, WM_NCACTIVATE, wParam, -1); + } else { + if (wParam == FALSE) { + *result = TRUE; + } else { + *result = FALSE; + } + } + return true; + } + case WM_SETICON: + case WM_SETTEXT: { + // Disable painting while these messages are handled to prevent them + // from drawing a window caption over the client area. + const auto oldStyle = static_cast<DWORD>(::GetWindowLongPtrW(hWnd, GWL_STYLE)); + // Prevent Windows from drawing the default title bar by temporarily + // toggling the WS_VISIBLE style. + const DWORD newStyle = (oldStyle & ~WS_VISIBLE); + ::SetWindowLongPtrW(hWnd, GWL_STYLE, static_cast<LONG_PTR>(newStyle)); + triggerFrameChange(hWnd); + const LRESULT originalResult = ::DefWindowProcW(hWnd, message, wParam, lParam); + ::SetWindowLongPtrW(hWnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle)); + triggerFrameChange(hWnd); + *result = originalResult; + return true; + } + default: + break; + } + } return false; } diff --git a/src/core/qwindowkit_windows.h b/src/core/qwindowkit_windows.h index 5e35b2d..b36f429 100644 --- a/src/core/qwindowkit_windows.h +++ b/src/core/qwindowkit_windows.h @@ -37,4 +37,12 @@ # define WM_UNREGISTER_WINDOW_SERVICES (0x0272) #endif +#ifndef WM_NCUAHDRAWCAPTION +# define WM_NCUAHDRAWCAPTION (0x00AE) +#endif + +#ifndef WM_NCUAHDRAWFRAME +# define WM_NCUAHDRAWFRAME (0x00AF) +#endif + #endif // QWINDOWKIT_WINDOWS_H -- Gitblit v1.9.1