From ee92e3d89429d71e97b1ddee472b9ccaa22cffc2 Mon Sep 17 00:00:00 2001 From: Zhao Yuhang <2546789017@qq.com> Date: Sat, 23 Sep 2023 22:06:37 +0800 Subject: [PATCH] wip --- include/FramelessHelper/Core/chromepalette.h | 2 +- .../FramelessHelper/Core/framelesshelper_qt.h | 9 +- .../FramelessHelper/Core/framelessmanager.h | 2 +- include/FramelessHelper/Core/micamaterial.h | 2 +- .../Core/windowborderpainter.h | 2 +- .../Quick/framelessquickhelper.h | 2 +- .../framelessquickapplicationwindow_p.h | 2 +- .../Quick/private/framelessquickwindow_p.h | 2 +- .../FramelessHelper/Quick/quickmicamaterial.h | 2 +- .../FramelessHelper/Quick/quickwindowborder.h | 2 +- .../FramelessHelper/Widgets/framelessdialog.h | 2 +- .../Widgets/framelessmainwindow.h | 2 +- .../FramelessHelper/Widgets/framelesswidget.h | 2 +- .../Widgets/framelesswidgetshelper.h | 2 +- .../Widgets/standardsystembutton.h | 2 +- .../Widgets/standardtitlebar.h | 2 +- src/core/framelesshelper_qt.cpp | 138 +++++++++++++----- src/core/framelessmanager.cpp | 7 + src/core/utils_win.cpp | 2 + 19 files changed, 133 insertions(+), 53 deletions(-) diff --git a/include/FramelessHelper/Core/chromepalette.h b/include/FramelessHelper/Core/chromepalette.h index 9e5d382..e8674c2 100644 --- a/include/FramelessHelper/Core/chromepalette.h +++ b/include/FramelessHelper/Core/chromepalette.h @@ -122,7 +122,7 @@ Q_SIGNALS: void chromeButtonColorChanged(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Core/framelesshelper_qt.h b/include/FramelessHelper/Core/framelesshelper_qt.h index 211419b..b8550ca 100644 --- a/include/FramelessHelper/Core/framelesshelper_qt.h +++ b/include/FramelessHelper/Core/framelesshelper_qt.h @@ -30,21 +30,26 @@ FRAMELESSHELPER_BEGIN_NAMESPACE +class FramelessHelperQtPrivate; class FRAMELESSHELPER_CORE_API FramelessHelperQt : public QObject { Q_OBJECT FRAMELESSHELPER_CLASS_INFO Q_DISABLE_COPY_MOVE(FramelessHelperQt) + Q_DECLARE_PRIVATE(FramelessHelperQt) public: explicit FramelessHelperQt(QObject *parent = nullptr); ~FramelessHelperQt() override; - static void addWindow(const QWindow *window); - static void removeWindow(const QWindow *window); + static void addWindow(const QObject *window); + static void removeWindow(const QObject *window); protected: Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override; + +private: + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Core/framelessmanager.h b/include/FramelessHelper/Core/framelessmanager.h index 2cacb1a..8344086 100644 --- a/include/FramelessHelper/Core/framelessmanager.h +++ b/include/FramelessHelper/Core/framelessmanager.h @@ -63,7 +63,7 @@ private: ~FramelessManager() override; private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Core/micamaterial.h b/include/FramelessHelper/Core/micamaterial.h index b1920a7..97c8cbc 100644 --- a/include/FramelessHelper/Core/micamaterial.h +++ b/include/FramelessHelper/Core/micamaterial.h @@ -82,7 +82,7 @@ Q_SIGNALS: void shouldRedraw(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Core/windowborderpainter.h b/include/FramelessHelper/Core/windowborderpainter.h index 8ce9fd4..024a162 100644 --- a/include/FramelessHelper/Core/windowborderpainter.h +++ b/include/FramelessHelper/Core/windowborderpainter.h @@ -79,7 +79,7 @@ Q_SIGNALS: void shouldRepaint(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Quick/framelessquickhelper.h b/include/FramelessHelper/Quick/framelessquickhelper.h index bf3ebc9..33c5ece 100644 --- a/include/FramelessHelper/Quick/framelessquickhelper.h +++ b/include/FramelessHelper/Quick/framelessquickhelper.h @@ -111,7 +111,7 @@ Q_SIGNALS: void ready(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Quick/private/framelessquickapplicationwindow_p.h b/include/FramelessHelper/Quick/private/framelessquickapplicationwindow_p.h index ae72529..3067f98 100644 --- a/include/FramelessHelper/Quick/private/framelessquickapplicationwindow_p.h +++ b/include/FramelessHelper/Quick/private/framelessquickapplicationwindow_p.h @@ -79,7 +79,7 @@ Q_SIGNALS: void fullScreenChanged(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Quick/private/framelessquickwindow_p.h b/include/FramelessHelper/Quick/private/framelessquickwindow_p.h index d0f8e64..ba0612e 100644 --- a/include/FramelessHelper/Quick/private/framelessquickwindow_p.h +++ b/include/FramelessHelper/Quick/private/framelessquickwindow_p.h @@ -79,7 +79,7 @@ Q_SIGNALS: void fullScreenChanged(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Quick/quickmicamaterial.h b/include/FramelessHelper/Quick/quickmicamaterial.h index f81d9fd..eaec15e 100644 --- a/include/FramelessHelper/Quick/quickmicamaterial.h +++ b/include/FramelessHelper/Quick/quickmicamaterial.h @@ -83,7 +83,7 @@ protected: void componentComplete() override; private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Quick/quickwindowborder.h b/include/FramelessHelper/Quick/quickwindowborder.h index edc7124..160f5d6 100644 --- a/include/FramelessHelper/Quick/quickwindowborder.h +++ b/include/FramelessHelper/Quick/quickwindowborder.h @@ -88,7 +88,7 @@ Q_SIGNALS: void nativeBorderChanged(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Widgets/framelessdialog.h b/include/FramelessHelper/Widgets/framelessdialog.h index 0c547b5..57050b3 100644 --- a/include/FramelessHelper/Widgets/framelessdialog.h +++ b/include/FramelessHelper/Widgets/framelessdialog.h @@ -45,7 +45,7 @@ public: ~FramelessDialog() override; private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Widgets/framelessmainwindow.h b/include/FramelessHelper/Widgets/framelessmainwindow.h index 5e4a52f..8e271be 100644 --- a/include/FramelessHelper/Widgets/framelessmainwindow.h +++ b/include/FramelessHelper/Widgets/framelessmainwindow.h @@ -60,7 +60,7 @@ Q_SIGNALS: void zoomedChanged(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Widgets/framelesswidget.h b/include/FramelessHelper/Widgets/framelesswidget.h index f9fb997..9430ff5 100644 --- a/include/FramelessHelper/Widgets/framelesswidget.h +++ b/include/FramelessHelper/Widgets/framelesswidget.h @@ -60,7 +60,7 @@ Q_SIGNALS: void zoomedChanged(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Widgets/framelesswidgetshelper.h b/include/FramelessHelper/Widgets/framelesswidgetshelper.h index 58128af..a935e49 100644 --- a/include/FramelessHelper/Widgets/framelesswidgetshelper.h +++ b/include/FramelessHelper/Widgets/framelesswidgetshelper.h @@ -98,7 +98,7 @@ Q_SIGNALS: void ready(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Widgets/standardsystembutton.h b/include/FramelessHelper/Widgets/standardsystembutton.h index cdaacd7..0fe939b 100644 --- a/include/FramelessHelper/Widgets/standardsystembutton.h +++ b/include/FramelessHelper/Widgets/standardsystembutton.h @@ -91,7 +91,7 @@ Q_SIGNALS: void glyphSizeChanged(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Widgets/standardtitlebar.h b/include/FramelessHelper/Widgets/standardtitlebar.h index 4ea1f49..4bfe213 100644 --- a/include/FramelessHelper/Widgets/standardtitlebar.h +++ b/include/FramelessHelper/Widgets/standardtitlebar.h @@ -106,7 +106,7 @@ Q_SIGNALS: void titleFontChanged(); private: - QScopedPointer d_ptr; + const QScopedPointer d_ptr; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/framelesshelper_qt.cpp b/src/core/framelesshelper_qt.cpp index fea2215..540981e 100644 --- a/src/core/framelesshelper_qt.cpp +++ b/src/core/framelesshelper_qt.cpp @@ -52,37 +52,83 @@ FRAMELESSHELPER_BEGIN_NAMESPACE using namespace Global; -using FramelessHelperQtPtr = std::shared_ptr; -#define CreateFramelessHelperQt(...) std::make_shared(__VA_ARGS__) - struct FramelessDataQt : public FramelessData { - FramelessHelperQtPtr eventFilter = nullptr; + FramelessHelperQt *eventFilter = nullptr; bool cursorShapeChanged = false; bool leftButtonPressed = false; + + FramelessDataQt(); + ~FramelessDataQt() override; }; using FramelessDataQtPtr = std::shared_ptr; -#define CreateFramelessDataQt(...) std::make_shared(__VA_ARGS__) -[[nodiscard]] FramelessDataQtPtr CreateEmptyDataQt() { return CreateFramelessDataQt(); } +class FramelessHelperQtPrivate : public QObject +{ + Q_OBJECT + FRAMELESSHELPER_CLASS_INFO + Q_DISABLE_COPY_MOVE(FramelessHelperQtPrivate) + Q_DECLARE_PUBLIC(FramelessHelperQt) -FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent) {} +public: + explicit FramelessHelperQtPrivate(FramelessHelperQt *q); + ~FramelessHelperQtPrivate() override; + + FramelessHelperQt *q_ptr = nullptr; + const QObject *window = nullptr; +}; + +[[nodiscard]] static inline FramelessDataQtPtr tryGetData(const QObject *window) +{ + Q_ASSERT(window); + if (!window) { + return nullptr; + } + const FramelessDataPtr data = FramelessManagerPrivate::getData(window); + if (!data) { + return nullptr; + } + return std::dynamic_pointer_cast(data); +} + +FramelessDataQt::FramelessDataQt() = default; + +FramelessDataQt::~FramelessDataQt() = default; + +[[nodiscard]] FramelessDataPtr FramelessData::create() +{ + return std::make_shared(); +} + +FramelessHelperQtPrivate::FramelessHelperQtPrivate(FramelessHelperQt *q) : QObject(q), q_ptr(q) +{ +} + +FramelessHelperQtPrivate::~FramelessHelperQtPrivate() = default; + +FramelessHelperQt::FramelessHelperQt(QObject *parent) : QObject(parent), d_ptr(new FramelessHelperQtPrivate(this)) +{ +} FramelessHelperQt::~FramelessHelperQt() = default; -void FramelessHelperQt::addWindow(const QWindow *window) +void FramelessHelperQt::addWindow(const QObject *window) { Q_ASSERT(window); if (!window) { return; } - const auto data = std::dynamic_pointer_cast(FramelessManagerPrivate::getData(window)); - Q_ASSERT(data->callbacks); - if (!data->callbacks) { + const FramelessDataQtPtr data = tryGetData(window); + if (!data || data->frameless || !data->callbacks) { return; } - data->eventFilter = CreateFramelessHelperQt(); - const auto shouldApplyFramelessFlag = []() -> bool { + QWindow *qWindow = data->callbacks->getWindowHandle(); + Q_ASSERT(qWindow); + if (!qWindow) { + return; + } + data->frameless = true; + static const auto shouldApplyFramelessFlag = []() -> bool { #ifdef Q_OS_MACOS return false; #elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) @@ -92,35 +138,46 @@ void FramelessHelperQt::addWindow(const QWindow *window) #endif // Q_OS_MACOS }(); #if (defined(Q_OS_MACOS) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))) - window->setProperty("_q_mac_wantsLayer", 1); + qWindow->setProperty("_q_mac_wantsLayer", 1); #endif // (defined(Q_OS_MACOS) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))) if (shouldApplyFramelessFlag) { data->callbacks->setWindowFlags(data->callbacks->getWindowFlags() | Qt::FramelessWindowHint); } else { #if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) - std::ignore = Utils::tryHideSystemTitleBar(window, true); + std::ignore = Utils::tryHideSystemTitleBar(data->callbacks->getWindowId(), true); #elif defined(Q_OS_MACOS) - Utils::setSystemTitleBarVisible(window, false); + Utils::setSystemTitleBarVisible(data->callbacks->getWindowId(), false); #endif // Q_OS_LINUX } - const_cast(window)->installEventFilter(data->eventFilter.get()); + if (!data->eventFilter) { + data->eventFilter = new FramelessHelperQt(data->window); + data->eventFilter->d_func()->window = window; + qWindow->installEventFilter(data->eventFilter); + } FramelessHelperEnableThemeAware(); } -void FramelessHelperQt::removeWindow(const QWindow *window) +void FramelessHelperQt::removeWindow(const QObject *window) { Q_ASSERT(window); if (!window) { return; } - const auto data = std::dynamic_pointer_cast(FramelessManagerPrivate::getData(window)); - Q_ASSERT(data->eventFilter); + const FramelessDataQtPtr data = tryGetData(window); + if (!data || !data->frameless || !data->callbacks) { + return; + } if (data->eventFilter) { - const_cast(window)->removeEventFilter(data->eventFilter.get()); - data->eventFilter = nullptr; + QWindow *qWindow = data->callbacks->getWindowHandle(); + Q_ASSERT(qWindow); + if (qWindow) { + qWindow->removeEventFilter(data->eventFilter); + delete data->eventFilter; + data->eventFilter = nullptr; + } } #ifdef Q_OS_MACOS - Utils::removeWindowProxy(window); + Utils::removeWindowProxy(data->callbacks->getWindowId()); #endif } @@ -131,22 +188,26 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) if (!object || !event) { return false; } + Q_D(FramelessHelperQt); + if (!d->window) { + return false; + } #if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) // First detect whether we got a theme change event or not, if so, // inform the user the system theme has changed. if (Utils::isThemeChangeEvent(event)) { // Sometimes the FramelessManager instance may be destroyed already. - if (FramelessManager * const manager = FramelessManager::instance()) { + if (FramelessManager *manager = FramelessManager::instance()) { if (FramelessManagerPrivate * const managerPriv = FramelessManagerPrivate::get(manager)) { managerPriv->notifySystemThemeHasChangedOrNot(); } } - return QObject::eventFilter(object, event); + return false; } #endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) - // We are only interested in events that are dispatched to top level windows. + // We are only interested in events that are dispatched to top level windows (not even top level widgets). if (!object->isWindowType()) { - return QObject::eventFilter(object, event); + return false; } const QEvent::Type type = event->type(); // We are only interested in some specific mouse events (plus DPR change event). @@ -158,10 +219,12 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) && (type != QEvent::ScreenChangeInternal) // Qt's internal event to notify screen change and DPR change. #endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) ) { - return QObject::eventFilter(object, event); + return false; + } + const FramelessDataQtPtr data = tryGetData(d->window); + if (!data || !data->frameless || !data->callbacks) { + return false; } - const auto window = qobject_cast(object); - const auto data = std::dynamic_pointer_cast(FramelessManagerPrivate::getData(window)); #if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) if (type == QEvent::DevicePixelRatioChange) #else // QT_VERSION < QT_VERSION_CHECK(6, 6, 0) @@ -169,8 +232,9 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) #endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) { data->callbacks->forceChildrenRepaint(500); - return QObject::eventFilter(object, event); + return false; } + const auto qWindow = qobject_cast(object); const auto mouseEvent = static_cast(event); const Qt::MouseButton button = mouseEvent->button(); #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) @@ -190,9 +254,9 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) if (button == Qt::LeftButton) { data->leftButtonPressed = true; if (!windowFixedSize) { - const Qt::Edges edges = Utils::calculateWindowEdges(window, scenePos); + const Qt::Edges edges = Utils::calculateWindowEdges(qWindow, scenePos); if (edges != Qt::Edges{}) { - std::ignore = Utils::startSystemResize(const_cast(window), edges, globalPos); + std::ignore = Utils::startSystemResize(qWindow, edges, globalPos); event->accept(); return true; } @@ -223,7 +287,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) break; case QEvent::MouseMove: { if (!dontOverrideCursor && !windowFixedSize) { - const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos); + const Qt::CursorShape cs = Utils::calculateCursorShape(qWindow, scenePos); if (cs == Qt::ArrowCursor) { if (data->cursorShapeChanged) { data->callbacks->unsetCursor(); @@ -236,7 +300,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) } if (data->leftButtonPressed) { if (!ignoreThisEvent && insideTitleBar) { - std::ignore = Utils::startSystemMove(const_cast(window), globalPos); + std::ignore = Utils::startSystemMove(qWindow, globalPos); event->accept(); return true; } @@ -245,9 +309,11 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event) default: break; } - return QObject::eventFilter(object, event); + return false; } FRAMELESSHELPER_END_NAMESPACE +#include "framelesshelper_qt.moc" + #endif // !native_impl diff --git a/src/core/framelessmanager.cpp b/src/core/framelessmanager.cpp index 21d2ebb..1524574 100644 --- a/src/core/framelessmanager.cpp +++ b/src/core/framelessmanager.cpp @@ -109,6 +109,7 @@ Q_GLOBAL_STATIC(InternalData, g_internalData) class InternalEventFilter : public QObject { Q_OBJECT + FRAMELESSHELPER_CLASS_INFO Q_DISABLE_COPY_MOVE(InternalEventFilter) public: @@ -512,6 +513,9 @@ bool FramelessManager::addWindow(const QObject *window, const WId windowId) # else # endif #else +# ifdef Q_OS_WINDOWS + std::ignore = Utils::installWindowProcHook(windowId); +# endif FramelessHelperQt::addWindow(window); #endif return true; @@ -549,6 +553,9 @@ bool FramelessManager::removeWindow(const QObject *window) # endif #else FramelessHelperQt::removeWindow(window); +# ifdef Q_OS_WINDOWS + std::ignore = Utils::uninstallWindowProcHook(data->windowId); +# endif #endif g_internalData()->dataMap.erase(it); g_internalData()->windowMap.remove(data->windowId); diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 014d551..97f0826 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -923,6 +923,7 @@ static constexpr const std::array g_win32MessageMap = if (!qWindow) { return defaultWindowProcessing(); } +#if FRAMELESSHELPER_CONFIG(native_impl) // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025 // We can see from the source code that Qt will filter out some messages first and then send the unfiltered // messages to the event dispatcher. To activate the Snap Layout feature on Windows 11, we must process @@ -971,6 +972,7 @@ static constexpr const std::array g_win32MessageMap = return LRESULT(filterResult); } } +#endif // native_impl const auto getNativePosFromMouse = [lParam]() -> QPoint { return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; };