diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index 8daa425..6e913e6 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -25,6 +25,7 @@ #include "mainwindow.h" #include #include "../../framelesswindowsmanager.h" +#include "../../utilities.h" FRAMELESSHELPER_USE_NAMESPACE @@ -86,11 +87,11 @@ void MainWindow::showEvent(QShowEvent *event) const auto win = windowHandle(); if (win) { FramelessWindowsManager::addWindow(win); - FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->iconButton, true); - FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->minimizeButton, true); - FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->maximizeButton, true); - FramelessWindowsManager::setHitTestVisibleInChrome(win, titleBarWidget->closeButton, true); - FramelessWindowsManager::setHitTestVisibleInChrome(win, appMainWindow->menubar, true); + FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->iconButton, true); + FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->minimizeButton, true); + FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->maximizeButton, true); + FramelessWindowsManager::setHitTestVisible(win, titleBarWidget->closeButton, true); + FramelessWindowsManager::setHitTestVisible(win, appMainWindow->menubar, true); setContentsMargins(1, 1, 1, 1); inited = true; } @@ -136,7 +137,12 @@ void MainWindow::paintEvent(QPaintEvent *event) {0, h, 0, 0} }; painter.save(); - painter.setPen({isActiveWindow() ? Qt::black : Qt::darkGray, 1}); + const ColorizationArea area = Utilities::getColorizationArea(); + const bool colorizedBorder = ((area == ColorizationArea::TitleBar_WindowBorder) + || (area == ColorizationArea::All)); + const QColor borderColor = (isActiveWindow() ? (colorizedBorder ? Utilities::getColorizationColor() : Qt::black) : Qt::darkGray); + const auto borderThickness = static_cast(Utilities::getWindowVisibleFrameBorderThickness(winId())); + painter.setPen({borderColor, qMax(borderThickness, devicePixelRatioF())}); painter.drawLines(lines); painter.restore(); } diff --git a/examples/quick/qml/main.qml b/examples/quick/qml/main.qml index 5483340..5c413e5 100644 --- a/examples/quick/qml/main.qml +++ b/examples/quick/qml/main.qml @@ -36,9 +36,7 @@ Window { title: qsTr("Hello, World!") color: "#f0f0f0" - property real _flh_margin: ((window.visibility === Window.Maximized) - || (window.visibility - === Window.FullScreen)) ? 0.0 : (1.0 / Screen.devicePixelRatio) + property real _flh_margin: ((window.visibility === Window.Maximized) | (window.visibility === Window.FullScreen)) ? 0.0 : (1.0 / Screen.devicePixelRatio) property var _win_prev_state: null FramelessHelper { @@ -83,14 +81,12 @@ Window { MinimizeButton { id: minimizeButton onClicked: window.showMinimized() - Component.onCompleted: framelessHelper.setHitTestVisibleInChrome( - minimizeButton, true) + Component.onCompleted: framelessHelper.setHitTestVisible(minimizeButton, true) } MaximizeButton { id: maximizeButton - maximized: ((window.visibility === Window.Maximized) - || (window.visibility === Window.FullScreen)) + maximized: ((window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen)) onClicked: { if (maximized) { window.showNormal() @@ -98,15 +94,13 @@ Window { window.showMaximized() } } - Component.onCompleted: framelessHelper.setHitTestVisibleInChrome( - maximizeButton, true) + Component.onCompleted: framelessHelper.setHitTestVisible(maximizeButton, true) } CloseButton { id: closeButton onClicked: window.close() - Component.onCompleted: framelessHelper.setHitTestVisibleInChrome( - closeButton, true) + Component.onCompleted: framelessHelper.setHitTestVisible(closeButton, true) } } } diff --git a/examples/widget/widget.cpp b/examples/widget/widget.cpp index 4bca9da..b845f9a 100644 --- a/examples/widget/widget.cpp +++ b/examples/widget/widget.cpp @@ -99,9 +99,9 @@ void Widget::showEvent(QShowEvent *event) return; } FramelessWindowsManager::addWindow(win); - FramelessWindowsManager::setHitTestVisibleInChrome(win, m_minimizeButton, true); - FramelessWindowsManager::setHitTestVisibleInChrome(win, m_maximizeButton, true); - FramelessWindowsManager::setHitTestVisibleInChrome(win, m_closeButton, true); + FramelessWindowsManager::setHitTestVisible(win, m_minimizeButton, true); + FramelessWindowsManager::setHitTestVisible(win, m_maximizeButton, true); + FramelessWindowsManager::setHitTestVisible(win, m_closeButton, true); const int margin = Utilities::getWindowVisibleFrameBorderThickness(winId()); setContentsMargins(margin, margin, margin, margin); } diff --git a/framelesshelper.cpp b/framelesshelper.cpp index dca059b..f6f162b 100644 --- a/framelesshelper.cpp +++ b/framelesshelper.cpp @@ -114,7 +114,7 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event) } return Qt::Edges{}; } (); - const bool hitTestVisible = Utilities::isHitTestVisibleInChrome(window); + const bool hitTestVisible = Utilities::isHitTestVisible(window); bool isInTitlebarArea = false; if ((window->windowState() == Qt::WindowMaximized) || (window->windowState() == Qt::WindowFullScreen)) { diff --git a/framelesshelper_global.h b/framelesshelper_global.h index aa5f7c1..64bceb0 100644 --- a/framelesshelper_global.h +++ b/framelesshelper_global.h @@ -86,7 +86,11 @@ FRAMELESSHELPER_BEGIN_NAMESPACE +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) Q_NAMESPACE_EXPORT(FRAMELESSHELPER_API) +#else +Q_NAMESPACE +#endif namespace Constants { @@ -95,10 +99,7 @@ namespace Constants [[maybe_unused]] constexpr char kResizeBorderThicknessFlag[] = "_FRAMELESSHELPER_RESIZE_BORDER_THICKNESS"; [[maybe_unused]] constexpr char kCaptionHeightFlag[] = "_FRAMELESSHELPER_CAPTION_HEIGHT"; [[maybe_unused]] constexpr char kTitleBarHeightFlag[] = "_FRAMELESSHELPER_TITLE_BAR_HEIGHT"; -[[maybe_unused]] constexpr char kHitTestVisibleInChromeFlag[] = "_FRAMELESSHELPER_HIT_TEST_VISIBLE_IN_CHROME"; -[[maybe_unused]] constexpr char kUseNativeTitleBarFlag[] = "_FRAMELESSHELPER_USE_NATIVE_TITLE_BAR"; -[[maybe_unused]] constexpr char kPreserveNativeFrameFlag[] = "_FRAMELESSHELPER_PRESERVE_NATIVE_WINDOW_FRAME"; -[[maybe_unused]] constexpr char kForcePreserveNativeFrameFlag[] = "_FRAMELESSHELPER_FORCE_PRESERVE_NATIVE_WINDOW_FRAME"; +[[maybe_unused]] constexpr char kHitTestVisibleFlag[] = "_FRAMELESSHELPER_HIT_TEST_VISIBLE"; [[maybe_unused]] constexpr char kWindowFixedSizeFlag[] = "_FRAMELESSHELPER_WINDOW_FIXED_SIZE"; } diff --git a/framelesshelper_win32.cpp b/framelesshelper_win32.cpp index 3920718..0e9aec1 100644 --- a/framelesshelper_win32.cpp +++ b/framelesshelper_win32.cpp @@ -32,28 +32,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE -[[nodiscard]] static inline bool shouldHaveWindowFrame() -{ - if (Utilities::shouldUseNativeTitleBar()) { - // We have to use the original window frame unconditionally if we - // want to use the native title bar. - return true; - } - const bool should = qEnvironmentVariableIsSet(Constants::kPreserveNativeFrameFlag); - const bool force = qEnvironmentVariableIsSet(Constants::kForcePreserveNativeFrameFlag); - if (should || force) { - if (force) { - return true; - } - if (should) { - // If you preserve the window frame on Win7~8.1, - // the window will have a terrible appearance. - return Utilities::isWin10OrGreater(); - } - } - return false; -} - struct FramelessHelperWinData { [[nodiscard]] bool create() { @@ -247,29 +225,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // preserve the four window borders. So we just remove the whole // window frame, otherwise the code will become much more complex. - if (Utilities::shouldUseNativeTitleBar()) { - break; - } - - if (msg->wParam == FALSE) { + if (static_cast(msg->wParam) == FALSE) { *result = 0; return true; } const auto clientRect = &(reinterpret_cast(msg->lParam)->rgrc[0]); - if (shouldHaveWindowFrame()) { - // 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, TRUE, 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; - } bool nonClientAreaExists = false; // 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 @@ -283,11 +243,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // a window when it's maximized unless you restore it). const int resizeBorderThickness = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true); clientRect->top += resizeBorderThickness; - if (!shouldHaveWindowFrame()) { - clientRect->bottom -= resizeBorderThickness; - clientRect->left += resizeBorderThickness; - clientRect->right -= resizeBorderThickness; - } + clientRect->bottom -= resizeBorderThickness; + clientRect->left += resizeBorderThickness; + clientRect->right -= resizeBorderThickness; nonClientAreaExists = true; } // Attempt to detect if there's an autohide taskbar, and if @@ -427,17 +385,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // area. case WM_NCUAHDRAWCAPTION: case WM_NCUAHDRAWFRAME: { - if (shouldHaveWindowFrame()) { - break; - } else { - *result = 0; - return true; - } + *result = 0; + return true; } case WM_NCPAINT: { // 边框阴影处于非客户区的范围,因此如果直接阻止非客户区的绘制,会导致边框阴影丢失 - if (!Utilities::isDwmCompositionAvailable() && !shouldHaveWindowFrame()) { + if (!Utilities::isDwmCompositionAvailable()) { // 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. @@ -448,26 +402,22 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me } } case WM_NCACTIVATE: { - if (shouldHaveWindowFrame()) { - break; + if (Utilities::isDwmCompositionAvailable()) { + // 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" otherwise the window won't respond + // to the window active state change. + *result = DefWindowProcW(msg->hwnd, WM_NCACTIVATE, msg->wParam, -1); } else { - if (Utilities::isDwmCompositionAvailable()) { - // 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" otherwise the window won't respond - // to the window active state change. - *result = DefWindowProcW(msg->hwnd, WM_NCACTIVATE, msg->wParam, -1); + if (static_cast(msg->wParam) == FALSE) { + *result = TRUE; } else { - if (msg->wParam == FALSE) { - *result = TRUE; - } else { - *result = FALSE; - } + *result = FALSE; } - return true; } + return true; } case WM_NCHITTEST: { // 原生Win32窗口只有顶边是在窗口内部resize的,其余三边都是在窗口 @@ -535,10 +485,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // another branch, if you are interested in it, you can give it a // try. - if (Utilities::shouldUseNativeTitleBar()) { - break; - } - POINT winLocalMouse = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)}; if (ScreenToClient(msg->hwnd, &winLocalMouse) == FALSE) { qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("ScreenToClient")); @@ -557,99 +503,76 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me if (IsMaximized(msg->hwnd) || (window->windowState() == Qt::WindowFullScreen)) { isTitleBar = (localMouse.y() >= 0) && (localMouse.y() <= titleBarHeight) && (localMouse.x() >= 0) && (localMouse.x() <= windowWidth) - && !Utilities::isHitTestVisibleInChrome(window); + && !Utilities::isHitTestVisible(window); } if (window->windowState() == Qt::WindowNoState) { isTitleBar = (localMouse.y() > resizeBorderThickness) && (localMouse.y() <= titleBarHeight) && (localMouse.x() > resizeBorderThickness) && (localMouse.x() < (windowWidth - resizeBorderThickness)) - && !Utilities::isHitTestVisibleInChrome(window); + && !Utilities::isHitTestVisible(window); } const bool isTop = localMouse.y() <= resizeBorderThickness; - if (shouldHaveWindowFrame()) { - // 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; - } - // 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 (!IsMaximized(msg->hwnd) && isTop) { - *result = HTTOP; - return true; - } - if (isTitleBar) { - *result = HTCAPTION; - return true; - } - *result = HTCLIENT; - return true; - } else { - const LRESULT hitTestResult = [clientRect, msg, isTitleBar, &localMouse, resizeBorderThickness, windowWidth, isTop, window]{ - if (IsMaximized(msg->hwnd)) { - if (isTitleBar) { - return HTCAPTION; - } - return HTCLIENT; - } - const LONG windowHeight = clientRect.bottom; - const bool isBottom = (localMouse.y() >= (windowHeight - resizeBorderThickness)); - // 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; - }; - if (isTop) { - if (isLeft) { - return getBorderValue(HTTOPLEFT); - } - if (isRight) { - return getBorderValue(HTTOPRIGHT); - } - return getBorderValue(HTTOP); - } - if (isBottom) { - if (isLeft) { - return getBorderValue(HTBOTTOMLEFT); - } - if (isRight) { - return getBorderValue(HTBOTTOMRIGHT); - } - return getBorderValue(HTBOTTOM); - } - if (isLeft) { - return getBorderValue(HTLEFT); - } - if (isRight) { - return getBorderValue(HTRIGHT); - } + const LRESULT hitTestResult = [clientRect, msg, isTitleBar, &localMouse, resizeBorderThickness, windowWidth, isTop, window]{ + if (IsMaximized(msg->hwnd)) { if (isTitleBar) { return HTCAPTION; } return HTCLIENT; - }(); - *result = hitTestResult; - return true; - } + } + const LONG windowHeight = clientRect.bottom; + const bool isBottom = (localMouse.y() >= (windowHeight - resizeBorderThickness)); + // 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; + }; + if (isTop) { + if (isLeft) { + return getBorderValue(HTTOPLEFT); + } + if (isRight) { + return getBorderValue(HTTOPRIGHT); + } + return getBorderValue(HTTOP); + } + if (isBottom) { + if (isLeft) { + return getBorderValue(HTBOTTOMLEFT); + } + if (isRight) { + return getBorderValue(HTBOTTOMRIGHT); + } + return getBorderValue(HTBOTTOM); + } + if (isLeft) { + return getBorderValue(HTLEFT); + } + if (isRight) { + return getBorderValue(HTRIGHT); + } + if (isTitleBar) { + return HTCAPTION; + } + return HTCLIENT; + }(); + *result = hitTestResult; + return true; } case WM_SETICON: case WM_SETTEXT: { - if (Utilities::shouldUseNativeTitleBar()) { - break; - } - // 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; @@ -657,6 +580,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me 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; @@ -665,15 +589,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me *result = ret; return true; } - case WM_SIZE: { - const bool normal = (msg->wParam == SIZE_RESTORED); - const bool max = (msg->wParam == SIZE_MAXIMIZED); - const bool full = (window->windowState() == Qt::WindowFullScreen); - if (normal || max || full) { - Utilities::updateFrameMargins(reinterpret_cast(msg->hwnd), (max || full)); - Utilities::updateQtFrameMargins(const_cast(window), true); - } - } break; default: break; } diff --git a/framelesshelper_windows.h b/framelesshelper_windows.h index d9eb80b..b12737c 100644 --- a/framelesshelper_windows.h +++ b/framelesshelper_windows.h @@ -90,11 +90,11 @@ #endif #ifndef GET_X_LPARAM -#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) +#define GET_X_LPARAM(lp) (static_cast(static_cast(LOWORD(lp)))) #endif #ifndef GET_Y_LPARAM -#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) +#define GET_Y_LPARAM(lp) (static_cast(static_cast(HIWORD(lp)))) #endif #ifndef IsMinimized @@ -105,13 +105,13 @@ #define IsMaximized(window) (IsZoomed(window) != FALSE) #endif -[[maybe_unused]] constexpr int kAutoHideTaskbarThickness = 2; // The thickness of an auto-hide taskbar in pixels +[[maybe_unused]] constexpr UINT kAutoHideTaskbarThickness = 2; // The thickness of an auto-hide taskbar in pixels [[maybe_unused]] constexpr char kDwmRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)"; [[maybe_unused]] constexpr char kPersonalizeRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"; -[[maybe_unused]] constexpr int kDefaultResizeBorderThicknessClassic = 4; -[[maybe_unused]] constexpr int kDefaultResizeBorderThicknessAero = 8; -[[maybe_unused]] constexpr int kDefaultCaptionHeight = 23; +[[maybe_unused]] constexpr UINT kDefaultResizeBorderThicknessClassic = 4; +[[maybe_unused]] constexpr UINT kDefaultResizeBorderThicknessAero = 8; +[[maybe_unused]] constexpr UINT kDefaultCaptionHeight = 23; -[[maybe_unused]] constexpr WORD _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37; +[[maybe_unused]] constexpr DWORD _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37; diff --git a/framelessquickhelper.cpp b/framelessquickhelper.cpp index 4022111..3a827a3 100644 --- a/framelessquickhelper.cpp +++ b/framelessquickhelper.cpp @@ -80,13 +80,13 @@ bool FramelessQuickHelper::isWindowFrameless() const return FramelessWindowsManager::isWindowFrameless(window()); } -void FramelessQuickHelper::setHitTestVisibleInChrome(QQuickItem *item, const bool visible) +void FramelessQuickHelper::setHitTestVisible(QQuickItem *item, const bool visible) { Q_ASSERT(item); if (!item) { return; } - FramelessWindowsManager::setHitTestVisibleInChrome(window(), item, visible); + FramelessWindowsManager::setHitTestVisible(window(), item, visible); } FRAMELESSHELPER_END_NAMESPACE diff --git a/framelessquickhelper.h b/framelessquickhelper.h index 6ff6be4..105077e 100644 --- a/framelessquickhelper.h +++ b/framelessquickhelper.h @@ -57,7 +57,7 @@ public Q_SLOTS: void removeWindowFrame(); void bringBackWindowFrame(); Q_NODISCARD bool isWindowFrameless() const; - void setHitTestVisibleInChrome(QQuickItem *item, const bool visible); + void setHitTestVisible(QQuickItem *item, const bool visible); Q_SIGNALS: void resizeBorderThicknessChanged(qreal); diff --git a/framelesswindowsmanager.cpp b/framelesswindowsmanager.cpp index 093e8f7..3b98aec 100644 --- a/framelesswindowsmanager.cpp +++ b/framelesswindowsmanager.cpp @@ -62,7 +62,7 @@ void FramelessWindowsManager::addWindow(QWindow *window) #endif } -void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject *object, const bool value) +void FramelessWindowsManager::setHitTestVisible(QWindow *window, QObject *object, const bool value) { Q_ASSERT(window); Q_ASSERT(object); @@ -73,7 +73,7 @@ void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject qWarning() << object << "is not a QWidget or QQuickItem."; return; } - auto objList = qvariant_cast(window->property(Constants::kHitTestVisibleInChromeFlag)); + auto objList = qvariant_cast(window->property(Constants::kHitTestVisibleFlag)); if (value) { if (objList.isEmpty() || !objList.contains(object)) { objList.append(object); @@ -83,7 +83,7 @@ void FramelessWindowsManager::setHitTestVisibleInChrome(QWindow *window, QObject objList.removeAll(object); } } - window->setProperty(Constants::kHitTestVisibleInChromeFlag, QVariant::fromValue(objList)); + window->setProperty(Constants::kHitTestVisibleFlag, QVariant::fromValue(objList)); } int FramelessWindowsManager::getResizeBorderThickness(const QWindow *window) diff --git a/framelesswindowsmanager.h b/framelesswindowsmanager.h index 7e41995..9541335 100644 --- a/framelesswindowsmanager.h +++ b/framelesswindowsmanager.h @@ -39,7 +39,7 @@ namespace FramelessWindowsManager FRAMELESSHELPER_API void addWindow(QWindow *window); FRAMELESSHELPER_API void removeWindow(QWindow *window); [[nodiscard]] FRAMELESSHELPER_API bool isWindowFrameless(const QWindow *window); -FRAMELESSHELPER_API void setHitTestVisibleInChrome(QWindow *window, QObject *object, const bool value = true); +FRAMELESSHELPER_API void setHitTestVisible(QWindow *window, QObject *object, const bool value = true); [[nodiscard]] FRAMELESSHELPER_API int getResizeBorderThickness(const QWindow *window); FRAMELESSHELPER_API void setResizeBorderThickness(QWindow *window, const int value); [[nodiscard]] FRAMELESSHELPER_API int getTitleBarHeight(const QWindow *window); diff --git a/utilities.cpp b/utilities.cpp index d67ed3e..bf9c530 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -49,11 +49,6 @@ QWindow *Utilities::findWindow(const WId winId) return nullptr; } -bool Utilities::shouldUseNativeTitleBar() -{ - return qEnvironmentVariableIsSet(Constants::kUseNativeTitleBarFlag); -} - bool Utilities::isWindowFixedSize(const QWindow *window) { Q_ASSERT(window); @@ -73,13 +68,13 @@ bool Utilities::isWindowFixedSize(const QWindow *window) return false; } -bool Utilities::isHitTestVisibleInChrome(const QWindow *window) +bool Utilities::isHitTestVisible(const QWindow *window) { Q_ASSERT(window); if (!window) { return false; } - const auto objs = qvariant_cast(window->property(Constants::kHitTestVisibleInChromeFlag)); + const auto objs = qvariant_cast(window->property(Constants::kHitTestVisibleFlag)); if (objs.isEmpty()) { return false; } diff --git a/utilities.h b/utilities.h index f7be5c2..c894206 100644 --- a/utilities.h +++ b/utilities.h @@ -34,9 +34,8 @@ namespace Utilities [[nodiscard]] FRAMELESSHELPER_API int getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue = false); [[nodiscard]] FRAMELESSHELPER_API QWindow *findWindow(const WId winId); -[[nodiscard]] FRAMELESSHELPER_API bool shouldUseNativeTitleBar(); [[nodiscard]] FRAMELESSHELPER_API bool isWindowFixedSize(const QWindow *window); -[[nodiscard]] FRAMELESSHELPER_API bool isHitTestVisibleInChrome(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_API bool isHitTestVisible(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_API QPointF mapOriginPointToWindow(const QObject *object); [[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor(); [[nodiscard]] FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const WId winId); @@ -54,7 +53,6 @@ namespace Utilities FRAMELESSHELPER_API void triggerFrameChange(const WId winId); FRAMELESSHELPER_API void updateFrameMargins(const WId winId, const bool reset); FRAMELESSHELPER_API void updateQtFrameMargins(QWindow *window, const bool enable); -[[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function, const HRESULT hr); [[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function); #endif diff --git a/utilities_win32.cpp b/utilities_win32.cpp index e79a0cf..2886970 100644 --- a/utilities_win32.cpp +++ b/utilities_win32.cpp @@ -69,6 +69,39 @@ FRAMELESSHELPER_BEGIN_NAMESPACE return result; } +[[nodiscard]] static inline QString __getSystemErrorMessage(const QString &function, const DWORD code) +{ + Q_ASSERT(!function.isEmpty()); + if (function.isEmpty()) { + return {}; + } + if (code == ERROR_SUCCESS) { + return {}; + } + LPWSTR buf = nullptr; + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&buf), 0, nullptr) == 0) { + return {}; + } + const QString message = QStringLiteral("Function %1() failed with error code %2: %3.") + .arg(function, QString::number(code), QString::fromWCharArray(buf)); + LocalFree(buf); + return message; +} + +[[nodiscard]] static inline QString __getSystemErrorMessage(const QString &function, const HRESULT hr) +{ + Q_ASSERT(!function.isEmpty()); + if (function.isEmpty()) { + return {}; + } + if (SUCCEEDED(hr)) { + return {}; + } + const DWORD dwError = HRESULT_CODE(hr); + return __getSystemErrorMessage(function, dwError); +} + bool Utilities::isWin8OrGreater() { #if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) @@ -110,7 +143,7 @@ bool Utilities::isDwmCompositionAvailable() if (SUCCEEDED(hr)) { return (enabled != FALSE); } else { - qWarning() << getSystemErrorMessage(QStringLiteral("DwmIsCompositionEnabled"), hr); + qWarning() << __getSystemErrorMessage(QStringLiteral("DwmIsCompositionEnabled"), hr); const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat); bool ok = false; const DWORD value = registry.value(QStringLiteral("Composition"), 0).toUInt(&ok); @@ -219,7 +252,7 @@ void Utilities::updateFrameMargins(const WId winId, const bool reset) const MARGINS margins = reset ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1}; const HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins); if (FAILED(hr)) { - qWarning() << getSystemErrorMessage(QStringLiteral("DwmExtendFrameIntoClientArea"), hr); + qWarning() << __getSystemErrorMessage(QStringLiteral("DwmExtendFrameIntoClientArea"), hr); } } @@ -255,53 +288,29 @@ void Utilities::updateQtFrameMargins(QWindow *window, const bool enable) #endif } -QString Utilities::getSystemErrorMessage(const QString &function, const HRESULT hr) -{ - Q_ASSERT(!function.isEmpty()); - if (function.isEmpty()) { - return {}; - } - if (SUCCEEDED(hr)) { - return QStringLiteral("Operation succeeded."); - } - const DWORD dwError = HRESULT_CODE(hr); - LPWSTR buf = nullptr; - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, nullptr) == 0) { - return QStringLiteral("Failed to retrieve the error message from system."); - } - const QString message = QStringLiteral("%1 failed with error %2: %3.") - .arg(function, QString::number(dwError), QString::fromWCharArray(buf)); - LocalFree(buf); - return message; -} - QString Utilities::getSystemErrorMessage(const QString &function) { Q_ASSERT(!function.isEmpty()); if (function.isEmpty()) { return {}; } - const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); - if (SUCCEEDED(hr)) { - return QStringLiteral("Operation succeeded."); + const DWORD code = GetLastError(); + if (code == ERROR_SUCCESS) { + return {}; } - return getSystemErrorMessage(function, hr); + return __getSystemErrorMessage(function, code); } QColor Utilities::getColorizationColor() { - COLORREF color = RGB(0, 0, 0); + DWORD color = 0; BOOL opaque = FALSE; const HRESULT hr = DwmGetColorizationColor(&color, &opaque); if (FAILED(hr)) { - qWarning() << getSystemErrorMessage(QStringLiteral("DwmGetColorizationColor"), hr); + qWarning() << __getSystemErrorMessage(QStringLiteral("DwmGetColorizationColor"), hr); const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat); bool ok = false; color = registry.value(QStringLiteral("ColorizationColor"), 0).toUInt(&ok); - if (!ok || (color == 0)) { - color = RGB(128, 128, 128); // Dark gray - } } return QColor::fromRgba(color); }