From ae65733b2d07f59bd6dceef109eeac8c786a9efa Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Fri, 11 Mar 2022 17:23:31 +0800 Subject: [PATCH] wip Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- CMakeLists.txt | 12 +- framelesshelper_global.h | 5 +- framelesshelper_win32.cpp | 327 +++++++++++++++++++++++------------- framelesshelper_windows.h | 1 + framelesswindowsmanager.cpp | 4 +- utilities.h | 6 +- utilities_win32.cpp | 76 ++++++--- 7 files changed, 275 insertions(+), 156 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e9d404..2181e15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,8 +20,8 @@ set(CMAKE_AUTORCC ON) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui REQUIRED) -find_package(QT NAMES Qt6 Qt5 COMPONENTS Quick) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick) +#find_package(QT NAMES Qt6 Qt5 COMPONENTS Quick) +#find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick) set(SOURCES framelesshelper_global.h @@ -34,12 +34,12 @@ set(SOURCES utilities.cpp ) -if(TARGET Qt${QT_VERSION_MAJOR}::Quick) +#[[if(TARGET Qt${QT_VERSION_MAJOR}::Quick) list(APPEND SOURCES framelessquickhelper.h framelessquickhelper.cpp ) -endif() +endif()]] if(WIN32) list(APPEND SOURCES @@ -85,11 +85,11 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::GuiPrivate ) -if(TARGET Qt${QT_VERSION_MAJOR}::Quick) +#[[if(TARGET Qt${QT_VERSION_MAJOR}::Quick) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Quick ) -endif() +endif()]] target_include_directories(${PROJECT_NAME} PUBLIC "$" diff --git a/framelesshelper_global.h b/framelesshelper_global.h index 0ded8b1..61f029a 100644 --- a/framelesshelper_global.h +++ b/framelesshelper_global.h @@ -151,10 +151,7 @@ enum class Property : int FrameBorderColor_Inactive = 15, SystemAccentColor = 16, SystemColorizationArea = 17, - SystemTheme = 18, - WallpaperBackgroundColor = 19, - WallpaperAspectStyle = 20, - WallpaperFilePath = 21 + SystemTheme = 18 }; Q_ENUM_NS(Property) diff --git a/framelesshelper_win32.cpp b/framelesshelper_win32.cpp index 5300dbb..6cbe963 100644 --- a/framelesshelper_win32.cpp +++ b/framelesshelper_win32.cpp @@ -24,6 +24,7 @@ #include "framelesshelper_win32.h" #include +#include #include #include #include "framelesswindowsmanager_p.h" @@ -64,8 +65,10 @@ void FramelessHelperWin::addWindow(QWindow *window) g_helper()->instance.reset(new FramelessHelperWin); qApp->installNativeEventFilter(g_helper()->instance.data()); } + const WId winId = window->winId(); + Utilities::fixupQtInternals(winId); Utilities::updateInternalWindowFrameMargins(window, true); - Utilities::updateWindowFrameMargins(window->winId(), false); + Utilities::updateWindowFrameMargins(winId, false); } void FramelessHelperWin::removeWindow(QWindow *window) @@ -98,13 +101,34 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // Anyway, we should skip the entire function in this case. return false; } + const WId winId = reinterpret_cast(msg->hwnd); const auto manager = Private::FramelessManager::instance(); + Q_CHECK_PTR(manager); + if (!manager) { + return false; + } manager->mutex.lock(); - if (!manager->winId.contains(reinterpret_cast(msg->hwnd))) { + if (!manager->winId.contains(winId)) { manager->mutex.unlock(); return false; } + const QUuid uuid = manager->winId.value(winId); + Q_ASSERT(manager->data.contains(uuid)); + if (!manager->data.contains(uuid)) { + manager->mutex.unlock(); + return false; + } + const QVariantHash data = manager->data.value(uuid); manager->mutex.unlock(); + Q_ASSERT(data.contains(kWindow)); + if (!data.contains(kWindow)) { + return false; + } + const auto window = qvariant_cast(data.value(kWindow)); + Q_ASSERT(window); + if (!window) { + return false; + } switch (msg->message) { case WM_NCCALCSIZE: { // Windows是根据这个消息的返回值来设置窗口的客户区(窗口中真正显示的内容) @@ -197,8 +221,20 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me const auto clientRect = ((static_cast(msg->wParam) == FALSE) ? reinterpret_cast(msg->lParam) : &(reinterpret_cast(msg->lParam))->rgrc[0]); + if (Utilities::isWin10OrGreater()) { + // Store the original top before the default window proc applies the default frame. + const LONG originalTop = clientRect->top; + // Apply the default frame. + const LRESULT ret = DefWindowProcW(msg->hwnd, WM_NCCALCSIZE, msg->wParam, msg->lParam); + if (ret != 0) { + *result = ret; + return true; + } + // Re-apply the original top from before the size of the default frame was applied. + clientRect->top = originalTop; + } const bool max = IsMaximized(msg->hwnd); - const bool full = Utilities::isFullScreen(reinterpret_cast(msg->hwnd)); + const bool full = Utilities::isFullScreen(winId); // We don't need this correction when we're fullscreen. We will // have the WS_POPUP size, so we don't have to worry about // borders, and the default frame will be fine. @@ -209,11 +245,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // then the window is clipped to the monitor so that the resize handle // do not appear because you don't need them (because you can't resize // a window when it's maximized unless you restore it). - const int resizeBorderThickness = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true, true); - clientRect->top += resizeBorderThickness; - clientRect->bottom -= resizeBorderThickness; - clientRect->left += resizeBorderThickness; - clientRect->right -= resizeBorderThickness; + const int frameSizeY = Utilities::getResizeBorderThickness(winId, false, true); + clientRect->top += frameSizeY; + if (!Utilities::isWin10OrGreater()) { + clientRect->bottom -= frameSizeY; + const int frameSizeX = Utilities::getResizeBorderThickness(winId, true, true); + clientRect->left += frameSizeX; + clientRect->right -= frameSizeX; + } } // Attempt to detect if there's an autohide taskbar, and if // there is, reduce our size a bit on the side with the taskbar, @@ -341,44 +380,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me *result = ((static_cast(msg->wParam) == FALSE) ? 0 : WVR_REDRAW); return true; } - 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 = 0; - return true; - } - case WM_NCPAINT: { - // 边框阴影处于非客户区的范围,因此如果直接阻止非客户区的绘制,会导致边框阴影丢失 - - if (!Utilities::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 = 0; - return true; - } else { - break; - } - } - case WM_NCACTIVATE: { - if (Utilities::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(msg->hwnd, WM_NCACTIVATE, msg->wParam, -1); - } else { - if (static_cast(msg->wParam) == FALSE) { - *result = TRUE; - } else { - *result = FALSE; - } - } - return true; - } case WM_NCHITTEST: { // 原生Win32窗口只有顶边是在窗口内部resize的,其余三边都是在窗口 // 外部进行resize的,其原理是,WS_THICKFRAME这个窗口样式会在窗 @@ -445,99 +446,111 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // another branch, if you are interested in it, you can give it a // try. - POINT winLocalMouse = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)}; - if (ScreenToClient(msg->hwnd, &winLocalMouse) == FALSE) { + const POINT globalPos = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)}; + POINT localPos = globalPos; + if (ScreenToClient(msg->hwnd, &localPos) == FALSE) { qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("ScreenToClient")); break; } - const QPointF localMouse = {static_cast(winLocalMouse.x), static_cast(winLocalMouse.y)}; - RECT clientRect = {0, 0, 0, 0}; - if (GetClientRect(msg->hwnd, &clientRect) == FALSE) { - qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("GetClientRect")); - break; - } - const LONG windowWidth = clientRect.right; const bool max = IsMaximized(msg->hwnd); - const bool isTop = localMouse.y() <= resizeBorderThickness; - *result = [clientRect, isTitleBar, &localMouse, resizeBorderThickness, windowWidth, isTop, window, max](){ - if (max) { - if (isTitleBar && mousePressed) { - return HTCAPTION; - } - return HTCLIENT; + const bool full = Utilities::isFullScreen(winId); + const int frameSizeY = Utilities::getResizeBorderThickness(winId, false, true); + const bool isTop = (localPos.y < frameSizeY); + const bool isTitleBar = false; // ### TODO + if (Utilities::isWin10OrGreater()) { + // This will handle the left, right and bottom parts of the frame + // because we didn't change them. + const LRESULT originalRet = DefWindowProcW(msg->hwnd, WM_NCHITTEST, 0, msg->lParam); + if (originalRet != HTCLIENT) { + *result = originalRet; + return true; } - const LONG windowHeight = clientRect.bottom; - const bool isBottom = (localMouse.y() >= (windowHeight - resizeBorderThickness)); + // At this point, we know that the cursor is inside the client area + // so it has to be either the little border at the top of our custom + // title bar or the drag bar. Apparently, it must be the drag bar or + // the little border at the top which the user can use to move or + // resize the window. + if (full) { + *result = HTCLIENT; + return true; + } + if (max) { + *result = (isTitleBar ? HTCAPTION : HTCLIENT); + return true; + } + if (isTop) { + *result = HTTOP; + return true; + } + if (isTitleBar) { + *result = HTCAPTION; + return true; + } + *result = HTCLIENT; + return true; + } else { + if (full) { + *result = HTCLIENT; + return true; + } + if (max) { + *result = (isTitleBar ? HTCAPTION : HTCLIENT); + return true; + } + RECT clientRect = {0, 0, 0, 0}; + if (GetClientRect(msg->hwnd, &clientRect) == FALSE) { + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("GetClientRect")); + break; + } + const LONG width = clientRect.right; + const LONG height = clientRect.bottom; + const bool isBottom = (localPos.y >= (height - frameSizeY)); // Make the border a little wider to let the user easy to resize on corners. - const qreal factor = (isTop || isBottom) ? 2.0 : 1.0; - const bool isLeft = (localMouse.x() <= qRound(static_cast(resizeBorderThickness) * factor)); - const bool isRight = (localMouse.x() >= (windowWidth - qRound(static_cast(resizeBorderThickness) * factor))); - const bool fixedSize = Utilities::isWindowFixedSize(window); - const auto getBorderValue = [fixedSize](int value) -> int { - return fixedSize ? HTCLIENT : value; - }; + const qreal scaleFactor = ((isTop || isBottom) ? 2.0 : 1.0); + const int frameSizeX = Utilities::getResizeBorderThickness(winId, true, true); + const auto scaledFrameSizeX = static_cast(qRound(qreal(frameSizeX) * scaleFactor)); + const bool isLeft = (localPos.x < scaledFrameSizeX); + const bool isRight = (localPos.x >= (width - scaledFrameSizeX)); if (isTop) { if (isLeft) { - return getBorderValue(HTTOPLEFT); + *result = HTTOPLEFT; + return true; } if (isRight) { - return getBorderValue(HTTOPRIGHT); + *result = HTTOPRIGHT; + return true; } - return getBorderValue(HTTOP); + *result = HTTOP; + return true; } if (isBottom) { if (isLeft) { - return getBorderValue(HTBOTTOMLEFT); + *result = HTBOTTOMLEFT; + return true; } if (isRight) { - return getBorderValue(HTBOTTOMRIGHT); + *result = HTBOTTOMRIGHT; + return true; } - return getBorderValue(HTBOTTOM); + *result = HTBOTTOM; + return true; } if (isLeft) { - return getBorderValue(HTLEFT); + *result = HTLEFT; + return true; } if (isRight) { - return getBorderValue(HTRIGHT); + *result = HTRIGHT; + return true; } - if (isTitleBar && mousePressed) { - return HTCAPTION; + if (isTitleBar) { + *result = HTCAPTION; + return true; } - return HTCLIENT; - }(); - return true; + *result = HTCLIENT; + return true; + } } -#if 0 // This block of code is causing some problems in my own Qt Quick applications. Needs some more investigation. - 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. - SetLastError(ERROR_SUCCESS); - const LONG_PTR oldStyle = GetWindowLongPtrW(msg->hwnd, GWL_STYLE); - if (oldStyle == 0) { - qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("GetWindowLongPtrW")); - break; - } - // Prevent Windows from drawing the default title bar by temporarily - // toggling the WS_VISIBLE style. - SetLastError(ERROR_SUCCESS); - if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, static_cast(oldStyle & ~WS_VISIBLE)) == 0) { - qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW")); - break; - } - const auto winId = reinterpret_cast(msg->hwnd); - Utilities::triggerFrameChange(winId); - const LRESULT ret = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam); - SetLastError(ERROR_SUCCESS); - if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, oldStyle) == 0) { - qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW")); - break; - } - Utilities::triggerFrameChange(winId); - *result = ret; - return true; - } -#endif #if (QT_VERSION < QT_VERSION_CHECK(6, 2, 2)) case WM_WINDOWPOSCHANGING: { // Tell Windows to discard the entire contents of the client area, as re-using @@ -552,11 +565,93 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me } break; case WM_DWMCOMPOSITIONCHANGED: { // Re-apply the custom window frame if recovered from the basic theme. - Utilities::updateWindowFrameMargins(reinterpret_cast(msg->hwnd), false); + Utilities::updateWindowFrameMargins(winId, false); } break; default: break; } + if (Utilities::isWin101809OrGreater()) { + if (msg->message == WM_SETTINGCHANGE) { + if ((msg->wParam == 0) && (QString::compare(QString::fromWCharArray(reinterpret_cast(msg->lParam)), kThemeChangeEventName, Qt::CaseInsensitive) == 0)) { + const bool dark = Utilities::shouldAppsUseDarkMode(); + Utilities::updateWindowFrameBorderColor(winId, dark); + } + } + } + if (!Utilities::isWin10OrGreater()) { + switch (msg->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 = 0; + return true; + } + case WM_NCPAINT: { + // 边框阴影处于非客户区的范围,因此如果直接阻止非客户区的绘制,会导致边框阴影丢失 + + if (!Utilities::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 = 0; + return true; + } else { + break; + } + } + case WM_NCACTIVATE: { + if (Utilities::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(msg->hwnd, WM_NCACTIVATE, msg->wParam, -1); + } else { + if (static_cast(msg->wParam) == FALSE) { + *result = TRUE; + } else { + *result = FALSE; + } + } + return true; + } +#if 0 // This block of code is causing some problems in my own Qt Quick applications. Needs some more investigation. + 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. + SetLastError(ERROR_SUCCESS); + const LONG_PTR oldStyle = GetWindowLongPtrW(msg->hwnd, GWL_STYLE); + if (oldStyle == 0) { + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("GetWindowLongPtrW")); + break; + } + // Prevent Windows from drawing the default title bar by temporarily + // toggling the WS_VISIBLE style. + SetLastError(ERROR_SUCCESS); + if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, static_cast(oldStyle & ~WS_VISIBLE)) == 0) { + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW")); + break; + } + Utilities::triggerFrameChange(winId); + const LRESULT ret = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam); + SetLastError(ERROR_SUCCESS); + if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, oldStyle) == 0) { + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW")); + break; + } + Utilities::triggerFrameChange(winId); + *result = ret; + return true; + } +#endif + default: + break; + } + } return false; } diff --git a/framelesshelper_windows.h b/framelesshelper_windows.h index efd4b12..d0718f5 100644 --- a/framelesshelper_windows.h +++ b/framelesshelper_windows.h @@ -131,6 +131,7 @@ [[maybe_unused]] static const QString kDwmRegistryKey = QStringLiteral(R"(Software\Microsoft\Windows\DWM)"); [[maybe_unused]] static const QString kPersonalizeRegistryKey = QStringLiteral(R"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"); +[[maybe_unused]] static const QString kThemeChangeEventName = QStringLiteral("ImmersiveColorSet"); [[maybe_unused]] static constexpr const DWORD _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19; [[maybe_unused]] static constexpr const DWORD _DWMWA_USE_IMMERSIVE_DARK_MODE = 20; diff --git a/framelesswindowsmanager.cpp b/framelesswindowsmanager.cpp index b6ec9bf..963ed6c 100644 --- a/framelesswindowsmanager.cpp +++ b/framelesswindowsmanager.cpp @@ -25,6 +25,7 @@ #include "framelesswindowsmanager.h" #include "framelesswindowsmanager_p.h" #include +#include #include "framelesshelper.h" #include "utilities.h" #ifdef Q_OS_WINDOWS @@ -77,7 +78,8 @@ void FramelessWindowsManager::addWindow(QWindow *window) FramelessHelperWin::addWindow(window); } // Work-around Win32 multi-monitor artifacts. - QObject::connect(window, &QWindow::screenChanged, window, [window](){ + QObject::connect(window, &QWindow::screenChanged, window, [window](QScreen *screen){ + Q_UNUSED(screen); // Force a WM_NCCALCSIZE event to inform Windows about our custom window frame, // this is only necessary when the window is being moved cross monitors. Utilities::triggerFrameChange(window->winId()); diff --git a/utilities.h b/utilities.h index 0baa22d..957f293 100644 --- a/utilities.h +++ b/utilities.h @@ -51,9 +51,6 @@ FRAMELESSHELPER_API void showSystemMenu(const WId winId, const QPointF &pos); [[nodiscard]] FRAMELESSHELPER_API bool shouldAppsUseDarkMode(); [[nodiscard]] FRAMELESSHELPER_API DwmColorizationArea getDwmColorizationArea(); [[nodiscard]] FRAMELESSHELPER_API bool isHighContrastModeEnabled(); -[[nodiscard]] FRAMELESSHELPER_API QColor getWallpaperBackgroundColor(); -[[nodiscard]] FRAMELESSHELPER_API int getWallpaperAspectStyle(); -[[nodiscard]] FRAMELESSHELPER_API QString getWallpaperFilePath(); [[nodiscard]] FRAMELESSHELPER_API quint32 getPrimaryScreenDpi(const bool horizontal); [[nodiscard]] FRAMELESSHELPER_API quint32 getWindowDpi(const WId winId, const bool horizontal); [[nodiscard]] FRAMELESSHELPER_API quint32 getResizeBorderThickness(const WId winId, const bool horizontal, const bool scaled); @@ -61,7 +58,8 @@ FRAMELESSHELPER_API void showSystemMenu(const WId winId, const QPointF &pos); [[nodiscard]] FRAMELESSHELPER_API quint32 getTitleBarHeight(const WId winId, const bool scaled); [[nodiscard]] FRAMELESSHELPER_API quint32 getFrameBorderThickness(const WId winId, const bool scaled); [[nodiscard]] FRAMELESSHELPER_API QColor getFrameBorderColor(const bool active); -FRAMELESSHELPER_API void updateWindowFrameColor(const WId winId, const bool dark); +FRAMELESSHELPER_API void updateWindowFrameBorderColor(const WId winId, const bool dark); +FRAMELESSHELPER_API void fixupQtInternals(const WId winId); #endif // Q_OS_WINDOWS } // namespace Utilities diff --git a/utilities_win32.cpp b/utilities_win32.cpp index f387584..4c92acb 100644 --- a/utilities_win32.cpp +++ b/utilities_win32.cpp @@ -198,23 +198,32 @@ void Utilities::triggerFrameChange(const WId winId) void Utilities::updateWindowFrameMargins(const WId winId, const bool reset) { + Q_ASSERT(winId); + if (!winId) { + return; + } // DwmExtendFrameIntoClientArea() will always fail if DWM composition is disabled. // No need to try in this case. if (!isDwmCompositionEnabled()) { return; } - Q_ASSERT(winId); - if (!winId) { - return; - } static const auto pDwmExtendFrameIntoClientArea = reinterpret_cast( QSystemLibrary::resolve(QStringLiteral("dwmapi"), "DwmExtendFrameIntoClientArea")); if (!pDwmExtendFrameIntoClientArea) { return; } + const MARGINS margins = [reset, winId]() -> MARGINS { + if (reset) { + return {0, 0, 0, 0}; + } + if (isWin10OrGreater()) { + return {0, static_cast(getTitleBarHeight(winId, true)), 0, 0}; + } else { + return {1, 1, 1, 1}; + } + }(); const auto hwnd = reinterpret_cast(winId); - const MARGINS margins = reset ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1}; const HRESULT hr = pDwmExtendFrameIntoClientArea(hwnd, &margins); if (FAILED(hr)) { qWarning() << __getSystemErrorMessage(QStringLiteral("DwmExtendFrameIntoClientArea"), hr); @@ -230,10 +239,16 @@ void Utilities::updateInternalWindowFrameMargins(QWindow *window, const bool ena return; } const WId winId = window->winId(); - const int resizeBorderThicknessH = enable ? getResizeBorderThickness(winId, true, true) : 0; - const int resizeBorderThicknessV = enable ? getResizeBorderThickness(winId, false, true) : 0; - const int titleBarHeight = enable ? getTitleBarHeight(winId, true) : 0; - const QMargins margins = {-resizeBorderThicknessH, -titleBarHeight, -resizeBorderThicknessH, -resizeBorderThicknessV}; + const QMargins margins = [winId]() -> QMargins { + const int titleBarHeight = getTitleBarHeight(winId, true); + if (isWin10OrGreater()) { + return {0, -titleBarHeight, 0, 0}; + } else { + const int frameSizeX = getResizeBorderThickness(winId, true, true); + const int frameSizeY = getResizeBorderThickness(winId, false, true); + return {-frameSizeX, -titleBarHeight, -frameSizeX, -frameSizeY}; + } + }(); const QVariant marginsVar = QVariant::fromValue(margins); window->setProperty("_q_windowsCustomMargins", marginsVar); #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) @@ -541,21 +556,6 @@ bool Utilities::isHighContrastModeEnabled() return (hc.dwFlags & HCF_HIGHCONTRASTON); } -QColor Utilities::getWallpaperBackgroundColor() -{ - return {}; -} - -int Utilities::getWallpaperAspectStyle() -{ - return 0; -} - -QString Utilities::getWallpaperFilePath() -{ - return {}; -} - quint32 Utilities::getPrimaryScreenDpi(const bool horizontal) { static const auto pGetDpiForMonitor = @@ -705,7 +705,7 @@ QColor Utilities::getFrameBorderColor(const bool active) } } -void Utilities::updateWindowFrameColor(const WId winId, const bool dark) +void Utilities::updateWindowFrameBorderColor(const WId winId, const bool dark) { Q_ASSERT(winId); if (!winId) { @@ -742,4 +742,30 @@ void Utilities::updateWindowFrameColor(const WId winId, const bool dark) } } +void Utilities::fixupQtInternals(const WId winId) +{ + Q_ASSERT(winId); + if (!winId) { + return; + } + const auto hwnd = reinterpret_cast(winId); + SetLastError(ERROR_SUCCESS); + const auto oldClassStyle = static_cast(GetClassLongPtrW(hwnd, GCL_STYLE)); + if (oldClassStyle == 0) { + qWarning() << getSystemErrorMessage(QStringLiteral("GetClassLongPtrW")); + return; + } + const DWORD newClassStyle = (oldClassStyle | CS_HREDRAW | CS_VREDRAW); + SetLastError(ERROR_SUCCESS); + if (SetClassLongPtrW(hwnd, GCL_STYLE, static_cast(newClassStyle)) == 0) { + qWarning() << getSystemErrorMessage(QStringLiteral("SetClassLongPtrW")); + return; + } + const DWORD newWindowStyle = (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + SetLastError(ERROR_SUCCESS); + if (SetWindowLongPtrW(hwnd, GWL_STYLE, static_cast(newWindowStyle)) == 0) { + qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW")); + } +} + FRAMELESSHELPER_END_NAMESPACE