From 44ab15baa5ffd2cd20fbd3e310b8b48a75dfdee9 Mon Sep 17 00:00:00 2001 From: justforlxz Date: Thu, 7 Dec 2023 14:33:01 +0800 Subject: [PATCH] fix: not responding to client requests on foreigntoplevel wrong signals Log: --- src/treeland/StackToplevelHelper.qml | 50 +++++++++- src/treeland/foreigntoplevelmanagerv1.cpp | 109 ++++++++++++++++++---- src/treeland/foreigntoplevelmanagerv1.h | 45 +++++++++ src/treeland/helper.cpp | 5 +- 4 files changed, 186 insertions(+), 23 deletions(-) diff --git a/src/treeland/StackToplevelHelper.qml b/src/treeland/StackToplevelHelper.qml index b1cead2d3..575e9b0dd 100644 --- a/src/treeland/StackToplevelHelper.qml +++ b/src/treeland/StackToplevelHelper.qml @@ -14,6 +14,7 @@ Item { required property ListModel dockModel required property DynamicCreatorComponent creator property WindowDecoration decoration + property var quickForeignToplevelManageMapper: waylandSurface.TreeLandForeignToplevelManagerV1 property OutputItem output property CoordMapper outputCoordMapper @@ -102,6 +103,51 @@ Item { } } + Connections { + target: quickForeignToplevelManageMapper + + function onRequestMaximize(maximized) { + if (maximized) { + connOfSurface.onRequestCancelMaximize() + } else { + connOfSurface.onRequestMaximize() + } + } + + function onRequestMinimize(minimized) { + if (minimized) { + connOfSurface.onRequestMinimize() + TreeLandHelper.activatedSurface = null + } else { + connOfSurface.onRequestCancelMinimize() + } + } + + function onRequestActivate(activated) { + if (activated && waylandSurface.isMinimized) { + cancelMinimize() + } + + surface.focus = activated + TreeLandHelper.activatedSurface = activated ? surface : null + } + + function onRequestFullscreen(fullscreen) { + // TODO: add full screen action + } + + function onRequestClose() { + if (waylandSurface.close) + waylandSurface.close() + else + waylandSurface.surface.unmap() + } + + function onRectangleChanged(edges) { + connOfSurface.onRequestResize(null, edges, null) + } + } + Connections { target: decoration @@ -305,8 +351,8 @@ Item { return surface.focus = false; - if (TreeLandHelper.activeSurface === surface) - TreeLandHelper.activeSurface = null; + if (TreeLandHelper.activatedSurface === surface) + TreeLandHelper.activatedSurface = null; surface.visible = false; dockModel.append({ source: surface }); diff --git a/src/treeland/foreigntoplevelmanagerv1.cpp b/src/treeland/foreigntoplevelmanagerv1.cpp index e7699fd92..e4eec4aaf 100644 --- a/src/treeland/foreigntoplevelmanagerv1.cpp +++ b/src/treeland/foreigntoplevelmanagerv1.cpp @@ -28,6 +28,57 @@ extern "C" { #undef static } +static QuickForeignToplevelManagerV1 *FOREIGN_TOPLEVEL_MANAGER = nullptr; + +QuickForeignToplevelManagerAttached::QuickForeignToplevelManagerAttached(WSurface *target, QuickForeignToplevelManagerV1 *manager) + : QObject(manager) + , m_target(target) + , m_manager(manager) +{ + connect(manager, &QuickForeignToplevelManagerV1::requestActivate, this, [this](WXdgSurface *surface, [[maybe_unused]] treeland_foreign_toplevel_handle_v1_activated_event *event) { + if (surface->surface() != m_target) { + return; + } + + Q_EMIT requestActivate(true); + }); + connect(manager, &QuickForeignToplevelManagerV1::requestMinimize, this, [this](WXdgSurface *surface, treeland_foreign_toplevel_handle_v1_minimized_event *event) { + if (surface->surface() != m_target) { + return; + } + + Q_EMIT requestMinimize(event->minimized); + }); + connect(manager, &QuickForeignToplevelManagerV1::requestMaximize, this, [this](WXdgSurface *surface, treeland_foreign_toplevel_handle_v1_maximized_event *event) { + if (surface->surface() != m_target) { + return; + } + + Q_EMIT requestMaximize(event->maximized); + }); + connect(manager, &QuickForeignToplevelManagerV1::requestFullscreen, this, [this](WXdgSurface *surface, treeland_foreign_toplevel_handle_v1_fullscreen_event *event) { + if (surface->surface() != m_target) { + return; + } + + Q_EMIT requestFullscreen(event->fullscreen); + }); + connect(manager, &QuickForeignToplevelManagerV1::requestClose, this, [this](WXdgSurface *surface) { + if (surface->surface() != m_target) { + return; + } + + Q_EMIT requestClose(); + }); + connect(manager, &QuickForeignToplevelManagerV1::rectangleChanged, this, [this](WXdgSurface *surface, treeland_foreign_toplevel_handle_v1_set_rectangle_event *event) { + if (surface->surface() != m_target) { + return; + } + + Q_EMIT rectangleChanged({event->x, event->y, event->width, event->height}); + }); +} + class QuickForeignToplevelManagerV1Private : public WObjectPrivate { public: QuickForeignToplevelManagerV1Private(QuickForeignToplevelManagerV1 *qq) @@ -44,14 +95,14 @@ class QuickForeignToplevelManagerV1Private : public WObjectPrivate { connection.push_back(QObject::connect(surface, &WXdgSurface::appIdChanged, q_func(), [=] { handle->setAppId(surface->appId().toUtf8()); })); - connection.push_back(QObject::connect(surface, &WXdgSurface::requestMinimize, q_func(), + connection.push_back(QObject::connect(surface, &WXdgSurface::minimizeChanged, q_func(), [=] { handle->setMinimized(surface->isMinimized()); })); - connection.push_back(QObject::connect(surface, &WXdgSurface::requestMaximize, q_func(), + connection.push_back(QObject::connect(surface, &WXdgSurface::maximizeChanged, q_func(), [=] { handle->setMaximized(surface->isMaximized()); })); connection.push_back(QObject::connect( - surface, &WXdgSurface::requestFullscreen, q_func(), + surface, &WXdgSurface::fullscreenChanged, q_func(), [=] { handle->setFullScreen(surface->isFullScreen()); })); connection.push_back(QObject::connect(surface, &WXdgSurface::activateChanged, q_func(), @@ -78,37 +129,37 @@ class QuickForeignToplevelManagerV1Private : public WObjectPrivate { connection.push_back(QObject::connect(handle.get(), &TreeLandForeignToplevelHandleV1::requestActivate, - surface, - [surface](treeland_foreign_toplevel_handle_v1_activated_event *event) { - surface->setActivate(event->toplevel->state & TREELAND_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED); + q_func(), + [surface, this, handle](treeland_foreign_toplevel_handle_v1_activated_event *event) { + Q_EMIT q_func()->requestActivate(surface, event); })); connection.push_back(QObject::connect(handle.get(), &TreeLandForeignToplevelHandleV1::requestMaximize, - surface, - [surface](treeland_foreign_toplevel_handle_v1_maximized_event *event) { - surface->setMaximize(event->maximized); + q_func(), + [surface, this](treeland_foreign_toplevel_handle_v1_maximized_event *event) { + Q_EMIT q_func()->requestMaximize(surface, event); })); connection.push_back(QObject::connect(handle.get(), &TreeLandForeignToplevelHandleV1::requestMinimize, - surface, - [surface](treeland_foreign_toplevel_handle_v1_minimized_event *event) { - surface->setMinimize(event->minimized); + q_func(), + [surface, this, handle](treeland_foreign_toplevel_handle_v1_minimized_event *event) { + Q_EMIT q_func()->requestMinimize(surface, event); })); connection.push_back(QObject::connect(handle.get(), &TreeLandForeignToplevelHandleV1::requestFullscreen, - surface, - [surface](treeland_foreign_toplevel_handle_v1_fullscreen_event *event) { - surface->setFullScreen(event->fullscreen); + q_func(), + [surface, this](treeland_foreign_toplevel_handle_v1_fullscreen_event *event) { + Q_EMIT q_func()->requestFullscreen(surface, event); })); connection.push_back(QObject::connect(handle.get(), &TreeLandForeignToplevelHandleV1::requestClose, - surface, - [surface] { - surface->handle()->topToplevel()->sendClose(); + q_func(), + [surface, this] { + Q_EMIT q_func()->requestClose(surface); })); wl_client *client = surface->handle()->handle()->resource->client; @@ -120,6 +171,10 @@ class QuickForeignToplevelManagerV1Private : public WObjectPrivate { Q_EMIT surface->titleChanged(); Q_EMIT surface->appIdChanged(); + Q_EMIT surface->minimizeChanged(); + Q_EMIT surface->maximizeChanged(); + Q_EMIT surface->fullscreenChanged(); + Q_EMIT surface->activateChanged(); connections.insert({surface, connection}); } @@ -158,7 +213,14 @@ class QuickForeignToplevelManagerV1Private : public WObjectPrivate { QuickForeignToplevelManagerV1::QuickForeignToplevelManagerV1(QObject *parent) : WQuickWaylandServerInterface(parent) - , WObject(*new QuickForeignToplevelManagerV1Private(this), nullptr) {} + , WObject(*new QuickForeignToplevelManagerV1Private(this), nullptr) +{ + if (FOREIGN_TOPLEVEL_MANAGER) { + qFatal("There are multiple instances of QuickForeignToplevelManagerV1"); + } + + FOREIGN_TOPLEVEL_MANAGER = this; +} void QuickForeignToplevelManagerV1::add(WXdgSurface *surface) { W_D(QuickForeignToplevelManagerV1); @@ -176,3 +238,12 @@ void QuickForeignToplevelManagerV1::create() { d->manager = TreeLandForeignToplevelManagerV1::create(server()->handle()); } + +QuickForeignToplevelManagerAttached *QuickForeignToplevelManagerV1::qmlAttachedProperties(QObject *target) +{ + if (auto *surface = qobject_cast(target)) { + return new QuickForeignToplevelManagerAttached(surface->surface(), FOREIGN_TOPLEVEL_MANAGER); + } + + return nullptr; +} diff --git a/src/treeland/foreigntoplevelmanagerv1.h b/src/treeland/foreigntoplevelmanagerv1.h index 52a52369c..558901220 100644 --- a/src/treeland/foreigntoplevelmanagerv1.h +++ b/src/treeland/foreigntoplevelmanagerv1.h @@ -15,6 +15,12 @@ #include #include +struct treeland_foreign_toplevel_handle_v1_maximized_event; +struct treeland_foreign_toplevel_handle_v1_minimized_event; +struct treeland_foreign_toplevel_handle_v1_activated_event; +struct treeland_foreign_toplevel_handle_v1_fullscreen_event; +struct treeland_foreign_toplevel_handle_v1_set_rectangle_event; + QW_USE_NAMESPACE WAYLIB_SERVER_USE_NAMESPACE @@ -54,12 +60,35 @@ class WXdgSurface; class WOutput; WAYLIB_SERVER_END_NAMESPACE +class QuickForeignToplevelManagerV1; +class QuickForeignToplevelManagerAttached : public QObject +{ + Q_OBJECT + QML_ANONYMOUS + +public: + QuickForeignToplevelManagerAttached(WSurface *target, QuickForeignToplevelManagerV1 *manager); + +Q_SIGNALS: + void requestMaximize(bool maximized); + void requestMinimize(bool minimized); + void requestActivate(bool activated); + void requestFullscreen(bool fullscreen); + void requestClose(); + void rectangleChanged(const QRect &rect); + +private: + WSurface *m_target; + QuickForeignToplevelManagerV1 *m_manager; +}; + class QuickForeignToplevelManagerV1Private; class QuickForeignToplevelManagerV1 : public WQuickWaylandServerInterface, public WObject { Q_OBJECT QML_NAMED_ELEMENT(TreeLandForeignToplevelManagerV1) W_DECLARE_PRIVATE(QuickForeignToplevelManagerV1) + QML_ATTACHED(QuickForeignToplevelManagerAttached) public: explicit QuickForeignToplevelManagerV1(QObject *parent = nullptr); @@ -67,6 +96,22 @@ class QuickForeignToplevelManagerV1 : public WQuickWaylandServerInterface, publi Q_INVOKABLE void add(WXdgSurface *surface); Q_INVOKABLE void remove(WXdgSurface *surface); + static QuickForeignToplevelManagerAttached *qmlAttachedProperties(QObject *target); + +Q_SIGNALS: + void requestMaximize(WXdgSurface *surface, treeland_foreign_toplevel_handle_v1_maximized_event *event); + void requestMinimize(WXdgSurface *surface, treeland_foreign_toplevel_handle_v1_minimized_event *event); + void requestActivate(WXdgSurface *surface, treeland_foreign_toplevel_handle_v1_activated_event *event); + void requestFullscreen(WXdgSurface *surface, treeland_foreign_toplevel_handle_v1_fullscreen_event *event); + void requestClose(WXdgSurface *surface); + void rectangleChanged(WXdgSurface *surface, treeland_foreign_toplevel_handle_v1_set_rectangle_event *event); + private: void create() override; }; + +Q_DECLARE_OPAQUE_POINTER(treeland_foreign_toplevel_handle_v1_maximized_event*); +Q_DECLARE_OPAQUE_POINTER(treeland_foreign_toplevel_handle_v1_minimized_event*); +Q_DECLARE_OPAQUE_POINTER(treeland_foreign_toplevel_handle_v1_activated_event*); +Q_DECLARE_OPAQUE_POINTER(treeland_foreign_toplevel_handle_v1_fullscreen_event*); +Q_DECLARE_OPAQUE_POINTER(treeland_foreign_toplevel_handle_v1_set_rectangle_event*); diff --git a/src/treeland/helper.cpp b/src/treeland/helper.cpp index c2ed64d9d..06661b015 100644 --- a/src/treeland/helper.cpp +++ b/src/treeland/helper.cpp @@ -410,11 +410,12 @@ WToplevelSurface *Helper::activatedSurface() const void Helper::setActivateSurface(WToplevelSurface *newActivate) { - if (newActivate && newActivate->doesNotAcceptFocus()) + if (m_activateSurface == newActivate) return; - if (m_activateSurface == newActivate) + if (newActivate && newActivate->doesNotAcceptFocus()) return; + if (m_activateSurface) { if (newActivate) { if (m_activateSurface->keyboardFocusPriority() > newActivate->keyboardFocusPriority())