From ece66727ccb30d8eb99fa620f5f260d43065cdfc Mon Sep 17 00:00:00 2001 From: ffiirree Date: Sat, 6 Apr 2024 15:23:26 +0800 Subject: [PATCH] fix(#47): remove top, bottom, and right border of frameless window on Windows 10 --- 3rdparty/probe | 2 +- src/widgets/framelesswindow.cpp | 70 ++++++++++++++----- src/widgets/framelesswindow.h | 2 +- .../platforms/window-effect-windows.cpp | 12 ++-- 4 files changed, 61 insertions(+), 25 deletions(-) diff --git a/3rdparty/probe b/3rdparty/probe index eec33c8..ae5d8c2 160000 --- a/3rdparty/probe +++ b/3rdparty/probe @@ -1 +1 @@ -Subproject commit eec33c8b56eb9f93de3925092245634c9a9d421c +Subproject commit ae5d8c266fa84e646f9ecf0f00398ac3f8a81cc7 diff --git a/src/widgets/framelesswindow.cpp b/src/widgets/framelesswindow.cpp index 12afe6a..6e2ea9f 100644 --- a/src/widgets/framelesswindow.cpp +++ b/src/widgets/framelesswindow.cpp @@ -12,12 +12,13 @@ #include #include #include +#include #include #endif // [microsoft/terminal](https://github.com/microsoft/terminal/blob/main/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp) FramelessWindow::FramelessWindow(QWidget *parent, const Qt::WindowFlags flags) - : QWidget(parent, Qt::Window | Qt::WindowCloseButtonHint | flags) + : QWidget(parent, Qt::WindowCloseButtonHint | flags) { #ifdef Q_OS_WIN setAttribute(Qt::WA_DontCreateNativeAncestors); @@ -25,10 +26,6 @@ FramelessWindow::FramelessWindow(QWidget *parent, const Qt::WindowFlags flags) const auto hwnd = reinterpret_cast(winId()); - // shadow - constexpr DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED; - ::DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &ncrp, sizeof(DWMNCRENDERINGPOLICY)); - constexpr MARGINS margins = { -1, -1, -1, -1 }; ::DwmExtendFrameIntoClientArea(hwnd, &margins); @@ -214,13 +211,15 @@ bool FramelessWindow::nativeEvent(const QByteArray& eventType, void *message, Q_ const LONG original_top = rect->top; // apply the default frame for standard window frame (the resizable frame border and the frame // shadow) including the left, bottom and right edges. - if (const LRESULT res = ::DefWindowProcW(hwnd, WM_NCCALCSIZE, wmsg->wParam, wmsg->lParam); - (res != HTERROR) && (res != HTNOWHERE)) { - *result = static_cast(res); - return true; + if (probe::system::version() >= probe::WIN_11) { + if (const LRESULT res = ::DefWindowProcW(hwnd, WM_NCCALCSIZE, wmsg->wParam, wmsg->lParam); + (res != HTERROR) && (res != HTNOWHERE)) { + *result = static_cast(res); + return true; + } } // re-apply the original top for removing the top frame entirely - rect->top = original_top; + rect->top = original_top; // const auto monitor = MonitorInfoFromWindow(hwnd); @@ -230,6 +229,11 @@ bool FramelessWindow::nativeEvent(const QByteArray& eventType, void *message, Q_ // top frame if (maximized && !fullscreen) { rect->top += ResizeHandleHeight(hwnd); + if (probe::system::version() < probe::WIN_11) { + rect->left += ResizeHandleHeight(hwnd); + rect->right -= ResizeHandleHeight(hwnd); + rect->bottom -= ResizeHandleHeight(hwnd); + } } // autohide taskbar @@ -265,12 +269,44 @@ bool FramelessWindow::nativeEvent(const QByteArray& eventType, void *message, Q_ } case WM_NCHITTEST: { - LRESULT res = ::DefWindowProcW(hwnd, WM_NCHITTEST, 0, wmsg->lParam); - if (res == HTCLIENT) { + LRESULT res = HTCLIENT; + if (probe::system::version() >= probe::WIN_11) { + res = ::DefWindowProcW(hwnd, WM_NCHITTEST, 0, wmsg->lParam); + if (res == HTCLIENT) { + RECT rect{}; + if (::GetWindowRect(hwnd, &rect) && + GET_Y_LPARAM(wmsg->lParam) < rect.top + ResizeHandleHeight(hwnd)) { + res = HTTOP; + } + } + } + else { + const auto x = GET_X_LPARAM(wmsg->lParam), y = GET_Y_LPARAM(wmsg->lParam); + const auto thickness = ResizeHandleHeight(hwnd); + RECT rect{}; - if (::GetWindowRect(hwnd, &rect) && - GET_Y_LPARAM(wmsg->lParam) < rect.top + ResizeHandleHeight(hwnd)) { - res = HTTOP; + if (::GetWindowRect(hwnd, &rect)) { + const auto le = x > rect.left && x < (rect.left + thickness); + const auto re = x > (rect.right - thickness) && x < rect.right; + const auto te = y > rect.top && y < (rect.top + thickness); + const auto be = y > (rect.bottom - thickness) && y < rect.bottom; + + if (le && te) + res = HTTOPLEFT; + else if (le && be) + res = HTBOTTOMLEFT; + else if (re && te) + res = HTTOPRIGHT; + else if (re && be) + res = HTBOTTOMRIGHT; + else if (re) + res = HTRIGHT; + else if (te) + res = HTTOP; + else if (le) + res = HTLEFT; + else if (be) + res = HTBOTTOM; } } @@ -291,7 +327,8 @@ bool FramelessWindow::nativeEvent(const QByteArray& eventType, void *message, Q_ } if (!fullscreen && res == HTCLIENT && titlebar_ && titlebar_->isVisible()) { - if (const auto pos = mapFromGlobal(QPoint{ GET_X_LPARAM(wmsg->lParam), GET_Y_LPARAM(wmsg->lParam) }); + if (const auto pos = + mapFromGlobal(QPoint{ GET_X_LPARAM(wmsg->lParam), GET_Y_LPARAM(wmsg->lParam) }); titlebar_->geometry().contains(pos) && !titlebar_->isInSystemButtons(pos)) { *result = HTCAPTION; return true; @@ -307,5 +344,6 @@ bool FramelessWindow::nativeEvent(const QByteArray& eventType, void *message, Q_ return QWidget::nativeEvent(eventType, message, result); } + #endif diff --git a/src/widgets/framelesswindow.h b/src/widgets/framelesswindow.h index a694b40..ab5d775 100644 --- a/src/widgets/framelesswindow.h +++ b/src/widgets/framelesswindow.h @@ -20,7 +20,7 @@ class FramelessWindow : public QWidget [[nodiscard]] bool isSizeFixed() const; - TitleBar * titlebar(); + TitleBar *titlebar(); public slots: void toggleTransparentInput(); diff --git a/src/widgets/platforms/window-effect-windows.cpp b/src/widgets/platforms/window-effect-windows.cpp index 08e0624..fe38077 100644 --- a/src/widgets/platforms/window-effect-windows.cpp +++ b/src/widgets/platforms/window-effect-windows.cpp @@ -5,7 +5,9 @@ #include #include #include -#include +#include + +#define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19 namespace windows::dwm { @@ -111,14 +113,10 @@ namespace windows::dwm &mode, sizeof(mode)); } + // https://github.com/ysc3839/win32-darkmode/blob/master/win32-darkmode/DarkMode.h HRESULT update_theme(HWND hwnd, BOOL dark) { - const auto SetWindowCompositionAttribute = - static_cast(probe::library::address_of( - probe::library::load("user32.dll"), "SetWindowCompositionAttribute")); - - WINDOWCOMPOSITIONATTRIBDATA wcad{ WCA_USEDARKMODECOLORS, &dark, sizeof(dark) }; - SetWindowCompositionAttribute(hwnd, &wcad); + ::DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, &dark, sizeof(dark)); return ::DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark, sizeof(dark)); }