From 47d4edd38bad47dd926d9fa5fef975b6c5fdae4b Mon Sep 17 00:00:00 2001 From: deepin-ci-robot Date: Thu, 21 Nov 2024 13:42:06 +0000 Subject: [PATCH] sync: from linuxdeepin/dtkgui Synchronize source files from linuxdeepin/dtkgui. Source-pull-request: https://github.com/linuxdeepin/dtkgui/pull/275 --- src/kernel/dplatformhandle.cpp | 158 ++++++++++++++---- .../personalizationwaylandclientextension.cpp | 24 +++ .../personalizationwaylandclientextension.h | 2 + 3 files changed, 155 insertions(+), 29 deletions(-) diff --git a/src/kernel/dplatformhandle.cpp b/src/kernel/dplatformhandle.cpp index 94118c1..b3c367f 100644 --- a/src/kernel/dplatformhandle.cpp +++ b/src/kernel/dplatformhandle.cpp @@ -1,21 +1,29 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022-2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later +#define protected public +#include +#undef protected + #include "dguiapplicationhelper.h" #include "dplatformhandle.h" #include "dplatformtheme.h" #include "dwindowmanagerhelper.h" +#include "dvtablehook.h" #ifndef DTK_DISABLE_TREELAND #include "wayland/personalizationwaylandclientextension.h" #endif #include #include +#include -#include #include #include #include +#include + +DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE @@ -635,39 +643,123 @@ class Q_DECL_HIDDEN CreatorWindowEventFilter : public QObject { } }; -// only for TreeLand -class Q_DECL_HIDDEN MoveWindowEventFilter : public QObject { - bool m_windowMoving = false; -public: - MoveWindowEventFilter(QObject *par= nullptr): QObject(par){} +class MoveWindowHelper : public QObject +{ public: - bool eventFilter(QObject *watched, QEvent *event) override { - if (auto *w = qobject_cast(watched); w) { - bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast(event)->buttons() == Qt::LeftButton; + explicit MoveWindowHelper(QWindow *w); + ~MoveWindowHelper(); - if (event->type() == QEvent::MouseButtonRelease) { - m_windowMoving = false; - } - if (event->type() == QEvent::MouseButtonPress) { - m_windowMoving = false; - } + static QHash mapped; - // FIXME: We need to check whether the event is accepted. - // Only when the upper control does not accept the event, - // the window should be moved through the window. - // But every event here has been accepted. I don't know what happened. - if (is_mouse_move && w->geometry().contains(static_cast(event)->globalPos())) { - if (!m_windowMoving) { - m_windowMoving = true; +private: + static bool windowEvent(QWindow *w, QEvent *event); + void updateEnableSystemMoveFromProperty(); - event->accept(); - static_cast(w->handle())->startSystemMove(); - } + QWindow *m_window; + bool m_windowMoving; + bool m_enableSystemMove; +}; + +QHash MoveWindowHelper::mapped; + +MoveWindowHelper::MoveWindowHelper(QWindow *window) + : QObject(window) + , m_window(window) +{ + mapped[window] = this; + updateEnableSystemMoveFromProperty(); +} + +MoveWindowHelper::~MoveWindowHelper() +{ + if (DVtableHook::hasVtable(m_window)) { + DVtableHook::resetVtable(m_window); + } + + mapped.remove(qobject_cast(parent())); +} + +void MoveWindowHelper::updateEnableSystemMoveFromProperty() +{ + if (!m_window) { + return; + } + const QVariant &v = m_window->property("_d_enableSystemMove"); + + m_enableSystemMove = !v.isValid() || v.toBool(); + + if (m_enableSystemMove) { + DVtableHook::overrideVfptrFun(m_window, &QWindow::event, &MoveWindowHelper::windowEvent); + } else if (DVtableHook::hasVtable(m_window)) { + DVtableHook::resetVfptrFun(m_window, &QWindow::event); + } +} + +bool MoveWindowHelper::windowEvent(QWindow *w, QEvent *event) +{ + MoveWindowHelper *self = mapped.value(w); + + if (!self) + return DVtableHook::callOriginalFun(w, &QWindow::event, event); + // m_window 的 event 被 override 以后,在 windowEvent 里面获取到的 this 就成 m_window 了, + // 而不是 DNoTitlebarWlWindowHelper,所以此处 windowEvent 改为 static 并传 self 进来 + { + static bool isTouchDown = false; + static QPointF touchBeginPosition; + if (event->type() == QEvent::TouchBegin) { + isTouchDown = true; + } + if (event->type() == QEvent::TouchEnd || event->type() == QEvent::MouseButtonRelease) { + isTouchDown = false; + } + if (isTouchDown && event->type() == QEvent::MouseButtonPress) { + touchBeginPosition = static_cast(event)->globalPos(); + } + // add some redundancy to distinguish trigger between system menu and system move + if (event->type() == QEvent::MouseMove) { + QPointF currentPos = static_cast(event)->globalPos(); + QPointF delta = touchBeginPosition - currentPos; + if (delta.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) { + return DVtableHook::callOriginalFun(w, &QWindow::event, event); } } - return QObject::eventFilter(watched, event); } -}; + + bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast(event)->buttons() == Qt::LeftButton; + + if (event->type() == QEvent::MouseButtonRelease) { + self->m_windowMoving = false; + } + + if (!DVtableHook::callOriginalFun(w, &QWindow::event, event)) + return false; + + // workaround for kwin: Qt receives no release event when kwin finishes MOVE operation, + // which makes app hang in windowMoving state. when a press happens, there's no sense of + // keeping the moving state, we can just reset ti back to normal. + if (event->type() == QEvent::MouseButtonPress) { + self->m_windowMoving = false; + } + + if (is_mouse_move && !event->isAccepted() + && w->geometry().contains(static_cast(event)->globalPos())) { + if (!self->m_windowMoving && self->m_enableSystemMove) { + self->m_windowMoving = true; + + event->accept(); + if (w && w->handle()) { +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + static_cast(w->handle())->startSystemMove(QCursor::pos()); +#else + static_cast(w->handle())->startSystemMove(); +#endif + } + } + } + + return true; +} + /*! \brief DPlatformHandle::setEnabledNoTitlebarForWindow. @@ -692,7 +784,9 @@ bool DPlatformHandle::setEnabledNoTitlebarForWindow(QWindow *window, bool enable #ifndef DTK_DISABLE_TREELAND if (window && DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { window->installEventFilter(new CreatorWindowEventFilter(window)); - window->installEventFilter(new MoveWindowEventFilter(window)); + if (MoveWindowHelper::mapped.value(window)) + return true; + Q_UNUSED(new MoveWindowHelper(window)) return true; } #endif @@ -1281,6 +1375,12 @@ void DPlatformHandle::setEnableSystemMove(bool enableSystemMove) void DPlatformHandle::setEnableBlurWindow(bool enableBlurWindow) { +#ifndef DTK_DISABLE_TREELAND + if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { + PersonalizationManager::instance()->setEnableBlurWindow(m_window, enableBlurWindow); + return; + } +#endif setWindowProperty(m_window, _enableBlurWindow, enableBlurWindow); } diff --git a/src/wayland/personalizationwaylandclientextension.cpp b/src/wayland/personalizationwaylandclientextension.cpp index f6b702c..9e98973 100644 --- a/src/wayland/personalizationwaylandclientextension.cpp +++ b/src/wayland/personalizationwaylandclientextension.cpp @@ -36,6 +36,13 @@ PersonalizationManager::PersonalizationManager() if (!m_isSupported) { qWarning() << "PersonalizationManager is not support"; } + + connect(this, &PersonalizationManager::activeChanged, this, [this] () { + for (auto window: m_pendingEnableBlurWindows.keys()) { + setEnableBlurWindow(window, m_pendingEnableBlurWindows[window]); + } + m_pendingEnableBlurWindows.clear(); + }); } PersonalizationManager::~PersonalizationManager() @@ -139,6 +146,23 @@ void PersonalizationManager::setEnableTitleBar(QWindow *window, bool enable) windowContext->setEnableTitleBar(enable); } +void PersonalizationManager::setEnableBlurWindow(QWindow *window, bool enable) +{ + if (!isActive()) { + m_pendingEnableBlurWindows[window] = enable; + connect(window, &QWindow::destroyed, this, [=] { + m_pendingEnableBlurWindows.remove(window); + }); + return; + } + auto windowContext = getWindowContext(window); + if (!windowContext) { + qWarning() << "windowContext is nullptr!"; + return; + } + windowContext->set_blend_mode(enable ? PersonalizationWindowContext::blend_mode_blur : PersonalizationWindowContext::blend_mode_transparent); +} + PersonalizationWindowContext::PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context) : QWaylandClientExtensionTemplate(treeland_personalization_window_context_v1_interface.version) , QtWayland::treeland_personalization_window_context_v1(context) diff --git a/src/wayland/personalizationwaylandclientextension.h b/src/wayland/personalizationwaylandclientextension.h index 74858d0..c564828 100644 --- a/src/wayland/personalizationwaylandclientextension.h +++ b/src/wayland/personalizationwaylandclientextension.h @@ -24,6 +24,7 @@ class PersonalizationManager: public QWaylandClientExtensionTemplate m_pendingEnableBlurWindows; static void handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version);