diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index f2628dc..ff2b9fe 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -79,10 +79,10 @@ void MainWindow::setupUi() setTitleBarWidget(titleBarWidget); - setHitTestVisible(titleBar->iconButton, true); - setHitTestVisible(titleBar->minimizeButton, true); - setHitTestVisible(titleBar->maximizeButton, true); - setHitTestVisible(titleBar->closeButton, true); + setHitTestVisible(titleBar->iconButton); + setHitTestVisible(titleBar->minimizeButton); + setHitTestVisible(titleBar->maximizeButton); + setHitTestVisible(titleBar->closeButton); connect(titleBar->minimizeButton, &QPushButton::clicked, this, &MainWindow::showMinimized); connect(titleBar->maximizeButton, &QPushButton::clicked, this, &MainWindow::toggleMaximized); diff --git a/examples/quick/qml/MainWindow.qml b/examples/quick/qml/MainWindow.qml index 43ca0c4..bc34d91 100644 --- a/examples/quick/qml/MainWindow.qml +++ b/examples/quick/qml/MainWindow.qml @@ -65,21 +65,21 @@ FramelessWindow { title: window.title minimizeButton { id: minimizeButton - onClicked: FramelessUtils.showMinimized2(window) + onClicked: window.showMinimized2() } maximizeButton { id: maximizeButton - onClicked: FramelessUtils.toggleMaximize(window) + onClicked: window.toggleMaximize() } closeButton { id: closeButton onClicked: window.close() } Component.onCompleted: { - FramelessHelper.setTitleBarItem(window, titleBar); - FramelessHelper.setHitTestVisible(window, minimizeButton, true); - FramelessHelper.setHitTestVisible(window, maximizeButton, true); - FramelessHelper.setHitTestVisible(window, closeButton, true); + window.setTitleBarItem(titleBar); + window.setHitTestVisible(minimizeButton); + window.setHitTestVisible(maximizeButton); + window.setHitTestVisible(closeButton); } } } diff --git a/include/FramelessHelper/Core/framelesshelpercore_global.h b/include/FramelessHelper/Core/framelesshelpercore_global.h index cc96491..9096784 100644 --- a/include/FramelessHelper/Core/framelesshelpercore_global.h +++ b/include/FramelessHelper/Core/framelesshelpercore_global.h @@ -148,7 +148,8 @@ enum class Option : int DisableResizing = 0x00002000, // Disable resizing of the window. DisableDragging = 0x00004000, // Disable dragging through the titlebar of the window. DontTouchCursorShape = 0x00008000, // Don't change the cursor shape while the mouse is hovering above the window. - DontMoveWindowToDesktopCenter = 0x00010000 // Don't move the window to the desktop center before shown. + DontMoveWindowToDesktopCenter = 0x00010000, // Don't move the window to the desktop center before shown. + DontTreatFullScreenAsZoomed = 0x00020000 // Don't treat fullscreen as zoomed (maximized). }; Q_DECLARE_FLAGS(Options, Option) Q_FLAG_NS(Options) diff --git a/include/FramelessHelper/Quick/framelessquickeventfilter.h b/include/FramelessHelper/Quick/framelessquickeventfilter.h index cffbeeb..06a803a 100644 --- a/include/FramelessHelper/Quick/framelessquickeventfilter.h +++ b/include/FramelessHelper/Quick/framelessquickeventfilter.h @@ -46,7 +46,7 @@ public: Q_INVOKABLE static void addWindow(QQuickWindow *window); Q_INVOKABLE static void removeWindow(QQuickWindow *window); Q_INVOKABLE static void setTitleBarItem(QQuickWindow *window, QQuickItem *item); - Q_INVOKABLE static void setHitTestVisible(QQuickWindow *window, QQuickItem *item, const bool visible); + Q_INVOKABLE static void setHitTestVisible(QQuickWindow *window, QQuickItem *item); protected: Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override; diff --git a/include/FramelessHelper/Quick/framelessquickhelper.h b/include/FramelessHelper/Quick/framelessquickhelper.h index aa98880..7bc1e4c 100644 --- a/include/FramelessHelper/Quick/framelessquickhelper.h +++ b/include/FramelessHelper/Quick/framelessquickhelper.h @@ -52,7 +52,7 @@ public: Q_INVOKABLE static void addWindow(QQuickWindow *window); Q_INVOKABLE static void removeWindow(QQuickWindow *window); Q_INVOKABLE static void setTitleBarItem(QQuickWindow *window, QQuickItem *item); - Q_INVOKABLE static void setHitTestVisible(QQuickWindow *window, QQuickItem *item, const bool visible); + Q_INVOKABLE static void setHitTestVisible(QQuickWindow *window, QQuickItem *item); }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Quick/framelessquickutils.h b/include/FramelessHelper/Quick/framelessquickutils.h index d893918..83dd6be 100644 --- a/include/FramelessHelper/Quick/framelessquickutils.h +++ b/include/FramelessHelper/Quick/framelessquickutils.h @@ -47,11 +47,9 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickUtils : public QObject Q_PROPERTY(qreal titleBarHeight READ titleBarHeight CONSTANT FINAL) Q_PROPERTY(bool frameBorderVisible READ frameBorderVisible CONSTANT FINAL) Q_PROPERTY(qreal frameBorderThickness READ frameBorderThickness CONSTANT FINAL) - Q_PROPERTY(QColor frameBorderActiveColor READ frameBorderActiveColor NOTIFY frameBorderActiveColorChanged FINAL) - Q_PROPERTY(QColor frameBorderInactiveColor READ frameBorderInactiveColor NOTIFY frameBorderInactiveColorChanged FINAL) Q_PROPERTY(bool darkModeEnabled READ darkModeEnabled NOTIFY darkModeEnabledChanged FINAL) Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemAccentColorChanged FINAL) - Q_PROPERTY(bool titleBarColorVisible READ titleBarColorVisible NOTIFY titleBarColorVisibleChanged FINAL) + Q_PROPERTY(bool titleBarColorized READ titleBarColorized NOTIFY titleBarColorizedChanged FINAL) Q_PROPERTY(QColor defaultSystemLightColor READ defaultSystemLightColor CONSTANT FINAL) Q_PROPERTY(QColor defaultSystemDarkColor READ defaultSystemDarkColor CONSTANT FINAL) Q_PROPERTY(QSizeF defaultSystemButtonSize READ defaultSystemButtonSize CONSTANT FINAL) @@ -64,28 +62,18 @@ public: Q_NODISCARD static qreal titleBarHeight(); Q_NODISCARD static bool frameBorderVisible(); Q_NODISCARD static qreal frameBorderThickness(); - Q_NODISCARD static QColor frameBorderActiveColor(); - Q_NODISCARD static QColor frameBorderInactiveColor(); Q_NODISCARD static bool darkModeEnabled(); Q_NODISCARD static QColor systemAccentColor(); - Q_NODISCARD static bool titleBarColorVisible(); + Q_NODISCARD static bool titleBarColorized(); Q_NODISCARD static QColor defaultSystemLightColor(); Q_NODISCARD static QColor defaultSystemDarkColor(); Q_NODISCARD static QSizeF defaultSystemButtonSize(); Q_NODISCARD static QSizeF defaultSystemButtonIconSize(); - Q_INVOKABLE static void showMinimized2(QQuickWindow *window); - Q_INVOKABLE static void toggleMaximize(QQuickWindow *window); - Q_INVOKABLE static void showSystemMenu(QQuickWindow *window, const QPoint &pos); - Q_INVOKABLE static void startSystemMove2(QQuickWindow *window); - Q_INVOKABLE static void startSystemResize2(QQuickWindow *window, const Qt::Edges edges); - Q_SIGNALS: - void frameBorderActiveColorChanged(); - void frameBorderInactiveColorChanged(); void darkModeEnabledChanged(); void systemAccentColorChanged(); - void titleBarColorVisibleChanged(); + void titleBarColorizedChanged(); }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Quick/framelessquickwindow.h b/include/FramelessHelper/Quick/framelessquickwindow.h index 337b133..e8cbdb8 100644 --- a/include/FramelessHelper/Quick/framelessquickwindow.h +++ b/include/FramelessHelper/Quick/framelessquickwindow.h @@ -25,6 +25,7 @@ #pragma once #include "framelesshelperquick_global.h" +#include #include FRAMELESSHELPER_BEGIN_NAMESPACE @@ -34,18 +35,34 @@ class FramelessQuickWindowPrivate; class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow { Q_OBJECT +#ifdef QML_NAMED_ELEMENT + QML_NAMED_ELEMENT(FramelessWindow) +#endif Q_DECLARE_PRIVATE(FramelessQuickWindow) Q_DISABLE_COPY_MOVE(FramelessQuickWindow) Q_PROPERTY(bool zoomed READ zoomed NOTIFY zoomedChanged FINAL) + Q_PROPERTY(QColor frameBorderColor READ frameBorderColor NOTIFY frameBorderColorChanged FINAL) public: - explicit FramelessQuickWindow(QWindow *parent = nullptr); + explicit FramelessQuickWindow(QWindow *parent = nullptr, const Options options = {}); ~FramelessQuickWindow() override; Q_NODISCARD bool zoomed() const; + Q_NODISCARD QColor frameBorderColor() const; + +public Q_SLOTS: + void showMinimized2(); + void toggleMaximize(); + void toggleFullScreen(); + void showSystemMenu(const QPoint &pos); + void startSystemMove2(); + void startSystemResize2(const Qt::Edges edges); + void setTitleBarItem(QQuickItem *item); + void setHitTestVisible(QQuickItem *item); Q_SIGNALS: void zoomedChanged(); + void frameBorderColorChanged(); private: QScopedPointer d_ptr; diff --git a/include/FramelessHelper/Widgets/framelessmainwindow.h b/include/FramelessHelper/Widgets/framelessmainwindow.h index 4728f9a..14b05f0 100644 --- a/include/FramelessHelper/Widgets/framelessmainwindow.h +++ b/include/FramelessHelper/Widgets/framelessmainwindow.h @@ -47,9 +47,10 @@ public: void setTitleBarWidget(QWidget *widget); Q_NODISCARD QWidget *titleBarWidget() const; - Q_INVOKABLE void setHitTestVisible(QWidget *widget, const bool visible); + Q_INVOKABLE void setHitTestVisible(QWidget *widget); Q_INVOKABLE void toggleMaximized(); + Q_INVOKABLE void toggleFullScreen(); protected: void changeEvent(QEvent *event) override; diff --git a/include/FramelessHelper/Widgets/framelesswidget.h b/include/FramelessHelper/Widgets/framelesswidget.h index 00b10ce..29ca494 100644 --- a/include/FramelessHelper/Widgets/framelesswidget.h +++ b/include/FramelessHelper/Widgets/framelesswidget.h @@ -51,9 +51,10 @@ public: void setContentWidget(QWidget *widget); Q_NODISCARD QWidget *contentWidget() const; - Q_INVOKABLE void setHitTestVisible(QWidget *widget, const bool visible); + Q_INVOKABLE void setHitTestVisible(QWidget *widget); Q_INVOKABLE void toggleMaximized(); + Q_INVOKABLE void toggleFullScreen(); protected: void changeEvent(QEvent *event) override; diff --git a/include/FramelessHelper/Widgets/framelesswidgetshelper.h b/include/FramelessHelper/Widgets/framelesswidgetshelper.h index 8e8a927..f6887b3 100644 --- a/include/FramelessHelper/Widgets/framelesswidgetshelper.h +++ b/include/FramelessHelper/Widgets/framelesswidgetshelper.h @@ -57,9 +57,10 @@ public: Q_INVOKABLE void setContentWidget(QWidget *widget); Q_NODISCARD Q_INVOKABLE QWidget *contentWidget() const; - Q_INVOKABLE void setHitTestVisible(QWidget *widget, const bool visible); + Q_INVOKABLE void setHitTestVisible(QWidget *widget); Q_INVOKABLE void toggleMaximized(); + Q_INVOKABLE void toggleFullScreen(); Q_INVOKABLE void changeEventHandler(QEvent *event); Q_INVOKABLE void paintEventHandler(QPaintEvent *event); @@ -96,6 +97,8 @@ private: QWidgetList m_hitTestVisibleWidgets = {}; QWidget *m_userContentContainerWidget = nullptr; QVBoxLayout *m_userContentContainerLayout = nullptr; + Qt::WindowStates m_savedWindowState = {}; + QWindow *m_window = nullptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/framelesshelper_qt.cpp b/src/core/framelesshelper_qt.cpp index 8671fe7..68a853e 100644 --- a/src/core/framelesshelper_qt.cpp +++ b/src/core/framelesshelper_qt.cpp @@ -30,11 +30,17 @@ FRAMELESSHELPER_BEGIN_NAMESPACE +struct QtHelperInternalData +{ + QWindow *window = nullptr; + FramelessHelperQt *qtFramelessHelper = nullptr; + Options options = {}; +}; + struct QtHelper { QMutex mutex = {}; - QHash qtFramelessHelpers = {}; - QHash options = {}; + QHash data = {}; explicit QtHelper() = default; ~QtHelper() = default; @@ -56,18 +62,19 @@ void FramelessHelperQt::addWindow(QWindow *window) return; } g_qtHelper()->mutex.lock(); - if (g_qtHelper()->qtFramelessHelpers.contains(window)) { + if (g_qtHelper()->data.contains(window)) { g_qtHelper()->mutex.unlock(); return; } - const auto options = qvariant_cast(window->property(kInternalOptionsFlag)); - g_qtHelper()->options.insert(window, options); + QtHelperInternalData data = {}; + data.window = window; // Give it a parent so that it can be deleted even if we forget to do so. - const auto qtFramelessHelper = new FramelessHelperQt(window); - g_qtHelper()->qtFramelessHelpers.insert(window, qtFramelessHelper); + data.qtFramelessHelper = new FramelessHelperQt(window); + data.options = qvariant_cast(window->property(kInternalOptionsFlag)); + g_qtHelper()->data.insert(window, data); g_qtHelper()->mutex.unlock(); window->setFlags(window->flags() | Qt::FramelessWindowHint); - window->installEventFilter(qtFramelessHelper); + window->installEventFilter(data.qtFramelessHelper); } void FramelessHelperQt::removeWindow(QWindow *window) @@ -77,17 +84,15 @@ void FramelessHelperQt::removeWindow(QWindow *window) return; } g_qtHelper()->mutex.lock(); - if (!g_qtHelper()->qtFramelessHelpers.contains(window)) { + if (!g_qtHelper()->data.contains(window)) { g_qtHelper()->mutex.unlock(); return; } - g_qtHelper()->options.remove(window); - FramelessHelperQt *qtFramelessHelper = g_qtHelper()->qtFramelessHelpers.value(window); - g_qtHelper()->qtFramelessHelpers.remove(window); + const QtHelperInternalData data = g_qtHelper()->data.value(window); + g_qtHelper()->data.remove(window); g_qtHelper()->mutex.unlock(); - window->removeEventFilter(qtFramelessHelper); - delete qtFramelessHelper; - qtFramelessHelper = nullptr; + window->removeEventFilter(data.qtFramelessHelper); + delete data.qtFramelessHelper; window->setFlags(window->flags() & ~Qt::FramelessWindowHint); } @@ -109,11 +114,11 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) } const auto window = qobject_cast(object); g_qtHelper()->mutex.lock(); - if (!g_qtHelper()->qtFramelessHelpers.contains(window)) { + if (!g_qtHelper()->data.contains(window)) { g_qtHelper()->mutex.unlock(); return false; } - const Options options = g_qtHelper()->options.value(window); + const QtHelperInternalData data = g_qtHelper()->data.value(window); g_qtHelper()->mutex.unlock(); if (Utils::isWindowFixedSize(window)) { return false; @@ -126,7 +131,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) #endif switch (type) { case QEvent::MouseMove: { - if (options & Option::DontTouchCursorShape) { + if (data.options & Option::DontTouchCursorShape) { return false; } const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos); diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 67836e8..2e3165b 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -53,11 +53,18 @@ Q_DECLARE_METATYPE(QMargins) FRAMELESSHELPER_BEGIN_NAMESPACE +struct Win32UtilsInternalData +{ + HWND hwnd = nullptr; + QWindow *window = nullptr; + WNDPROC originalWindowProc = nullptr; + Options options = {}; +}; + struct Win32UtilsHelper { QMutex mutex = {}; - QHash qtWindowProcs = {}; - QHash windowMapping = {}; + QHash data = {}; explicit Win32UtilsHelper() = default; ~Win32UtilsHelper() = default; @@ -178,28 +185,28 @@ static const QString successErrorText = QStringLiteral("The operation completed (const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) { g_utilsHelper()->mutex.lock(); - if (!g_utilsHelper()->qtWindowProcs.contains(hWnd)) { - g_utilsHelper()->mutex.unlock(); - return DefWindowProcW(hWnd, uMsg, wParam, lParam); - } - const QWindow * const window = g_utilsHelper()->windowMapping.value(hWnd); - Q_ASSERT(window); - if (!window) { + if (!g_utilsHelper()->data.contains(hWnd)) { g_utilsHelper()->mutex.unlock(); return DefWindowProcW(hWnd, uMsg, wParam, lParam); } + const Win32UtilsInternalData data = g_utilsHelper()->data.value(hWnd); g_utilsHelper()->mutex.unlock(); + Q_ASSERT(data.window); + if (!data.window) { + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } const auto winId = reinterpret_cast(hWnd); const auto getGlobalPosFromMouse = [lParam]() -> QPoint { return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; }; - const auto getGlobalPosFromKeyboard = [hWnd, winId]() -> QPoint { + const auto getGlobalPosFromKeyboard = [hWnd, winId, &data]() -> QPoint { RECT windowPos = {}; if (GetWindowRect(hWnd, &windowPos) == FALSE) { qWarning() << Utils::getSystemErrorMessage(QStringLiteral("GetWindowRect")); return {}; } - const bool maxOrFull = (IsMaximized(hWnd) || Utils::isFullScreen(winId)); + const bool maxOrFull = (IsMaximized(hWnd) || + ((data.options & Option::DontTreatFullScreenAsZoomed) ? false : Utils::isFullScreen(winId))); const int frameSizeX = Utils::getResizeBorderThickness(winId, true, true); const bool frameBorderVisible = Utils::isWindowFrameBorderVisible(); const int horizontalOffset = ((maxOrFull || !frameBorderVisible) ? 0 : frameSizeX); @@ -244,21 +251,18 @@ static const QString successErrorText = QStringLiteral("The operation completed } } if (shouldShowSystemMenu) { - Utils::showSystemMenu(window, globalPos); + Utils::showSystemMenu(data.window, globalPos); // QPA's internal code will handle system menu events separately, and its // behavior is not what we would want to see because it doesn't know our // window doesn't have any window frame now, so return early here to avoid // entering Qt's own handling logic. return 0; // Return 0 means we have handled this event. } - g_utilsHelper()->mutex.lock(); - const WNDPROC originalWindowProc = g_utilsHelper()->qtWindowProcs.value(hWnd); - g_utilsHelper()->mutex.unlock(); - Q_ASSERT(originalWindowProc); - if (originalWindowProc) { + Q_ASSERT(data.originalWindowProc); + if (data.originalWindowProc) { // Hand over to Qt's original window proc function for events we are not // interested in. - return CallWindowProcW(originalWindowProc, hWnd, uMsg, wParam, lParam); + return CallWindowProcW(data.originalWindowProc, hWnd, uMsg, wParam, lParam); } else { return DefWindowProcW(hWnd, uMsg, wParam, lParam); } @@ -519,9 +523,10 @@ void Utils::showSystemMenu(const QWindow *window, const QPoint &pos) } return true; }; - const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(reinterpret_cast(hWnd))); - const bool fixedSize = isWindowFixedSize(window); const auto options = qvariant_cast(window->property(kInternalOptionsFlag)); + const bool maxOrFull = (IsMaximized(hWnd) || + ((options & Option::DontTreatFullScreenAsZoomed) ? false : isFullScreen(reinterpret_cast(hWnd)))); + const bool fixedSize = isWindowFixedSize(window); if (!setState(SC_RESTORE, (maxOrFull && !fixedSize), true)) { return; } @@ -1027,7 +1032,7 @@ void Utils::installSystemMenuHook(const QWindow *window) } const auto hwnd = reinterpret_cast(window->winId()); QMutexLocker locker(&g_utilsHelper()->mutex); - if (g_utilsHelper()->qtWindowProcs.contains(hwnd)) { + if (g_utilsHelper()->data.contains(hwnd)) { return; } SetLastError(ERROR_SUCCESS); @@ -1043,8 +1048,12 @@ void Utils::installSystemMenuHook(const QWindow *window) return; } //triggerFrameChange(winId); - g_utilsHelper()->qtWindowProcs.insert(hwnd, originalWindowProc); - g_utilsHelper()->windowMapping.insert(hwnd, const_cast(window)); + Win32UtilsInternalData data = {}; + data.hwnd = hwnd; + data.window = const_cast(window); + data.originalWindowProc = originalWindowProc; + data.options = qvariant_cast(window->property(kInternalOptionsFlag)); + g_utilsHelper()->data.insert(hwnd, data); } void Utils::uninstallSystemMenuHook(const WId winId) @@ -1055,22 +1064,21 @@ void Utils::uninstallSystemMenuHook(const WId winId) } const auto hwnd = reinterpret_cast(winId); QMutexLocker locker(&g_utilsHelper()->mutex); - if (!g_utilsHelper()->qtWindowProcs.contains(hwnd)) { + if (!g_utilsHelper()->data.contains(hwnd)) { return; } - const WNDPROC originalWindowProc = g_utilsHelper()->qtWindowProcs.value(hwnd); - Q_ASSERT(originalWindowProc); - if (!originalWindowProc) { + const Win32UtilsInternalData data = g_utilsHelper()->data.value(hwnd); + Q_ASSERT(data.originalWindowProc); + if (!data.originalWindowProc) { return; } SetLastError(ERROR_SUCCESS); - if (SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast(originalWindowProc)) == 0) { + if (SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast(data.originalWindowProc)) == 0) { qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW")); return; } //triggerFrameChange(winId); - g_utilsHelper()->qtWindowProcs.remove(hwnd); - g_utilsHelper()->windowMapping.remove(hwnd); + g_utilsHelper()->data.remove(hwnd); } void Utils::sendMouseReleaseEvent() diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt index c7127e7..66a9ed6 100644 --- a/src/quick/CMakeLists.txt +++ b/src/quick/CMakeLists.txt @@ -58,7 +58,7 @@ if(MSVC) _WIN32_IE=${_WIN32_WINNT_WIN10} NTDDI_VERSION=${NTDDI_WIN10_CO} ) target_compile_options(${SUB_PROJ_NAME} PRIVATE - /W4 /WX + /utf-8 /W4 /WX ) else() target_compile_options(${SUB_PROJ_NAME} PRIVATE diff --git a/src/quick/framelessquickeventfilter.cpp b/src/quick/framelessquickeventfilter.cpp index d7546db..4c4705a 100644 --- a/src/quick/framelessquickeventfilter.cpp +++ b/src/quick/framelessquickeventfilter.cpp @@ -147,7 +147,7 @@ void FramelessQuickEventFilter::setTitleBarItem(QQuickWindow *window, QQuickItem g_data()->data[window].titleBarItem = item; } -void FramelessQuickEventFilter::setHitTestVisible(QQuickWindow *window, QQuickItem *item, const bool visible) +void FramelessQuickEventFilter::setHitTestVisible(QQuickWindow *window, QQuickItem *item) { Q_ASSERT(window); Q_ASSERT(item); @@ -159,11 +159,12 @@ void FramelessQuickEventFilter::setHitTestVisible(QQuickWindow *window, QQuickIt return; } auto &items = g_data()->data[window].hitTestVisibleItems; + static constexpr const bool visible = true; const bool exists = items.contains(item); if (visible && !exists) { items.append(item); } - if (!visible && exists) { + if constexpr (!visible && exists) { items.removeAll(item); } } @@ -246,7 +247,7 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event) return true; } case QEvent::MouseButtonDblClick: { - if ((options & Option::NoDoubleClickMaximizeToggle) || (options & Option::DisableResizing)) { + if ((options & Option::NoDoubleClickMaximizeToggle) || Utils::isWindowFixedSize(window)) { return false; } if (button != Qt::LeftButton) { @@ -255,7 +256,8 @@ bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event) if (!titleBar) { return false; } - if ((visibility == QQuickWindow::Maximized) || (visibility == QQuickWindow::FullScreen)) { + if ((visibility == QQuickWindow::Maximized) || + ((options & Option::DontTreatFullScreenAsZoomed) ? false : (visibility == QQuickWindow::FullScreen))) { window->showNormal(); } else { window->showMaximized(); diff --git a/src/quick/framelessquickhelper.cpp b/src/quick/framelessquickhelper.cpp index de9a6c8..371d619 100644 --- a/src/quick/framelessquickhelper.cpp +++ b/src/quick/framelessquickhelper.cpp @@ -63,14 +63,14 @@ void FramelessQuickHelper::setTitleBarItem(QQuickWindow *window, QQuickItem *ite FramelessQuickEventFilter::setTitleBarItem(window, item); } -void FramelessQuickHelper::setHitTestVisible(QQuickWindow *window, QQuickItem *item, const bool visible) +void FramelessQuickHelper::setHitTestVisible(QQuickWindow *window, QQuickItem *item) { Q_ASSERT(window); Q_ASSERT(item); if (!window || !item) { return; } - FramelessQuickEventFilter::setHitTestVisible(window, item, visible); + FramelessQuickEventFilter::setHitTestVisible(window, item); } FRAMELESSHELPER_END_NAMESPACE diff --git a/src/quick/framelessquickutils.cpp b/src/quick/framelessquickutils.cpp index e9a2461..efd2a36 100644 --- a/src/quick/framelessquickutils.cpp +++ b/src/quick/framelessquickutils.cpp @@ -23,27 +23,21 @@ */ #include "framelessquickutils.h" -#include #if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1)) # include # include #endif #include #include -#ifdef Q_OS_WINDOWS -# include -#endif FRAMELESSHELPER_BEGIN_NAMESPACE FramelessQuickUtils::FramelessQuickUtils(QObject *parent) : QObject(parent) { connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, [this](){ - Q_EMIT frameBorderActiveColorChanged(); - Q_EMIT frameBorderInactiveColorChanged(); Q_EMIT darkModeEnabledChanged(); Q_EMIT systemAccentColorChanged(); - Q_EMIT titleBarColorVisibleChanged(); + Q_EMIT titleBarColorizedChanged(); }); } @@ -51,7 +45,7 @@ FramelessQuickUtils::~FramelessQuickUtils() = default; qreal FramelessQuickUtils::titleBarHeight() { - return 30; + return 30.0; } bool FramelessQuickUtils::frameBorderVisible() @@ -65,25 +59,7 @@ bool FramelessQuickUtils::frameBorderVisible() qreal FramelessQuickUtils::frameBorderThickness() { - return 1; -} - -QColor FramelessQuickUtils::frameBorderActiveColor() -{ -#ifdef Q_OS_WINDOWS - return Utils::getFrameBorderColor(true); -#else - return {}; -#endif -} - -QColor FramelessQuickUtils::frameBorderInactiveColor() -{ -#ifdef Q_OS_WINDOWS - return Utils::getFrameBorderColor(false); -#else - return {}; -#endif + return 1.0; } bool FramelessQuickUtils::darkModeEnabled() @@ -111,7 +87,7 @@ QColor FramelessQuickUtils::systemAccentColor() #endif } -bool FramelessQuickUtils::titleBarColorVisible() +bool FramelessQuickUtils::titleBarColorized() { #ifdef Q_OS_WINDOWS return Utils::isTitleBarColorized(); @@ -140,81 +116,4 @@ QSizeF FramelessQuickUtils::defaultSystemButtonIconSize() return kDefaultSystemButtonIconSize; } -void FramelessQuickUtils::showMinimized2(QQuickWindow *window) -{ - Q_ASSERT(window); - if (!window) { - return; - } -#ifdef Q_OS_WINDOWS - // Work-around a QtQuick bug: https://bugreports.qt.io/browse/QTBUG-69711 - // Don't use "SW_SHOWMINIMIZED" because it will activate the current window - // instead of the next window in the Z order, which is not the default behavior - // of native Win32 applications. - ShowWindow(reinterpret_cast(window->winId()), SW_MINIMIZE); -#else - window->showMinimized(); -#endif -} - -void FramelessQuickUtils::toggleMaximize(QQuickWindow *window) -{ - Q_ASSERT(window); - if (!window) { - return; - } - const QQuickWindow::Visibility visibility = window->visibility(); - if ((visibility == QQuickWindow::Maximized) || (visibility == QQuickWindow::FullScreen)) { - window->showNormal(); - } else { - window->showMaximized(); - } -} - -void FramelessQuickUtils::showSystemMenu(QQuickWindow *window, const QPoint &pos) -{ - Q_ASSERT(window); - if (!window) { - return; - } -#ifdef Q_OS_WINDOWS -# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - const QPoint globalPos = window->mapToGlobal(pos); -# else - const QPoint globalPos = window->mapToGlobal(pos); -# endif - const QPoint nativePos = QPointF(QPointF(globalPos) * window->effectiveDevicePixelRatio()).toPoint(); - Utils::showSystemMenu(window, nativePos); -#endif -} - -void FramelessQuickUtils::startSystemMove2(QQuickWindow *window) -{ - Q_ASSERT(window); - if (!window) { - return; - } -#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) - window->startSystemMove(); -#else - Utils::startSystemMove(window); -#endif -} - -void FramelessQuickUtils::startSystemResize2(QQuickWindow *window, const Qt::Edges edges) -{ - Q_ASSERT(window); - if (!window) { - return; - } - if (edges == Qt::Edges{}) { - return; - } -#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) - window->startSystemResize(edges); -#else - Utils::startSystemResize(window, edges); -#endif -} - FRAMELESSHELPER_END_NAMESPACE diff --git a/src/quick/framelessquickwindow.cpp b/src/quick/framelessquickwindow.cpp index 4752c23..7506519 100644 --- a/src/quick/framelessquickwindow.cpp +++ b/src/quick/framelessquickwindow.cpp @@ -29,16 +29,18 @@ #include #include #include +#include "framelessquickhelper.h" FRAMELESSHELPER_BEGIN_NAMESPACE -FramelessQuickWindowPrivate::FramelessQuickWindowPrivate(FramelessQuickWindow *q) : QObject(q) +FramelessQuickWindowPrivate::FramelessQuickWindowPrivate(FramelessQuickWindow *q, const Options options) : QObject(q) { Q_ASSERT(q); if (!q) { return; } q_ptr = q; + m_options = options; initialize(); } @@ -48,45 +50,191 @@ bool FramelessQuickWindowPrivate::isZoomed() const { Q_Q(const FramelessQuickWindow); const FramelessQuickWindow::Visibility visibility = q->visibility(); - return ((visibility == FramelessQuickWindow::Maximized) || (visibility == FramelessQuickWindow::FullScreen)); + return ((visibility == FramelessQuickWindow::Maximized) || + ((m_options & Option::DontTreatFullScreenAsZoomed) ? false : (visibility == FramelessQuickWindow::FullScreen))); +} + +QColor FramelessQuickWindowPrivate::getFrameBorderColor() const +{ +#ifdef Q_OS_WINDOWS + Q_Q(const FramelessQuickWindow); + return Utils::getFrameBorderColor(q->isActive()); +#else + return {}; +#endif +} + +void FramelessQuickWindowPrivate::setTitleBarItem(QQuickItem *item) +{ + Q_ASSERT(item); + if (!item) { + return; + } + Q_Q(FramelessQuickWindow); + FramelessQuickHelper::setTitleBarItem(q, item); +} + +void FramelessQuickWindowPrivate::setHitTestVisible(QQuickItem *item) +{ + Q_ASSERT(item); + if (!item) { + return; + } + Q_Q(FramelessQuickWindow); + FramelessQuickHelper::setHitTestVisible(q, item); +} + +void FramelessQuickWindowPrivate::showMinimized2() +{ + Q_Q(FramelessQuickWindow); +#ifdef Q_OS_WINDOWS + // Work-around a QtQuick bug: https://bugreports.qt.io/browse/QTBUG-69711 + // Don't use "SW_SHOWMINIMIZED" because it will activate the current window + // instead of the next window in the Z order, which is not the default behavior + // of native Win32 applications. + ShowWindow(reinterpret_cast(q->winId()), SW_MINIMIZE); +#else + q->showMinimized(); +#endif +} + +void FramelessQuickWindowPrivate::toggleMaximize() +{ + Q_Q(FramelessQuickWindow); + if (Utils::isWindowFixedSize(q)) { + return; + } + if (isZoomed()) { + q->showNormal(); + } else { + q->showMaximized(); + } +} + +void FramelessQuickWindowPrivate::toggleFullScreen() +{ + Q_Q(FramelessQuickWindow); + if (Utils::isWindowFixedSize(q)) { + return; + } + const QWindow::Visibility visibility = q->visibility(); + if (visibility == QWindow::FullScreen) { + q->setVisibility(m_savedVisibility); + } else { + m_savedVisibility = visibility; + q->showFullScreen(); + } +} + +void FramelessQuickWindowPrivate::showSystemMenu(const QPoint &pos) +{ +#ifdef Q_OS_WINDOWS + Q_Q(FramelessQuickWindow); +# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + const QPoint globalPos = q->mapToGlobal(pos); +# else + const QPoint globalPos = q->mapToGlobal(pos); +# endif + const QPoint nativePos = QPointF(QPointF(globalPos) * q->effectiveDevicePixelRatio()).toPoint(); + Utils::showSystemMenu(q, nativePos); +#endif +} + +void FramelessQuickWindowPrivate::startSystemMove2() +{ + Q_Q(FramelessQuickWindow); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + q->startSystemMove(); +#else + Utils::startSystemMove(q); +#endif +} + +void FramelessQuickWindowPrivate::startSystemResize2(const Qt::Edges edges) +{ + if (edges == Qt::Edges{}) { + return; + } + Q_Q(FramelessQuickWindow); + if (Utils::isWindowFixedSize(q)) { + return; + } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + q->startSystemResize(edges); +#else + Utils::startSystemResize(q, edges); +#endif } void FramelessQuickWindowPrivate::initialize() { + if (m_initialized) { + return; + } + m_initialized = true; Q_Q(FramelessQuickWindow); - FramelessWindowsManager * const manager = FramelessWindowsManager::instance(); - manager->addWindow(q); - QQuickItem * const rootItem = q->contentItem(); - const QQuickItemPrivate * const rootItemPrivate = QQuickItemPrivate::get(rootItem); - m_topBorderRectangle.reset(new QQuickRectangle(rootItem)); - updateTopBorderHeight(); - updateTopBorderColor(); - connect(q, &FramelessQuickWindow::visibilityChanged, this, &FramelessQuickWindowPrivate::updateTopBorderHeight); - connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor); - connect(manager, &FramelessWindowsManager::systemThemeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor); - const auto topBorderAnchors = new QQuickAnchors(m_topBorderRectangle.data(), m_topBorderRectangle.data()); - topBorderAnchors->setTop(rootItemPrivate->top()); - topBorderAnchors->setLeft(rootItemPrivate->left()); - topBorderAnchors->setRight(rootItemPrivate->right()); - connect(q, &FramelessQuickWindow::visibilityChanged, q, &FramelessQuickWindow::zoomedChanged); + q->setProperty(kInternalOptionsFlag, QVariant::fromValue(m_options)); + FramelessQuickHelper::addWindow(q); +#ifdef Q_OS_WINDOWS + if (isFrameBorderVisible()) { + QQuickItem * const rootItem = q->contentItem(); + const QQuickItemPrivate * const rootItemPrivate = QQuickItemPrivate::get(rootItem); + m_topBorderRectangle.reset(new QQuickRectangle(rootItem)); + updateTopBorderHeight(); + updateTopBorderColor(); + connect(q, &FramelessQuickWindow::visibilityChanged, this, [this, q](){ + updateTopBorderHeight(); + Q_EMIT q->zoomedChanged(); + }); + connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor); + connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, this, [this, q](){ + updateTopBorderColor(); + Q_EMIT q->frameBorderColorChanged(); + }); + const auto topBorderAnchors = new QQuickAnchors(m_topBorderRectangle.data(), m_topBorderRectangle.data()); + topBorderAnchors->setTop(rootItemPrivate->top()); + topBorderAnchors->setLeft(rootItemPrivate->left()); + topBorderAnchors->setRight(rootItemPrivate->right()); + } +#endif + Utils::moveWindowToDesktopCenter([q]() -> QScreen * { return q->screen(); }, + [q]() -> QSize { return q->size(); }, + [q](const int x, const int y) -> void { + q->setX(x); + q->setY(y); + }, true); +} + +bool FramelessQuickWindowPrivate::isFrameBorderVisible() const +{ +#ifdef Q_OS_WINDOWS + return (Utils::isWindowFrameBorderVisible() && !Utils::isWin11OrGreater()); +#else + return false; +#endif } void FramelessQuickWindowPrivate::updateTopBorderColor() { - Q_Q(FramelessQuickWindow); - m_topBorderRectangle->setColor(Utils::getFrameBorderColor(q->isActive())); + if (!isFrameBorderVisible()) { + return; + } + m_topBorderRectangle->setColor(getFrameBorderColor()); } void FramelessQuickWindowPrivate::updateTopBorderHeight() { + if (!isFrameBorderVisible()) { + return; + } Q_Q(FramelessQuickWindow); const qreal newHeight = ((q->visibility() == FramelessQuickWindow::Windowed) ? 1.0 : 0.0); m_topBorderRectangle->setHeight(newHeight); } -FramelessQuickWindow::FramelessQuickWindow(QWindow *parent) : QQuickWindow(parent) +FramelessQuickWindow::FramelessQuickWindow(QWindow *parent, const Options options) : QQuickWindow(parent) { - d_ptr.reset(new FramelessQuickWindowPrivate(this)); + d_ptr.reset(new FramelessQuickWindowPrivate(this, options)); } FramelessQuickWindow::~FramelessQuickWindow() = default; @@ -97,4 +245,66 @@ bool FramelessQuickWindow::zoomed() const return d->isZoomed(); } +QColor FramelessQuickWindow::frameBorderColor() const +{ + Q_D(const FramelessQuickWindow); + return d->getFrameBorderColor(); +} + +void FramelessQuickWindow::setTitleBarItem(QQuickItem *item) +{ + Q_ASSERT(item); + if (!item) { + return; + } + Q_D(FramelessQuickWindow); + d->setTitleBarItem(item); +} + +void FramelessQuickWindow::setHitTestVisible(QQuickItem *item) +{ + Q_ASSERT(item); + if (!item) { + return; + } + Q_D(FramelessQuickWindow); + d->setHitTestVisible(item); +} + +void FramelessQuickWindow::showMinimized2() +{ + Q_D(FramelessQuickWindow); + d->showMinimized2(); +} + +void FramelessQuickWindow::toggleMaximize() +{ + Q_D(FramelessQuickWindow); + d->toggleMaximize(); +} + +void FramelessQuickWindow::toggleFullScreen() +{ + Q_D(FramelessQuickWindow); + d->toggleFullScreen(); +} + +void FramelessQuickWindow::showSystemMenu(const QPoint &pos) +{ + Q_D(FramelessQuickWindow); + d->showSystemMenu(pos); +} + +void FramelessQuickWindow::startSystemMove2() +{ + Q_D(FramelessQuickWindow); + d->startSystemMove2(); +} + +void FramelessQuickWindow::startSystemResize2(const Qt::Edges edges) +{ + Q_D(FramelessQuickWindow); + d->startSystemResize2(edges); +} + FRAMELESSHELPER_END_NAMESPACE diff --git a/src/quick/framelessquickwindow_p.h b/src/quick/framelessquickwindow_p.h index 1d7aa4a..633b3f1 100644 --- a/src/quick/framelessquickwindow_p.h +++ b/src/quick/framelessquickwindow_p.h @@ -26,8 +26,10 @@ #include "framelesshelperquick_global.h" #include +#include QT_BEGIN_NAMESPACE +class QQuickItem; class QQuickRectangle; QT_END_NAMESPACE @@ -42,10 +44,22 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject Q_DISABLE_COPY_MOVE(FramelessQuickWindowPrivate) public: - explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q); + explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q, const Options options); ~FramelessQuickWindowPrivate() override; - Q_NODISCARD bool isZoomed() const; + Q_INVOKABLE Q_NODISCARD bool isZoomed() const; + Q_INVOKABLE Q_NODISCARD QColor getFrameBorderColor() const; + Q_INVOKABLE Q_NODISCARD bool isFrameBorderVisible() const; + +public Q_SLOTS: + void showMinimized2(); + void toggleMaximize(); + void toggleFullScreen(); + void showSystemMenu(const QPoint &pos); + void startSystemMove2(); + void startSystemResize2(const Qt::Edges edges); + void setTitleBarItem(QQuickItem *item); + void setHitTestVisible(QQuickItem *item); private: void initialize(); @@ -56,7 +70,10 @@ private Q_SLOTS: private: FramelessQuickWindow *q_ptr = nullptr; + bool m_initialized = false; QScopedPointer m_topBorderRectangle; + QWindow::Visibility m_savedVisibility = QWindow::Windowed; + Options m_options = {}; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/src/quick/qml/CloseButton.qml b/src/quick/qml/CloseButton.qml index 2fd1c6b..524e879 100644 --- a/src/quick/qml/CloseButton.qml +++ b/src/quick/qml/CloseButton.qml @@ -36,7 +36,7 @@ Button { Image { anchors.centerIn: parent - source: (FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible) + source: (FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorized) ? "image://framelesshelper/dark/close" : "image://framelesshelper/light/close" } } diff --git a/src/quick/qml/MaximizeButton.qml b/src/quick/qml/MaximizeButton.qml index 33ddfc1..259d6e3 100644 --- a/src/quick/qml/MaximizeButton.qml +++ b/src/quick/qml/MaximizeButton.qml @@ -39,9 +39,9 @@ Button { Image { anchors.centerIn: parent source: button.maximized ? - ((FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible) + ((FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorized) ? "image://framelesshelper/dark/restore" : "image://framelesshelper/light/restore") : - ((FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible) + ((FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorized) ? "image://framelesshelper/dark/maximize" : "image://framelesshelper/light/maximize") } } diff --git a/src/quick/qml/MinimizeButton.qml b/src/quick/qml/MinimizeButton.qml index 6e53e98..b24af7c 100644 --- a/src/quick/qml/MinimizeButton.qml +++ b/src/quick/qml/MinimizeButton.qml @@ -36,7 +36,7 @@ Button { Image { anchors.centerIn: parent - source: (FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible) + source: (FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorized) ? "image://framelesshelper/dark/minimize" : "image://framelesshelper/light/minimize" } } diff --git a/src/quick/qml/StandardTitleBar.qml b/src/quick/qml/StandardTitleBar.qml index 8d22071..bac013a 100644 --- a/src/quick/qml/StandardTitleBar.qml +++ b/src/quick/qml/StandardTitleBar.qml @@ -36,7 +36,7 @@ Rectangle { id: titleBar height: FramelessUtils.titleBarHeight - color: titleBar.active ? (FramelessUtils.titleBarColorVisible ? FramelessUtils.systemAccentColor + color: titleBar.active ? (FramelessUtils.titleBarColorized ? FramelessUtils.systemAccentColor : (FramelessUtils.darkModeEnabled ? "black" : "white")) : (FramelessUtils.darkModeEnabled ? FramelessUtils.defaultSystemDarkColor : "white") @@ -44,7 +44,7 @@ Rectangle { id: windowTitleLabel font.pointSize: 11 color: titleBar.active ? ((FramelessUtils.darkModeEnabled - || FramelessUtils.titleBarColorVisible) ? "white" : "black") : "darkGray" + || FramelessUtils.titleBarColorized) ? "white" : "black") : "darkGray" anchors { left: parent.left leftMargin: 10 diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index 3be8b3e..f5bbea1 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -41,7 +41,7 @@ target_compile_definitions(${SUB_PROJ_NAME} PRIVATE if(MSVC) target_compile_options(${SUB_PROJ_NAME} PRIVATE - /W4 /WX + /utf-8 /W4 /WX ) else() target_compile_options(${SUB_PROJ_NAME} PRIVATE diff --git a/src/widgets/framelessmainwindow.cpp b/src/widgets/framelessmainwindow.cpp index 8ffa28a..b7a479c 100644 --- a/src/widgets/framelessmainwindow.cpp +++ b/src/widgets/framelessmainwindow.cpp @@ -54,9 +54,9 @@ QWidget *FramelessMainWindow::titleBarWidget() const return m_helper->titleBarWidget(); } -void FramelessMainWindow::setHitTestVisible(QWidget *widget, const bool visible) +void FramelessMainWindow::setHitTestVisible(QWidget *widget) { - m_helper->setHitTestVisible(widget, visible); + m_helper->setHitTestVisible(widget); } void FramelessMainWindow::toggleMaximized() @@ -64,6 +64,11 @@ void FramelessMainWindow::toggleMaximized() m_helper->toggleMaximized(); } +void FramelessMainWindow::toggleFullScreen() +{ + m_helper->toggleFullScreen(); +} + void FramelessMainWindow::changeEvent(QEvent *event) { QMainWindow::changeEvent(event); diff --git a/src/widgets/framelesswidget.cpp b/src/widgets/framelesswidget.cpp index 2214288..2a34bfd 100644 --- a/src/widgets/framelesswidget.cpp +++ b/src/widgets/framelesswidget.cpp @@ -64,9 +64,9 @@ QWidget *FramelessWidget::contentWidget() const return m_helper->contentWidget(); } -void FramelessWidget::setHitTestVisible(QWidget *widget, const bool visible) +void FramelessWidget::setHitTestVisible(QWidget *widget) { - m_helper->setHitTestVisible(widget, visible); + m_helper->setHitTestVisible(widget); } void FramelessWidget::toggleMaximized() @@ -74,6 +74,11 @@ void FramelessWidget::toggleMaximized() m_helper->toggleMaximized(); } +void FramelessWidget::toggleFullScreen() +{ + m_helper->toggleFullScreen(); +} + void FramelessWidget::changeEvent(QEvent *event) { QWidget::changeEvent(event); diff --git a/src/widgets/framelesswidgetshelper.cpp b/src/widgets/framelesswidgetshelper.cpp index 7799a21..96b2eb0 100644 --- a/src/widgets/framelesswidgetshelper.cpp +++ b/src/widgets/framelesswidgetshelper.cpp @@ -73,7 +73,7 @@ bool FramelessWidgetsHelper::isNormal() const bool FramelessWidgetsHelper::isZoomed() const { - return (q->isMaximized() || q->isFullScreen()); + return (q->isMaximized() || ((m_options & Option::DontTreatFullScreenAsZoomed) ? false : q->isFullScreen())); } void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget) @@ -133,17 +133,18 @@ QWidget *FramelessWidgetsHelper::contentWidget() const return m_userContentWidget; } -void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visible) +void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget) { Q_ASSERT(widget); if (!widget) { return; } + static constexpr const bool visible = true; const bool exists = m_hitTestVisibleWidgets.contains(widget); if (visible && !exists) { m_hitTestVisibleWidgets.append(widget); } - if (!visible && exists) { + if constexpr (!visible && exists) { m_hitTestVisibleWidgets.removeAll(widget); } } @@ -218,7 +219,7 @@ void FramelessWidgetsHelper::mousePressEventHandler(QMouseEvent *event) if (!isInTitleBarDraggableArea(scenePos)) { return; } - Utils::startSystemMove(q->windowHandle()); + Utils::startSystemMove(m_window); } void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event) @@ -251,7 +252,7 @@ void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event) const QPoint globalPos = event->globalPos(); # endif const QPoint nativePos = QPointF(QPointF(globalPos) * q->devicePixelRatioF()).toPoint(); - Utils::showSystemMenu(q->windowHandle(), nativePos); + Utils::showSystemMenu(m_window, nativePos); #endif } @@ -261,7 +262,7 @@ void FramelessWidgetsHelper::mouseDoubleClickEventHandler(QMouseEvent *event) if (!event) { return; } - if ((m_options & Option::NoDoubleClickMaximizeToggle) || (m_options & Option::DisableResizing)) { + if ((m_options & Option::NoDoubleClickMaximizeToggle) || Utils::isWindowFixedSize(m_window)) { return; } if (event->button() != Qt::LeftButton) { @@ -295,12 +296,12 @@ void FramelessWidgetsHelper::initialize() // Force the widget become a native window now so that we can deal with its // win32 events as soon as possible. q->setAttribute(Qt::WA_NativeWindow); - QWindow * const window = q->windowHandle(); - Q_ASSERT(window); - if (!window) { + m_window = q->windowHandle(); + Q_ASSERT(m_window); + if (!m_window) { return; } - window->setProperty(kInternalOptionsFlag, QVariant::fromValue(m_options)); + m_window->setProperty(kInternalOptionsFlag, QVariant::fromValue(m_options)); if (m_options & Option::UseStandardWindowLayout) { if (q->inherits(QT_MAINWINDOW_CLASS_NAME)) { m_options &= ~Options(Option::UseStandardWindowLayout); @@ -315,7 +316,7 @@ void FramelessWidgetsHelper::initialize() true); } FramelessWindowsManager *manager = FramelessWindowsManager::instance(); - manager->addWindow(window); + manager->addWindow(m_window); connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this](){ if (m_options & Option::UseStandardWindowLayout) { updateSystemTitleBarStyleSheet(); @@ -327,12 +328,11 @@ void FramelessWidgetsHelper::initialize() setupInitialUi(); if (!(m_options & Option::DontMoveWindowToDesktopCenter)) { Utils::moveWindowToDesktopCenter( - [this, window]() -> QScreen * { + [this]() -> QScreen * { #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) - Q_UNUSED(window); return q->screen(); #else - return window->screen(); + return m_window->screen(); #endif }, [this]() -> QSize { return q->size(); }, @@ -525,7 +525,7 @@ void FramelessWidgetsHelper::updateSystemButtonsIcon() void FramelessWidgetsHelper::toggleMaximized() { - if (m_options & Option::DisableResizing) { + if (Utils::isWindowFixedSize(m_window)) { return; } if (isZoomed()) { @@ -535,4 +535,18 @@ void FramelessWidgetsHelper::toggleMaximized() } } +void FramelessWidgetsHelper::toggleFullScreen() +{ + if (Utils::isWindowFixedSize(m_window)) { + return; + } + const Qt::WindowStates windowState = q->windowState(); + if (windowState & Qt::WindowFullScreen) { + q->setWindowState(m_savedWindowState); + } else { + m_savedWindowState = windowState; + q->showFullScreen(); + } +} + FRAMELESSHELPER_END_NAMESPACE