From d548f4bce43489c26ccfeb4ccf68b73b89ba64db Mon Sep 17 00:00:00 2001 From: David Redondo Date: Mon, 7 Mar 2022 14:21:07 +0100 Subject: [PATCH] Implement plasma-surface open-under-cursor The surface is positioned at the current cursor location but kept in bounds to keep it fully visible when the cursor is near the screen border. --- src/wayland/plasmashell_interface.cpp | 16 ++++++++++++++++ src/wayland/plasmashell_interface.h | 11 +++++++++++ src/xdgshellwindow.cpp | 20 +++++++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/wayland/plasmashell_interface.cpp b/src/wayland/plasmashell_interface.cpp index 981dfc096b..f5cadfb579 100644 --- a/src/wayland/plasmashell_interface.cpp +++ b/src/wayland/plasmashell_interface.cpp @@ -46,6 +46,7 @@ public: bool m_skipTaskbar = false; bool m_skipSwitcher = false; bool m_panelTakesFocus = false; + bool m_openUnderCursorRequested = false; private: void org_kde_plasma_surface_destroy_resource(Resource *resource) override; @@ -59,6 +60,7 @@ private: void org_kde_plasma_surface_panel_auto_hide_show(Resource *resource) override; void org_kde_plasma_surface_set_panel_takes_focus(Resource *resource, uint32_t takes_focus) override; void org_kde_plasma_surface_set_skip_switcher(Resource *resource, uint32_t skip) override; + void org_kde_plasma_surface_open_under_cursor(Resource *resource) override; }; PlasmaShellInterface::PlasmaShellInterface(Display *display, QObject *parent) @@ -148,6 +150,15 @@ void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_position(Res Q_EMIT q->positionChanged(); } +void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_open_under_cursor(Resource *resource) +{ + if (surface && surface->buffer()) { + wl_resource_post_error(resource->handle, -1, "open_under_cursor: surface has a buffer"); + } + m_openUnderCursorRequested = true; + Q_EMIT q->openUnderCursorRequested(); +} + void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_role(Resource *resource, uint32_t role) { Q_UNUSED(resource) @@ -272,6 +283,11 @@ bool PlasmaShellSurfaceInterface::isPositionSet() const return d->m_positionSet; } +bool PlasmaShellSurfaceInterface::wantsOpenUnderCursor() const +{ + return d->m_openUnderCursorRequested; +} + PlasmaShellSurfaceInterface::PanelBehavior PlasmaShellSurfaceInterface::panelBehavior() const { return d->m_panelBehavior; diff --git a/src/wayland/plasmashell_interface.h b/src/wayland/plasmashell_interface.h index 8583f1c490..f8b5f339d7 100644 --- a/src/wayland/plasmashell_interface.h +++ b/src/wayland/plasmashell_interface.h @@ -74,6 +74,11 @@ public: */ bool isPositionSet() const; + /** + * @returns Whether the surface has requested to be opened under the cursor. + */ + bool wantsOpenUnderCursor() const; + /** * Describes possible roles this PlasmaShellSurfaceInterface can have. * The role can be used by the server to e.g. change the stacking order accordingly. @@ -159,6 +164,12 @@ Q_SIGNALS: * A change of global position has been requested. */ void positionChanged(); + + /** + * The surface has requested to be initially shown under the cursor. Can only occur + * before any buffer has been attached. + */ + void openUnderCursorRequested(); /** * A change of the role has been requested. */ diff --git a/src/xdgshellwindow.cpp b/src/xdgshellwindow.cpp index e7e89c1a82..989d0992b8 100644 --- a/src/xdgshellwindow.cpp +++ b/src/xdgshellwindow.cpp @@ -438,6 +438,17 @@ void XdgSurfaceWindow::installPlasmaShellSurface(PlasmaShellSurfaceInterface *sh auto updatePosition = [this, shellSurface] { move(shellSurface->position()); }; + auto moveUnderCursor = [this, shellSurface] { + // Wait for the first commit + auto connection = new QMetaObject::Connection; + *connection = connect(this, &Window::windowShown, [this, connection] () { + disconnect(*connection); + if (input()->hasPointer()) { + move(input()->globalPointer().toPoint()); + keepInArea(workspace()->clientArea(PlacementArea, this)); + } + }); + }; auto updateRole = [this, shellSurface] { NET::WindowType type = NET::Unknown; switch (shellSurface->role()) { @@ -486,6 +497,7 @@ void XdgSurfaceWindow::installPlasmaShellSurface(PlasmaShellSurfaceInterface *sh workspace()->updateClientArea(); }; connect(shellSurface, &PlasmaShellSurfaceInterface::positionChanged, this, updatePosition); + connect(shellSurface, &PlasmaShellSurfaceInterface::openUnderCursorRequested, this, moveUnderCursor); connect(shellSurface, &PlasmaShellSurfaceInterface::roleChanged, this, updateRole); connect(shellSurface, &PlasmaShellSurfaceInterface::panelBehaviorChanged, this, [this] { updateShowOnScreenEdge(); @@ -511,6 +523,9 @@ void XdgSurfaceWindow::installPlasmaShellSurface(PlasmaShellSurfaceInterface *sh if (shellSurface->isPositionSet()) { updatePosition(); } + if (shellSurface->wantsOpenUnderCursor()) { + moveUnderCursor(); + } updateRole(); updateShowOnScreenEdge(); connect(this, &XdgSurfaceWindow::frameGeometryChanged, @@ -707,7 +722,10 @@ bool XdgToplevelWindow::isMinimizable() const bool XdgToplevelWindow::isPlaceable() const { - return !m_plasmaShellSurface || !m_plasmaShellSurface->isPositionSet(); + if (m_plasmaShellSurface) { + return !m_plasmaShellSurface->isPositionSet() && !m_plasmaShellSurface->wantsOpenUnderCursor(); + } + return true; } bool XdgToplevelWindow::isTransient() const