diff --git a/CMakeLists.txt b/CMakeLists.txt index 0006ece..4d0a4fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,14 @@ if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug") AND NOT DEFINED CMAKE_INTERPROCEDURAL set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) endif() +if(NOT DEFINED CMAKE_DEBUG_POSTFIX) + if(WIN32) + set(CMAKE_DEBUG_POSTFIX d) + else() + set(CMAKE_DEBUG_POSTFIX _debug) + endif() +endif() + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/examples/mainwindow/MainWindow.ui b/examples/mainwindow/MainWindow.ui index 4e54cdb..0dc3e7e 100644 --- a/examples/mainwindow/MainWindow.ui +++ b/examples/mainwindow/MainWindow.ui @@ -6,8 +6,8 @@ 0 0 - 518 - 368 + 800 + 600 diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index 3727086..c55dd65 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -61,7 +61,7 @@ void MainWindow::changeEvent(QEvent *event) bool shouldUpdate = false; if (event->type() == QEvent::WindowStateChange) { #ifdef Q_OS_WINDOWS - if (Utilities::isWin10OrGreater()) { + if (Utilities::isWindowFrameBorderVisible()) { if (isMaximized() || isFullScreen()) { setContentsMargins(0, 0, 0, 0); } else if (!isMinimized()) { @@ -91,7 +91,7 @@ void MainWindow::initFramelessHelperOnce() void MainWindow::resetContentsMargins() { #ifdef Q_OS_WINDOWS - if (Utilities::isWin10OrGreater()) { + if (Utilities::isWindowFrameBorderVisible()) { setContentsMargins(0, 1, 0, 0); } #endif @@ -101,7 +101,7 @@ void MainWindow::paintEvent(QPaintEvent *event) { QMainWindow::paintEvent(event); #ifdef Q_OS_WINDOWS - if ((windowState() == Qt::WindowNoState) && Utilities::isWin10OrGreater() && !Utilities::isWin11OrGreater()) { + if ((windowState() == Qt::WindowNoState) && Utilities::isWindowFrameBorderVisible() && !Utilities::isWin11OrGreater()) { QPainter painter(this); painter.save(); QPen pen = {}; diff --git a/examples/widget/widget.cpp b/examples/widget/widget.cpp index ff5462b..bc114a5 100644 --- a/examples/widget/widget.cpp +++ b/examples/widget/widget.cpp @@ -111,7 +111,7 @@ void Widget::changeEvent(QEvent *event) bool shouldUpdate = false; if (event->type() == QEvent::WindowStateChange) { #ifdef Q_OS_WINDOWS - if (Utilities::isWin10OrGreater()) { + if (Utilities::isWindowFrameBorderVisible()) { if (isMaximized() || isFullScreen()) { setContentsMargins(0, 0, 0, 0); } else if (!isMinimized()) { @@ -133,7 +133,7 @@ void Widget::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); #ifdef Q_OS_WINDOWS - if ((windowState() == Qt::WindowNoState) && Utilities::isWin10OrGreater() && !Utilities::isWin11OrGreater()) { + if ((windowState() == Qt::WindowNoState) && Utilities::isWindowFrameBorderVisible() && !Utilities::isWin11OrGreater()) { QPainter painter(this); painter.save(); QPen pen = {}; @@ -333,7 +333,7 @@ void Widget::updateSystemButtonIcons() void Widget::resetContentsMargins() { #ifdef Q_OS_WINDOWS - if (Utilities::isWin10OrGreater()) { + if (Utilities::isWindowFrameBorderVisible()) { setContentsMargins(0, 1, 0, 0); } #endif diff --git a/framelesshelper.cpp b/framelesshelper.cpp index 687049c..d023d89 100644 --- a/framelesshelper.cpp +++ b/framelesshelper.cpp @@ -23,12 +23,27 @@ */ #include "framelesshelper.h" +#include #include #include #include "utilities.h" FRAMELESSHELPER_BEGIN_NAMESPACE +struct UnixHelper +{ + QMutex mutex = {}; + QWindowList acceptableWindows = {}; + + explicit UnixHelper() = default; + ~UnixHelper() = default; + +private: + Q_DISABLE_COPY_MOVE(UnixHelper) +}; + +Q_GLOBAL_STATIC(UnixHelper, g_unixHelper) + FramelessHelper::FramelessHelper(QObject *parent) : QObject(parent) {} FramelessHelper::~FramelessHelper() = default; @@ -39,6 +54,13 @@ void FramelessHelper::addWindow(QWindow *window) if (!window) { return; } + g_unixHelper()->mutex.lock(); + if (g_unixHelper()->acceptableWindows.contains(window)) { + g_unixHelper()->mutex.unlock(); + return; + } + g_unixHelper()->acceptableWindows.append(window); + g_unixHelper()->mutex.unlock(); window->setFlags(window->flags() | Qt::FramelessWindowHint); window->installEventFilter(this); } @@ -49,6 +71,13 @@ void FramelessHelper::removeWindow(QWindow *window) if (!window) { return; } + g_unixHelper()->mutex.lock(); + if (!g_unixHelper()->acceptableWindows.contains(window)) { + g_unixHelper()->mutex.unlock(); + return; + } + g_unixHelper()->acceptableWindows.removeAll(window); + g_unixHelper()->mutex.unlock(); window->removeEventFilter(this); window->setFlags(window->flags() & ~Qt::FramelessWindowHint); } @@ -70,6 +99,12 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event) return false; } const auto window = qobject_cast(object); + g_unixHelper()->mutex.lock(); + if (!g_unixHelper()->acceptableWindows.contains(window)) { + g_unixHelper()->mutex.unlock(); + return false; + } + g_unixHelper()->mutex.unlock(); if (Utilities::isWindowFixedSize(window)) { return false; } diff --git a/framelesshelper_global.h b/framelesshelper_global.h index 91ddd99..8e41e7a 100644 --- a/framelesshelper_global.h +++ b/framelesshelper_global.h @@ -95,19 +95,9 @@ FRAMELESSHELPER_BEGIN_NAMESPACE Q_NAMESPACE_EXPORT(FRAMELESSHELPER_API) -[[maybe_unused]] static constexpr const int kDefaultResizeBorderThicknessClassic = 4; -[[maybe_unused]] static constexpr const int kDefaultResizeBorderThicknessAero = 8; +[[maybe_unused]] static constexpr const int kDefaultResizeBorderThickness = 8; [[maybe_unused]] static constexpr const int kDefaultCaptionHeight = 23; [[maybe_unused]] static constexpr const int kDefaultTitleBarHeight = 30; [[maybe_unused]] static constexpr const int kDefaultWindowFrameBorderThickness = 1; -enum class DwmColorizationArea : int -{ - None = 0, - StartMenu_TaskBar_ActionCenter = 1, - TitleBar_WindowBorder = 2, - All = 3 -}; -Q_ENUM_NS(DwmColorizationArea) - FRAMELESSHELPER_END_NAMESPACE diff --git a/framelesshelper_win32.cpp b/framelesshelper_win32.cpp index b47bea3..1fc1717 100644 --- a/framelesshelper_win32.cpp +++ b/framelesshelper_win32.cpp @@ -30,37 +30,37 @@ #include #include #include "framelesswindowsmanager.h" -#include "framelesswindowsmanager_p.h" #include "utilities.h" #include "framelesshelper_windows.h" FRAMELESSHELPER_BEGIN_NAMESPACE -struct FramelessHelperWinData +struct Win32Helper { QMutex mutex = {}; - QScopedPointer instance; - QList acceptableWinIds = {}; + QScopedPointer nativeEventFilter; + QWindowList acceptableWindows = {}; + QHash windowMapping = {}; QHash qtWindowProcs = {}; - explicit FramelessHelperWinData() = default; - ~FramelessHelperWinData() = default; + explicit Win32Helper() = default; + ~Win32Helper() = default; private: - Q_DISABLE_COPY_MOVE(FramelessHelperWinData) + Q_DISABLE_COPY_MOVE(Win32Helper) }; -Q_GLOBAL_STATIC(FramelessHelperWinData, g_helper) +Q_GLOBAL_STATIC(Win32Helper, g_win32Helper) [[nodiscard]] static inline LRESULT CALLBACK HookWindowProc (const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { - g_helper()->mutex.lock(); - if (!g_helper()->qtWindowProcs.contains(hWnd)) { - g_helper()->mutex.unlock(); + g_win32Helper()->mutex.lock(); + if (!g_win32Helper()->qtWindowProcs.contains(hWnd)) { + g_win32Helper()->mutex.unlock(); return DefWindowProcW(hWnd, uMsg, wParam, lParam); } - g_helper()->mutex.unlock(); + g_win32Helper()->mutex.unlock(); const auto winId = reinterpret_cast(hWnd); const auto getGlobalPosFromMouse = [lParam]() -> QPointF { return {qreal(GET_X_LPARAM(lParam)), qreal(GET_Y_LPARAM(lParam))}; @@ -75,7 +75,7 @@ Q_GLOBAL_STATIC(FramelessHelperWinData, g_helper) const int frameSizeX = Utilities::getResizeBorderThickness(winId, true, true); const int frameSizeY = Utilities::getResizeBorderThickness(winId, false, true); const int titleBarHeight = Utilities::getTitleBarHeight(winId, true); - const int horizontalOffset = ((maxOrFull || !Utilities::isWin10OrGreater()) ? 0 : frameSizeX); + const int horizontalOffset = ((maxOrFull || !Utilities::isWindowFrameBorderVisible()) ? 0 : frameSizeX); const int verticalOffset = (maxOrFull ? titleBarHeight : (titleBarHeight - frameSizeY)); return {qreal(rect.left + horizontalOffset), qreal(rect.top + verticalOffset)}; }; @@ -108,9 +108,9 @@ Q_GLOBAL_STATIC(FramelessHelperWinData, g_helper) // entering Qt's own handling logic. return 0; // Return 0 means we have handled this event. } - g_helper()->mutex.lock(); - const WNDPROC originalWindowProc = g_helper()->qtWindowProcs.value(hWnd); - g_helper()->mutex.unlock(); + g_win32Helper()->mutex.lock(); + const WNDPROC originalWindowProc = g_win32Helper()->qtWindowProcs.value(hWnd); + g_win32Helper()->mutex.unlock(); Q_ASSERT(originalWindowProc); if (originalWindowProc) { // Hand over to Qt's original window proc function for events we are not @@ -128,8 +128,8 @@ Q_GLOBAL_STATIC(FramelessHelperWinData, g_helper) return false; } const auto hwnd = reinterpret_cast(winId); - QMutexLocker locker(&g_helper()->mutex); - if (g_helper()->qtWindowProcs.contains(hwnd)) { + QMutexLocker locker(&g_win32Helper()->mutex); + if (g_win32Helper()->qtWindowProcs.contains(hwnd)) { return false; } SetLastError(ERROR_SUCCESS); @@ -144,7 +144,7 @@ Q_GLOBAL_STATIC(FramelessHelperWinData, g_helper) qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW")); return false; } - g_helper()->qtWindowProcs.insert(hwnd, originalWindowProc); + g_win32Helper()->qtWindowProcs.insert(hwnd, originalWindowProc); return true; } @@ -155,11 +155,11 @@ Q_GLOBAL_STATIC(FramelessHelperWinData, g_helper) return false; } const auto hwnd = reinterpret_cast(winId); - QMutexLocker locker(&g_helper()->mutex); - if (!g_helper()->qtWindowProcs.contains(hwnd)) { + QMutexLocker locker(&g_win32Helper()->mutex); + if (!g_win32Helper()->qtWindowProcs.contains(hwnd)) { return false; } - const WNDPROC originalWindowProc = g_helper()->qtWindowProcs.value(hwnd); + const WNDPROC originalWindowProc = g_win32Helper()->qtWindowProcs.value(hwnd); Q_ASSERT(originalWindowProc); if (!originalWindowProc) { return false; @@ -169,7 +169,7 @@ Q_GLOBAL_STATIC(FramelessHelperWinData, g_helper) qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW")); return false; } - g_helper()->qtWindowProcs.remove(hwnd); + g_win32Helper()->qtWindowProcs.remove(hwnd); return true; } @@ -186,18 +186,19 @@ void FramelessHelperWin::addWindow(QWindow *window) if (!window) { return; } - const WId winId = window->winId(); - g_helper()->mutex.lock(); - if (g_helper()->acceptableWinIds.contains(winId)) { - g_helper()->mutex.unlock(); + g_win32Helper()->mutex.lock(); + if (g_win32Helper()->acceptableWindows.contains(window)) { + g_win32Helper()->mutex.unlock(); return; } - g_helper()->acceptableWinIds.append(winId); - if (g_helper()->instance.isNull()) { - g_helper()->instance.reset(new FramelessHelperWin); - qApp->installNativeEventFilter(g_helper()->instance.data()); + g_win32Helper()->acceptableWindows.append(window); + const WId winId = window->winId(); + g_win32Helper()->windowMapping.insert(winId, window); + if (g_win32Helper()->nativeEventFilter.isNull()) { + g_win32Helper()->nativeEventFilter.reset(new FramelessHelperWin); + qApp->installNativeEventFilter(g_win32Helper()->nativeEventFilter.data()); } - g_helper()->mutex.unlock(); + g_win32Helper()->mutex.unlock(); Utilities::fixupQtInternals(winId); Utilities::updateInternalWindowFrameMargins(window, true); Utilities::updateWindowFrameMargins(winId, false); @@ -214,14 +215,15 @@ void FramelessHelperWin::removeWindow(QWindow *window) if (!window) { return; } - const WId winId = window->winId(); - g_helper()->mutex.lock(); - if (!g_helper()->acceptableWinIds.contains(winId)) { - g_helper()->mutex.unlock(); + g_win32Helper()->mutex.lock(); + if (!g_win32Helper()->acceptableWindows.contains(window)) { + g_win32Helper()->mutex.unlock(); return; } - g_helper()->acceptableWinIds.removeAll(winId); - g_helper()->mutex.unlock(); + g_win32Helper()->acceptableWindows.removeAll(window); + const WId winId = window->winId(); + g_win32Helper()->windowMapping.remove(winId); + g_win32Helper()->mutex.unlock(); if (!uninstallWindowHook(winId)) { qWarning() << "Failed to un-hook the window proc function."; } @@ -250,19 +252,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me return false; } const WId winId = reinterpret_cast(msg->hwnd); - g_helper()->mutex.lock(); - if (!g_helper()->acceptableWinIds.contains(winId)) { - g_helper()->mutex.unlock(); + g_win32Helper()->mutex.lock(); + if (!g_win32Helper()->windowMapping.contains(winId)) { + g_win32Helper()->mutex.unlock(); return false; } - g_helper()->mutex.unlock(); - const FramelessManagerPrivate * const manager = FramelessManagerPrivate::instance(); - const QUuid id = manager->findIdByWinId(winId); - Q_ASSERT(!id.isNull()); - if (id.isNull()) { - return false; - } - QWindow * const window = manager->findWindowById(id); + QWindow * const window = g_win32Helper()->windowMapping.value(winId); + g_win32Helper()->mutex.unlock(); Q_ASSERT(window); if (!window) { return false; @@ -359,7 +355,7 @@ 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()) { + if (Utilities::isWindowFrameBorderVisible()) { // Store the original top before the default window proc applies the default frame. const LONG originalTop = clientRect->top; // Apply the default frame. @@ -385,7 +381,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // a window when it's maximized unless you restore it). const int frameSizeY = Utilities::getResizeBorderThickness(winId, false, true); clientRect->top += frameSizeY; - if (!Utilities::isWin10OrGreater()) { + if (!Utilities::isWindowFrameBorderVisible()) { clientRect->bottom -= frameSizeY; const int frameSizeX = Utilities::getResizeBorderThickness(winId, true, true); clientRect->left += frameSizeX; @@ -598,8 +594,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me 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()) { + static constexpr const bool isTitleBar = false; + if (Utilities::isWindowFrameBorderVisible()) { // 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); @@ -712,7 +708,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me default: break; } - if (!Utilities::isWin10OrGreater()) { + if (!Utilities::isWindowFrameBorderVisible()) { switch (msg->message) { case WM_NCUAHDRAWCAPTION: case WM_NCUAHDRAWFRAME: { diff --git a/framelessquickhelper.cpp b/framelessquickhelper.cpp index 48d4443..a28e2ae 100644 --- a/framelessquickhelper.cpp +++ b/framelessquickhelper.cpp @@ -78,7 +78,7 @@ qreal FramelessQuickUtils::titleBarHeight() bool FramelessQuickUtils::frameBorderVisible() { #ifdef Q_OS_WINDOWS - return (Utilities::isWin10OrGreater() && !Utilities::isWin11OrGreater()); + return (Utilities::isWindowFrameBorderVisible() && !Utilities::isWin11OrGreater()); #else return false; #endif diff --git a/framelessquickhelper.h b/framelessquickhelper.h index 0f35076..eef8c6e 100644 --- a/framelessquickhelper.h +++ b/framelessquickhelper.h @@ -41,6 +41,9 @@ class FRAMELESSHELPER_API FramelessQuickHelper : public QObject #ifdef QML_NAMED_ELEMENT QML_NAMED_ELEMENT(FramelessHelper) #endif +#ifdef QML_SINGLETON + QML_SINGLETON +#endif public: explicit FramelessQuickHelper(QObject *parent = nullptr); @@ -56,6 +59,9 @@ class FRAMELESSHELPER_API FramelessQuickUtils : public QObject Q_DISABLE_COPY_MOVE(FramelessQuickUtils) #ifdef QML_NAMED_ELEMENT QML_NAMED_ELEMENT(FramelessUtils) +#endif +#ifdef QML_SINGLETON + QML_SINGLETON #endif Q_PROPERTY(qreal titleBarHeight READ titleBarHeight CONSTANT FINAL) Q_PROPERTY(bool frameBorderVisible READ frameBorderVisible CONSTANT FINAL) diff --git a/utilities.cpp b/utilities.cpp index 76ccace..02072e5 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -26,8 +26,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE -static constexpr const int g_resizeBorderThickness = kDefaultResizeBorderThicknessAero; - Qt::CursorShape Utilities::calculateCursorShape(const QWindow *window, const QPointF &pos) { Q_ASSERT(window); @@ -37,18 +35,18 @@ Qt::CursorShape Utilities::calculateCursorShape(const QWindow *window, const QPo if (window->visibility() != QWindow::Windowed) { return Qt::ArrowCursor; } - if (((pos.x() < g_resizeBorderThickness) && (pos.y() < g_resizeBorderThickness)) - || ((pos.x() >= (window->width() - g_resizeBorderThickness)) && (pos.y() >= (window->height() - g_resizeBorderThickness)))) { + if (((pos.x() < kDefaultResizeBorderThickness) && (pos.y() < kDefaultResizeBorderThickness)) + || ((pos.x() >= (window->width() - kDefaultResizeBorderThickness)) && (pos.y() >= (window->height() - kDefaultResizeBorderThickness)))) { return Qt::SizeFDiagCursor; } - if (((pos.x() >= (window->width() - g_resizeBorderThickness)) && (pos.y() < g_resizeBorderThickness)) - || ((pos.x() < g_resizeBorderThickness) && (pos.y() >= (window->height() - g_resizeBorderThickness)))) { + if (((pos.x() >= (window->width() - kDefaultResizeBorderThickness)) && (pos.y() < kDefaultResizeBorderThickness)) + || ((pos.x() < kDefaultResizeBorderThickness) && (pos.y() >= (window->height() - kDefaultResizeBorderThickness)))) { return Qt::SizeBDiagCursor; } - if ((pos.x() < g_resizeBorderThickness) || (pos.x() >= (window->width() - g_resizeBorderThickness))) { + if ((pos.x() < kDefaultResizeBorderThickness) || (pos.x() >= (window->width() - kDefaultResizeBorderThickness))) { return Qt::SizeHorCursor; } - if ((pos.y() < g_resizeBorderThickness) || (pos.y() >= (window->height() - g_resizeBorderThickness))) { + if ((pos.y() < kDefaultResizeBorderThickness) || (pos.y() >= (window->height() - kDefaultResizeBorderThickness))) { return Qt::SizeVerCursor; } return Qt::ArrowCursor; @@ -64,16 +62,16 @@ Qt::Edges Utilities::calculateWindowEdges(const QWindow *window, const QPointF & return {}; } Qt::Edges edges = {}; - if (pos.x() < g_resizeBorderThickness) { + if (pos.x() < kDefaultResizeBorderThickness) { edges |= Qt::LeftEdge; } - if (pos.x() >= (window->width() - g_resizeBorderThickness)) { + if (pos.x() >= (window->width() - kDefaultResizeBorderThickness)) { edges |= Qt::RightEdge; } - if (pos.y() < g_resizeBorderThickness) { + if (pos.y() < kDefaultResizeBorderThickness) { edges |= Qt::TopEdge; } - if (pos.y() >= (window->height() - g_resizeBorderThickness)) { + if (pos.y() >= (window->height() - kDefaultResizeBorderThickness)) { edges |= Qt::BottomEdge; } return edges; diff --git a/utilities.h b/utilities.h index 86d3bda..4247554 100644 --- a/utilities.h +++ b/utilities.h @@ -29,6 +29,17 @@ FRAMELESSHELPER_BEGIN_NAMESPACE +#ifdef Q_OS_WINDOWS +enum class DwmColorizationArea : int +{ + None = 0, + StartMenu_TaskBar_ActionCenter = 1, + TitleBar_WindowBorder = 2, + All = 3 +}; +Q_ENUM_NS(DwmColorizationArea) +#endif + namespace Utilities { @@ -66,6 +77,7 @@ FRAMELESSHELPER_API void showSystemMenu(const WId winId, const QPointF &pos); [[nodiscard]] FRAMELESSHELPER_API QColor getFrameBorderColor(const bool active); FRAMELESSHELPER_API void updateWindowFrameBorderColor(const WId winId, const bool dark); FRAMELESSHELPER_API void fixupQtInternals(const WId winId); +[[nodiscard]] FRAMELESSHELPER_API bool isWindowFrameBorderVisible(); #endif // Q_OS_WINDOWS } // namespace Utilities diff --git a/utilities_win32.cpp b/utilities_win32.cpp index ce5b654..5e473e4 100644 --- a/utilities_win32.cpp +++ b/utilities_win32.cpp @@ -46,6 +46,8 @@ Q_DECLARE_METATYPE(QMargins) FRAMELESSHELPER_BEGIN_NAMESPACE +static const QString successErrorText = QStringLiteral("The operation completed successfully."); + #if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) [[nodiscard]] static inline bool isWindowsVersionOrGreater(const DWORD dwMajor, const DWORD dwMinor, const DWORD dwBuild) { @@ -71,17 +73,21 @@ FRAMELESSHELPER_BEGIN_NAMESPACE return {}; } if (code == ERROR_SUCCESS) { - return {}; + return successErrorText; } 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 {}; + return QStringLiteral("FormatMessageW() returned empty string."); } - const QString message = QStringLiteral("Function %1() failed with error code %2: %3.") - .arg(function, QString::number(code), QString::fromWCharArray(buf)); + QString errorText = QString::fromWCharArray(buf); LocalFree(buf); - return message; + buf = nullptr; + errorText = errorText.trimmed(); + errorText.remove(QStringLiteral("\\r")); + errorText.replace(QStringLiteral("\\n"), QStringLiteral("\n")); + return QStringLiteral("Function \"%1()\" failed with error code %2: %3.") + .arg(function, QString::number(code), errorText); } [[nodiscard]] static inline QString __getSystemErrorMessage(const QString &function, const HRESULT hr) @@ -91,7 +97,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE return {}; } if (SUCCEEDED(hr)) { - return {}; + return successErrorText; } const DWORD dwError = HRESULT_CODE(hr); return __getSystemErrorMessage(function, dwError); @@ -248,7 +254,7 @@ void Utilities::updateWindowFrameMargins(const WId winId, const bool reset) if (reset) { return {0, 0, 0, 0}; } - if (isWin10OrGreater()) { + if (isWindowFrameBorderVisible()) { return {0, static_cast(getTitleBarHeight(winId, true)), 0, 0}; } else { return {1, 1, 1, 1}; @@ -275,7 +281,7 @@ void Utilities::updateInternalWindowFrameMargins(QWindow *window, const bool ena return {}; } const int titleBarHeight = getTitleBarHeight(winId, true); - if (isWin10OrGreater()) { + if (isWindowFrameBorderVisible()) { return {0, -titleBarHeight, 0, 0}; } else { const int frameSizeX = getResizeBorderThickness(winId, true, true); @@ -286,17 +292,14 @@ void Utilities::updateInternalWindowFrameMargins(QWindow *window, const bool ena const QVariant marginsVar = QVariant::fromValue(margins); window->setProperty("_q_windowsCustomMargins", marginsVar); #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - QPlatformWindow *platformWindow = window->handle(); - if (platformWindow) { + if (QPlatformWindow *platformWindow = window->handle()) { QGuiApplication::platformNativeInterface()->setWindowProperty(platformWindow, QStringLiteral("WindowsCustomMargins"), marginsVar); } else { qWarning() << "Failed to retrieve the platform window."; return; } #else - auto *platformWindow = dynamic_cast( - window->handle()); - if (platformWindow) { + if (const auto platformWindow = dynamic_cast(window->handle())) { platformWindow->setCustomMargins(margins); } else { qWarning() << "Failed to retrieve the platform window."; @@ -866,4 +869,20 @@ void Utilities::startSystemResize(QWindow *window, const Qt::Edges edges) #endif } +bool Utilities::isWindowFrameBorderVisible() +{ + static const bool result = []() -> bool { + // If we preserve the window frame border on systems before Windows 10, + // the window will look rather ugly and I guess no one would like to see + // such weired windows. If you really want to know what the window look + // like in such situations, just comment out the following IF statement + // and run your application on Windows 7/8/8.1. + if (!isWin10OrGreater()) { + return false; + } + return !qEnvironmentVariableIsSet("FRAMELESSHELPER_HIDE_FRAME_BORDER"); + }(); + return result; +} + FRAMELESSHELPER_END_NAMESPACE