diff --git a/include/FramelessHelper/Quick/FramelessQuickWindow b/include/FramelessHelper/Quick/FramelessQuickWindow new file mode 100644 index 0000000..06e08be --- /dev/null +++ b/include/FramelessHelper/Quick/FramelessQuickWindow @@ -0,0 +1 @@ +#include diff --git a/include/FramelessHelper/Quick/framelessquickwindow.h b/include/FramelessHelper/Quick/framelessquickwindow.h new file mode 100644 index 0000000..2baf6b1 --- /dev/null +++ b/include/FramelessHelper/Quick/framelessquickwindow.h @@ -0,0 +1,85 @@ +/* + * MIT License + * + * Copyright (C) 2022 by wangwenx190 (Yuhang Zhao) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include "framelesshelperquick_global.h" +#include +#include + +FRAMELESSHELPER_BEGIN_NAMESPACE + +class FramelessQuickWindowPrivate; + +class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow, public QQmlParserStatus +{ + Q_OBJECT +#ifdef QML_NAMED_ELEMENT + QML_NAMED_ELEMENT(FramelessWindow) +#endif + Q_DECLARE_PRIVATE(FramelessQuickWindow) + Q_DISABLE_COPY_MOVE(FramelessQuickWindow) + Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL) + Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL) + Q_PROPERTY(bool minimized READ isMinimized NOTIFY minimizedChanged FINAL) + Q_PROPERTY(bool maximized READ isMaximized NOTIFY maximizedChanged FINAL) + Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL) + Q_PROPERTY(bool fullScreen READ isFullScreen NOTIFY fullScreenChanged FINAL) + +public: + explicit FramelessQuickWindow(QWindow *parent = nullptr); + ~FramelessQuickWindow() override; + + Q_NODISCARD bool isHidden() const; + Q_NODISCARD bool isNormal() const; + Q_NODISCARD bool isMinimized() const; + Q_NODISCARD bool isMaximized() const; + Q_NODISCARD bool isZoomed() const; + Q_NODISCARD bool isFullScreen() const; + +public Q_SLOTS: + void showMinimized2(); + void toggleMaximized(); + void toggleFullScreen(); + +protected: + void classBegin() override; + void componentComplete() override; + +Q_SIGNALS: + void hiddenChanged(); + void normalChanged(); + void minimizedChanged(); + void maximizedChanged(); + void zoomedChanged(); + void fullScreenChanged(); + +private: + QScopedPointer d_ptr; +}; + +FRAMELESSHELPER_END_NAMESPACE + +Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindow)) +QML_DECLARE_TYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindow)) diff --git a/include/FramelessHelper/Quick/private/framelessquickwindow_p.h b/include/FramelessHelper/Quick/private/framelessquickwindow_p.h index 2baf6b1..c97a4d9 100644 --- a/include/FramelessHelper/Quick/private/framelessquickwindow_p.h +++ b/include/FramelessHelper/Quick/private/framelessquickwindow_p.h @@ -25,61 +25,46 @@ #pragma once #include "framelesshelperquick_global.h" -#include -#include +#include "framelessquickwindow.h" FRAMELESSHELPER_BEGIN_NAMESPACE -class FramelessQuickWindowPrivate; +class QuickWindowBorder; -class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow, public QQmlParserStatus +class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject { Q_OBJECT -#ifdef QML_NAMED_ELEMENT - QML_NAMED_ELEMENT(FramelessWindow) -#endif - Q_DECLARE_PRIVATE(FramelessQuickWindow) - Q_DISABLE_COPY_MOVE(FramelessQuickWindow) - Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL) - Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL) - Q_PROPERTY(bool minimized READ isMinimized NOTIFY minimizedChanged FINAL) - Q_PROPERTY(bool maximized READ isMaximized NOTIFY maximizedChanged FINAL) - Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL) - Q_PROPERTY(bool fullScreen READ isFullScreen NOTIFY fullScreenChanged FINAL) + Q_DECLARE_PUBLIC(FramelessQuickWindow) + Q_DISABLE_COPY_MOVE(FramelessQuickWindowPrivate) public: - explicit FramelessQuickWindow(QWindow *parent = nullptr); - ~FramelessQuickWindow() override; + explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q); + ~FramelessQuickWindowPrivate() override; - Q_NODISCARD bool isHidden() const; - Q_NODISCARD bool isNormal() const; - Q_NODISCARD bool isMinimized() const; - Q_NODISCARD bool isMaximized() const; - Q_NODISCARD bool isZoomed() const; - Q_NODISCARD bool isFullScreen() const; + Q_NODISCARD static FramelessQuickWindowPrivate *get(FramelessQuickWindow *pub); + Q_NODISCARD static const FramelessQuickWindowPrivate *get(const FramelessQuickWindow *pub); + + Q_INVOKABLE Q_NODISCARD bool isHidden() const; + Q_INVOKABLE Q_NODISCARD bool isNormal() const; + Q_INVOKABLE Q_NODISCARD bool isMinimized() const; + Q_INVOKABLE Q_NODISCARD bool isMaximized() const; + Q_INVOKABLE Q_NODISCARD bool isZoomed() const; + Q_INVOKABLE Q_NODISCARD bool isFullScreen() const; public Q_SLOTS: void showMinimized2(); void toggleMaximized(); void toggleFullScreen(); -protected: - void classBegin() override; - void componentComplete() override; - -Q_SIGNALS: - void hiddenChanged(); - void normalChanged(); - void minimizedChanged(); - void maximizedChanged(); - void zoomedChanged(); - void fullScreenChanged(); +private: + void initialize(); private: - QScopedPointer d_ptr; + QPointer q_ptr = nullptr; + QScopedPointer m_windowBorder; + QQuickWindow::Visibility m_savedVisibility = QQuickWindow::Windowed; }; FRAMELESSHELPER_END_NAMESPACE -Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindow)) -QML_DECLARE_TYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindow)) +Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindowPrivate)) diff --git a/include/FramelessHelper/Quick/private/framelessquickwindow_p_p.h b/include/FramelessHelper/Quick/private/framelessquickwindow_p_p.h deleted file mode 100644 index 0b543c3..0000000 --- a/include/FramelessHelper/Quick/private/framelessquickwindow_p_p.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * MIT License - * - * Copyright (C) 2022 by wangwenx190 (Yuhang Zhao) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#pragma once - -#include "framelesshelperquick_global.h" -#include "framelessquickwindow_p.h" - -FRAMELESSHELPER_BEGIN_NAMESPACE - -class QuickWindowBorder; - -class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject -{ - Q_OBJECT - Q_DECLARE_PUBLIC(FramelessQuickWindow) - Q_DISABLE_COPY_MOVE(FramelessQuickWindowPrivate) - -public: - explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q); - ~FramelessQuickWindowPrivate() override; - - Q_NODISCARD static FramelessQuickWindowPrivate *get(FramelessQuickWindow *pub); - Q_NODISCARD static const FramelessQuickWindowPrivate *get(const FramelessQuickWindow *pub); - - Q_INVOKABLE Q_NODISCARD bool isHidden() const; - Q_INVOKABLE Q_NODISCARD bool isNormal() const; - Q_INVOKABLE Q_NODISCARD bool isMinimized() const; - Q_INVOKABLE Q_NODISCARD bool isMaximized() const; - Q_INVOKABLE Q_NODISCARD bool isZoomed() const; - Q_INVOKABLE Q_NODISCARD bool isFullScreen() const; - -public Q_SLOTS: - void showMinimized2(); - void toggleMaximized(); - void toggleFullScreen(); - -private: - void initialize(); - Q_NODISCARD bool shouldDrawFrameBorder() const; - -private Q_SLOTS: - void updateWindowBorderVisibility(); - -private: - QPointer q_ptr = nullptr; - QScopedPointer m_windowBorder; - QQuickWindow::Visibility m_savedVisibility = QQuickWindow::Windowed; -}; - -FRAMELESSHELPER_END_NAMESPACE - -Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindowPrivate)) diff --git a/include/FramelessHelper/Quick/private/quickwindowborder_p.h b/include/FramelessHelper/Quick/private/quickwindowborder_p.h index b713a61..43fe579 100644 --- a/include/FramelessHelper/Quick/private/quickwindowborder_p.h +++ b/include/FramelessHelper/Quick/private/quickwindowborder_p.h @@ -46,12 +46,18 @@ public: void paint(QPainter *painter) const; +public Q_SLOTS: + void update(); + private: void initialize(); + void rebindWindow(); private: QPointer q_ptr = nullptr; QScopedPointer m_borderPainter; + QMetaObject::Connection m_activeChangeConnection = {}; + QMetaObject::Connection m_visibilityChangeConnection = {}; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Quick/quickwindowborder.h b/include/FramelessHelper/Quick/quickwindowborder.h index 1af0a0b..4028792 100644 --- a/include/FramelessHelper/Quick/quickwindowborder.h +++ b/include/FramelessHelper/Quick/quickwindowborder.h @@ -75,6 +75,7 @@ public Q_SLOTS: void setInactiveColor(const QColor &value); protected: + void itemChange(const ItemChange change, const ItemChangeData &value) override; void classBegin() override; void componentComplete() override; diff --git a/qmake/quick.pri b/qmake/quick.pri index 76f24d5..8dd6c68 100644 --- a/qmake/quick.pri +++ b/qmake/quick.pri @@ -27,11 +27,11 @@ HEADERS += \ $$QUICK_PUB_INC_DIR/quickmicamaterial.h \ $$QUICK_PUB_INC_DIR/quickimageitem.h \ $$QUICK_PUB_INC_DIR/quickwindowborder.h \ + $$QUICK_PUB_INC_DIR/framelessquickwindow.h \ $$QUICK_PRIV_INC_DIR/quickstandardsystembutton_p.h \ $$QUICK_PRIV_INC_DIR/quickstandardtitlebar_p.h \ $$QUICK_PRIV_INC_DIR/framelessquickhelper_p.h \ $$QUICK_PRIV_INC_DIR/framelessquickwindow_p.h \ - $$QUICK_PRIV_INC_DIR/framelessquickwindow_p_p.h \ $$QUICK_PRIV_INC_DIR/quickmicamaterial_p.h \ $$QUICK_PRIV_INC_DIR/quickimageitem_p.h \ $$QUICK_PRIV_INC_DIR/quickwindowborder_p.h diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 5114d6a..689018f 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -963,8 +963,15 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me const bool isFixedSize = data.params.isWindowFixedSize(); const bool dontOverrideCursor = data.params.getProperty(kDontOverrideCursorVar, false).toBool(); const bool dontToggleMaximize = data.params.getProperty(kDontToggleMaximizeVar, false).toBool(); - // To disable window maximization, you should remove the WS_MAXIMIZEBOX style from the window instead. - Q_UNUSED(dontToggleMaximize); + if (dontToggleMaximize) { + static bool once = false; + if (!once) { + once = true; + DEBUG << "To disable window maximization, you should remove the " + "WS_MAXIMIZEBOX style from the window instead. FramelessHelper " + "won't do that for you, so you'll have to do it manually yourself."; + } + } if (frameBorderVisible) { // This will handle the left, right and bottom parts of the frame // because we didn't change them. diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt index 7cc9cd0..e28df29 100644 --- a/src/quick/CMakeLists.txt +++ b/src/quick/CMakeLists.txt @@ -40,6 +40,7 @@ set(PUBLIC_HEADERS ${INCLUDE_PREFIX}/quickmicamaterial.h ${INCLUDE_PREFIX}/quickimageitem.h ${INCLUDE_PREFIX}/quickwindowborder.h + ${INCLUDE_PREFIX}/framelessquickwindow.h ) set(PUBLIC_HEADERS_ALIAS @@ -51,6 +52,7 @@ set(PUBLIC_HEADERS_ALIAS ${INCLUDE_PREFIX}/QuickMicaMaterial ${INCLUDE_PREFIX}/QuickImageItem ${INCLUDE_PREFIX}/QuickWindowBorder + ${INCLUDE_PREFIX}/FramelessQuickWindow ) set(PRIVATE_HEADERS @@ -58,7 +60,6 @@ set(PRIVATE_HEADERS ${INCLUDE_PREFIX}/private/quickstandardtitlebar_p.h ${INCLUDE_PREFIX}/private/framelessquickhelper_p.h ${INCLUDE_PREFIX}/private/framelessquickwindow_p.h - ${INCLUDE_PREFIX}/private/framelessquickwindow_p_p.h ${INCLUDE_PREFIX}/private/quickmicamaterial_p.h ${INCLUDE_PREFIX}/private/quickimageitem_p.h ${INCLUDE_PREFIX}/private/quickwindowborder_p.h diff --git a/src/quick/framelesshelperquick_global.cpp b/src/quick/framelesshelperquick_global.cpp index 6a54f7d..0d799d5 100644 --- a/src/quick/framelesshelperquick_global.cpp +++ b/src/quick/framelesshelperquick_global.cpp @@ -30,8 +30,8 @@ # include "quickchromepalette.h" # include "quickstandardsystembutton_p.h" # include "quickstandardtitlebar_p.h" +# include "framelessquickwindow.h" # include "framelessquickwindow_p.h" -# include "framelessquickwindow_p_p.h" # include "quickmicamaterial.h" # include "quickmicamaterial_p.h" # include "quickimageitem.h" diff --git a/src/quick/framelessquickmodule.cpp b/src/quick/framelessquickmodule.cpp index aa7c175..6d866d5 100644 --- a/src/quick/framelessquickmodule.cpp +++ b/src/quick/framelessquickmodule.cpp @@ -29,7 +29,7 @@ #include "quickmicamaterial.h" #include "quickimageitem.h" #include "quickwindowborder.h" -#include "framelessquickwindow_p.h" +#include "framelessquickwindow.h" #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) # include "quickstandardsystembutton_p.h" # include "quickstandardtitlebar_p.h" diff --git a/src/quick/framelessquickwindow.cpp b/src/quick/framelessquickwindow.cpp index 594a51d..c41ea20 100644 --- a/src/quick/framelessquickwindow.cpp +++ b/src/quick/framelessquickwindow.cpp @@ -22,16 +22,12 @@ * SOFTWARE. */ +#include "framelessquickwindow.h" #include "framelessquickwindow_p.h" -#include "framelessquickwindow_p_p.h" #include "framelessquickhelper.h" #include "quickwindowborder.h" #include #include -#include -#ifdef Q_OS_WINDOWS -# include -#endif FRAMELESSHELPER_BEGIN_NAMESPACE @@ -154,8 +150,7 @@ void FramelessQuickWindowPrivate::initialize() m_windowBorder->setParentItem(rootItem); m_windowBorder->setZ(999); // Make sure it always stays on the top. QQuickItemPrivate::get(m_windowBorder.data())->anchors()->setFill(rootItem); - connect(q, &FramelessQuickWindow::visibilityChanged, this, [this, q](){ - updateWindowBorderVisibility(); + connect(q, &FramelessQuickWindow::visibilityChanged, q, [q](){ Q_EMIT q->hiddenChanged(); Q_EMIT q->normalChanged(); Q_EMIT q->minimizedChanged(); @@ -163,27 +158,6 @@ void FramelessQuickWindowPrivate::initialize() Q_EMIT q->zoomedChanged(); Q_EMIT q->fullScreenChanged(); }); - connect(q, &FramelessQuickWindow::activeChanged, - m_windowBorder.data(), [this](){ m_windowBorder->update(); }); - updateWindowBorderVisibility(); -} - -bool FramelessQuickWindowPrivate::shouldDrawFrameBorder() const -{ -#ifdef Q_OS_WINDOWS - return (Utils::isWindowFrameBorderVisible() - && !WindowsVersionHelper::isWin11OrGreater() && isNormal()); -#else - return false; -#endif -} - -void FramelessQuickWindowPrivate::updateWindowBorderVisibility() -{ - if (m_windowBorder.isNull()) { - return; - } - m_windowBorder->setVisible(shouldDrawFrameBorder()); } FramelessQuickWindow::FramelessQuickWindow(QWindow *parent) diff --git a/src/quick/quickmicamaterial.cpp b/src/quick/quickmicamaterial.cpp index b660bf8..252c07e 100644 --- a/src/quick/quickmicamaterial.cpp +++ b/src/quick/quickmicamaterial.cpp @@ -181,10 +181,11 @@ void QuickMicaMaterialPrivate::initialize() void QuickMicaMaterialPrivate::rebindWindow() { Q_Q(QuickMicaMaterial); - QQuickWindow * const window = q->window(); + const QQuickWindow * const window = q->window(); if (!window) { return; } + q->setZ(-999); // Make sure we always stays on the bottom most place. if (m_rootWindowXChangedConnection) { disconnect(m_rootWindowXChangedConnection); m_rootWindowXChangedConnection = {}; diff --git a/src/quick/quickwindowborder.cpp b/src/quick/quickwindowborder.cpp index 6bc22a1..1a784fe 100644 --- a/src/quick/quickwindowborder.cpp +++ b/src/quick/quickwindowborder.cpp @@ -118,6 +118,17 @@ void QuickWindowBorderPrivate::paint(QPainter *painter) const m_borderPainter->paint(painter, size, (q->window() && q->window()->isActive())); } +void QuickWindowBorderPrivate::update() +{ + Q_Q(QuickWindowBorder); + const QQuickWindow * const window = q->window(); + if (!window) { + return; + } + q->update(); + q->setVisible(window->visibility() == QQuickWindow::Windowed); +} + void QuickWindowBorderPrivate::initialize() { Q_Q(QuickWindowBorder); @@ -141,6 +152,28 @@ void QuickWindowBorderPrivate::initialize() connect(m_borderPainter.data(), &WindowBorderPainter::shouldRepaint, q, [q](){ q->update(); }); } +void QuickWindowBorderPrivate::rebindWindow() +{ + Q_Q(QuickWindowBorder); + const QQuickWindow * const window = q->window(); + if (!window) { + return; + } + q->setZ(999); // Make sure we always stays on the top most place. + if (m_activeChangeConnection) { + disconnect(m_activeChangeConnection); + m_activeChangeConnection = {}; + } + if (m_visibilityChangeConnection) { + disconnect(m_visibilityChangeConnection); + m_visibilityChangeConnection = {}; + } + m_activeChangeConnection = connect(window, &QQuickWindow::activeChanged, + this, &QuickWindowBorderPrivate::update); + m_visibilityChangeConnection = connect(window, &QQuickWindow::visibilityChanged, + this, &QuickWindowBorderPrivate::update); +} + QuickWindowBorder::QuickWindowBorder(QQuickItem *parent) : QQuickPaintedItem(parent), d_ptr(new QuickWindowBorderPrivate(this)) { @@ -252,6 +285,15 @@ void QuickWindowBorder::setInactiveColor(const QColor &value) d->m_borderPainter->setInactiveColor(value); } +void QuickWindowBorder::itemChange(const ItemChange change, const ItemChangeData &value) +{ + QQuickPaintedItem::itemChange(change, value); + if ((change == ItemSceneChange) && value.window) { + Q_D(QuickWindowBorder); + d->rebindWindow(); + } +} + void QuickWindowBorder::classBegin() { QQuickPaintedItem::classBegin();