From 124bd8aaed19aa1347ed236424ea3a7fd8920573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Tue, 9 Jun 2015 19:10:56 +0200 Subject: [PATCH] [wayland] Add support for the PlasmaShell interface The PlasmaShell interface allows to create a PlasmaShellSurface for a given Surface. Through this interface the Surface can request: * a specific position * a window type So far only the window types Normal, Panel and Desktop are supported which is a sufficient subset for getting plasmashell to work. In future there should be security checks so that only the dedicated desktop shell can bind these interfaces. --- shell_client.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++ shell_client.h | 6 ++++++ wayland_server.cpp | 37 +++++++++++++++++++++++++++++++ wayland_server.h | 3 +++ workspace.cpp | 4 +++- 5 files changed, 103 insertions(+), 1 deletion(-) diff --git a/shell_client.cpp b/shell_client.cpp index 8078a78eec..808f606f02 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -30,6 +30,7 @@ along with this program. If not, see . #include #include #include +#include #include @@ -125,6 +126,20 @@ void ShellClient::debug(QDebug &stream) const Layer ShellClient::layer() const { // TODO: implement the rest + if (isDesktop()) + return workspace()->showingDesktop() ? AboveLayer : DesktopLayer; + if (isDock()) { + if (workspace()->showingDesktop()) + return NotificationLayer; + // slight hack for the 'allow window to cover panel' Kicker setting + // don't move keepbelow docks below normal window, but only to the same + // layer, so that both may be raised to cover the other + if (keepBelow()) + return NormalLayer; + if (keepAbove()) // slight hack for the autohiding panels + return AboveLayer; + return DockLayer; + } if (isFullScreen() && isActive()) return ActiveLayer; return KWin::NormalLayer; @@ -517,4 +532,43 @@ void ShellClient::unmap() workspace()->clientHidden(this); } +void ShellClient::installPlasmaShellSurface(PlasmaShellSurfaceInterface *surface) +{ + m_plasmaShellSurface = surface; + auto updatePosition = [this, surface] { + setGeometry(QRect(surface->position(), m_clientSize)); + }; + auto updateRole = [this, surface] { + NET::WindowType type = NET::Unknown; + switch (surface->role()) { + case PlasmaShellSurfaceInterface::Role::Desktop: + type = NET::Desktop; + break; + case PlasmaShellSurfaceInterface::Role::Panel: + type = NET::Dock; + break; + case PlasmaShellSurfaceInterface::Role::Normal: + default: + type = NET::Normal; + break; + } + if (type != m_windowType) { + m_windowType = type; + workspace()->updateClientArea(); + } + }; + connect(surface, &PlasmaShellSurfaceInterface::positionChanged, this, updatePosition); + connect(surface, &PlasmaShellSurfaceInterface::roleChanged, this, updateRole); + updatePosition(); + updateRole(); +} + +bool ShellClient::isInitialPositionSet() const +{ + if (m_plasmaShellSurface) { + return m_plasmaShellSurface->isPositionSet(); + } + return false; +} + } diff --git a/shell_client.h b/shell_client.h index 19c343c9e4..265b7fea8c 100644 --- a/shell_client.h +++ b/shell_client.h @@ -27,6 +27,7 @@ namespace KWayland namespace Server { class ShellSurfaceInterface; +class PlasmaShellSurfaceInterface; } } @@ -101,6 +102,10 @@ public: return m_internalWindow; } + void installPlasmaShellSurface(KWayland::Server::PlasmaShellSurfaceInterface *surface); + + bool isInitialPositionSet() const; + protected: void addDamage(const QRegion &damage) override; bool belongsToSameApplication(const AbstractClient *other, bool active_hack) const override; @@ -130,6 +135,7 @@ private: MaximizeMode m_maximizeMode = MaximizeRestore; QRect m_geomMaximizeRestore; // size and position of the window before it was set to maximize NET::WindowType m_windowType = NET::Normal; + QPointer m_plasmaShellSurface; }; } diff --git a/wayland_server.cpp b/wayland_server.cpp index 74081557cb..354208087d 100644 --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -33,6 +33,7 @@ along with this program. If not, see . #include #include #include +#include #include #include @@ -136,6 +137,15 @@ void WaylandServer::init(const QByteArray &socketName) m_seat = m_display->createSeat(m_display); m_seat->create(); m_display->createDataDeviceManager(m_display)->create(); + m_plasmaShell = m_display->createPlasmaShell(m_display); + m_plasmaShell->create(); + connect(m_plasmaShell, &PlasmaShellInterface::surfaceCreated, + [this] (PlasmaShellSurfaceInterface *surface) { + if (ShellClient *client = findClient(surface->surface())) { + client->installPlasmaShellSurface(surface); + } + } + ); } void WaylandServer::initOutputs() @@ -285,6 +295,19 @@ static ShellClient *findClientInList(const QList &clients, quint32 return *it; } +static ShellClient *findClientInList(const QList &clients, KWayland::Server::SurfaceInterface *surface) +{ + auto it = std::find_if(clients.begin(), clients.end(), + [surface] (ShellClient *c) { + return c->surface() == surface; + } + ); + if (it == clients.end()) { + return nullptr; + } + return *it; +} + ShellClient *WaylandServer::findClient(quint32 id) const { if (id == 0) { @@ -299,6 +322,20 @@ ShellClient *WaylandServer::findClient(quint32 id) const return nullptr; } +ShellClient *WaylandServer::findClient(SurfaceInterface *surface) const +{ + if (!surface) { + return nullptr; + } + if (ShellClient *c = findClientInList(m_clients, surface)) { + return c; + } + if (ShellClient *c = findClientInList(m_internalClients, surface)) { + return c; + } + return nullptr; +} + quint32 WaylandServer::createWindowId(SurfaceInterface *surface) { auto it = m_clientIds.constFind(surface->client()); diff --git a/wayland_server.h b/wayland_server.h index ebb32db804..919e1786d2 100644 --- a/wayland_server.h +++ b/wayland_server.h @@ -43,6 +43,7 @@ class ShellInterface; class SeatInterface; class SurfaceInterface; class OutputInterface; +class PlasmaShellInterface; } } @@ -80,6 +81,7 @@ public: } void removeClient(ShellClient *c); ShellClient *findClient(quint32 id) const; + ShellClient *findClient(KWayland::Server::SurfaceInterface *surface) const; AbstractBackend *backend() const { return m_backend; @@ -128,6 +130,7 @@ private: KWayland::Server::CompositorInterface *m_compositor = nullptr; KWayland::Server::SeatInterface *m_seat = nullptr; KWayland::Server::ShellInterface *m_shell = nullptr; + KWayland::Server::PlasmaShellInterface *m_plasmaShell = nullptr; KWayland::Server::ClientConnection *m_xwaylandConnection = nullptr; KWayland::Server::ClientConnection *m_qtConnection = nullptr; KWayland::Client::ConnectionThread *m_qtClientConnection = nullptr; diff --git a/workspace.cpp b/workspace.cpp index ff721f6481..30eb5485e7 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -380,7 +380,9 @@ void Workspace::init() [this] (ShellClient *c) { if (!c->isInternal()) { QRect area = clientArea(PlacementArea, Screens::self()->current(), c->desktop()); - Placement::self()->place(c, area); + if (!c->isInitialPositionSet()) { + Placement::self()->place(c, area); + } if (!unconstrained_stacking_order.contains(c)) unconstrained_stacking_order.append(c); // Raise if it hasn't got any stacking position yet if (!stacking_order.contains(c)) // It'll be updated later, and updateToolWindows() requires