From 5e96f65224803ef5deec82e58b3bf83f3e9453ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Thu, 17 Dec 2015 15:47:36 +0100 Subject: [PATCH] Add window decoration to ShellClient If a ShellClient supports the ServerSideDecoration interface we can create a server decoration for it. For that updateDecoration is added as a pure virtual method in AbstractClient and a more-or-less code copy from Client is added to ShellClient. Geometry handling is adjusted to consider the window decoration offsets. --- abstract_client.h | 5 +++ client.h | 2 +- shell_client.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++----- shell_client.h | 3 ++ workspace.cpp | 1 + 5 files changed, 91 insertions(+), 10 deletions(-) diff --git a/abstract_client.h b/abstract_client.h index 1cee0733f..8ea1c409c 100644 --- a/abstract_client.h +++ b/abstract_client.h @@ -523,6 +523,11 @@ public: bool processDecorationButtonPress(QMouseEvent *event, bool ignoreMenu = false); void processDecorationButtonRelease(QMouseEvent *event); + /** + * TODO: fix boolean traps + **/ + virtual void updateDecoration(bool check_workspace_pos, bool force = false) = 0; + /** * Returns whether the window provides context help or not. If it does, * you should show a help menu item or a help button like '?' and call diff --git a/client.h b/client.h index 5540d83d7..c5a1b42ae 100644 --- a/client.h +++ b/client.h @@ -209,7 +209,7 @@ public: void takeFocus() override; - void updateDecoration(bool check_workspace_pos, bool force = false); + void updateDecoration(bool check_workspace_pos, bool force = false) override; void updateShape(); diff --git a/shell_client.cpp b/shell_client.cpp index eda91de84..5959a557a 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -26,6 +26,10 @@ along with this program. If not, see . #include "workspace.h" #include "virtualdesktops.h" #include "workspace.h" +#include "decorations/decorationbridge.h" +#include "decorations/decoratedclient.h" +#include +#include #include #include @@ -78,7 +82,7 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface) connect(surface->surface(), &SurfaceInterface::sizeChanged, this, [this] { m_clientSize = m_shellSurface->surface()->buffer()->size(); - doSetGeometry(QRect(geom.topLeft(), m_clientSize)); + doSetGeometry(QRect(geom.topLeft(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); discardWindowPixmap(); } ); @@ -153,6 +157,8 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface) if (ServerSideDecorationInterface *deco = ServerSideDecorationInterface::get(surface->surface())) { installServerSideDecoration(deco); } + + updateColorScheme(QString()); } ShellClient::~ShellClient() = default; @@ -165,6 +171,7 @@ void ShellClient::destroyClient() del = Deleted::create(this); } emit windowClosed(this, del); + destroyDecoration(); if (workspace()) { StackingUpdatesBlocker blocker(workspace()); @@ -276,7 +283,7 @@ void ShellClient::addDamage(const QRegion &damage) position = m_positionAfterResize.point(); m_positionAfterResize.clear(); } - doSetGeometry(QRect(position, m_clientSize)); + doSetGeometry(QRect(position, m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); } markAsMapped(); setDepth(m_shellSurface->surface()->buffer()->hasAlphaChannel() ? 32 : 24); @@ -301,11 +308,56 @@ void ShellClient::markAsMapped() if (!m_unmapped) { return; } + m_unmapped = false; setReadyForPainting(); setupWindowManagementInterface(); } +void ShellClient::createDecoration(const QRect &oldGeom) +{ + KDecoration2::Decoration *decoration = Decoration::DecorationBridge::self()->createDecoration(this); + if (decoration) { + QMetaObject::invokeMethod(decoration, "update", Qt::QueuedConnection); + connect(decoration, &KDecoration2::Decoration::shadowChanged, this, &Toplevel::getShadow); + connect(decoration, &KDecoration2::Decoration::bordersChanged, this, + [this]() { + GeometryUpdatesBlocker blocker(this); + QRect oldgeom = geometry(); + if (!isShade()) + checkWorkspacePosition(oldgeom); + emit geometryShapeChanged(this, oldgeom); + } + ); + } + setDecoration(decoration); + + emit geometryShapeChanged(this, oldGeom); +} + +void ShellClient::updateDecoration(bool check_workspace_pos, bool force) +{ + if (!force && + ((!isDecorated() && noBorder()) || (isDecorated() && !noBorder()))) + return; + QRect oldgeom = geometry(); + QRect oldClientGeom = oldgeom.adjusted(borderLeft(), borderTop(), -borderRight(), -borderBottom()); + blockGeometryUpdates(true); + if (force) + destroyDecoration(); + if (!noBorder()) { + createDecoration(oldgeom); + } else + destroyDecoration(); + if (m_serverDecoration && isDecorated()) { + m_serverDecoration->setMode(KWayland::Server::ServerSideDecorationManagerInterface::Mode::Server); + } + getShadow(); + if (check_workspace_pos) + checkWorkspacePosition(oldgeom, -2, oldClientGeom); + blockGeometryUpdates(false); +} + void ShellClient::setGeometry(int x, int y, int w, int h, ForceGeometry_t force) { Q_UNUSED(force) @@ -339,6 +391,7 @@ void ShellClient::doSetGeometry(const QRect &rect) if (!m_unmapped) { addWorkspaceRepaint(visibleRect()); } + triggerDecorationRepaint(); emit geometryShapeChanged(this, old); } @@ -492,6 +545,14 @@ MaximizeMode ShellClient::maximizeMode() const bool ShellClient::noBorder() const { + if (isInternal()) { + return true; + } + if (m_serverDecoration) { + if (m_serverDecoration->mode() == ServerSideDecorationManagerInterface::Mode::Server) { + return m_userNoBorder; + } + } return true; } @@ -509,7 +570,16 @@ void ShellClient::setFullScreen(bool set, bool user) void ShellClient::setNoBorder(bool set) { - Q_UNUSED(set) + if (!userCanSetNoBorder()) { + return; + } + set = rules()->checkNoBorder(set); + if (m_userNoBorder == set) { + return; + } + m_userNoBorder = set; + updateDecoration(true, false); + updateWindowRules(Rules::NoBorder); } void ShellClient::setOnAllActivities(bool set) @@ -662,7 +732,7 @@ xcb_window_t ShellClient::window() const void ShellClient::requestGeometry(const QRect &rect) { m_positionAfterResize.setPoint(rect.topLeft()); - m_shellSurface->requestSize(rect.size()); + m_shellSurface->requestSize(rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())); } void ShellClient::clientFullScreenChanged(bool fullScreen) @@ -717,7 +787,7 @@ void ShellClient::installPlasmaShellSurface(PlasmaShellSurfaceInterface *surface { m_plasmaShellSurface = surface; auto updatePosition = [this, surface] { - doSetGeometry(QRect(surface->position(), m_clientSize)); + doSetGeometry(QRect(surface->position(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); }; auto updateRole = [this, surface] { NET::WindowType type = NET::Unknown; @@ -860,18 +930,20 @@ void ShellClient::installServerSideDecoration(KWayland::Server::ServerSideDecora m_serverDecoration = deco; connect(m_serverDecoration, &ServerSideDecorationInterface::destroyed, this, [this] { - // TODO: update decoration m_serverDecoration = nullptr; + updateDecoration(true); } ); - // TODO: update decoration + if (!m_unmapped) { + updateDecoration(true); + } connect(m_serverDecoration, &ServerSideDecorationInterface::modeRequested, this, [this] (ServerSideDecorationManagerInterface::Mode mode) { const bool changed = mode != m_serverDecoration->mode(); // always acknowledge the requested mode m_serverDecoration->setMode(mode); - if (changed) { - // TODO: update decoration + if (changed && !m_unmapped) { + updateDecoration(false); } } ); diff --git a/shell_client.h b/shell_client.h index 67e9da2a4..9acb3e3d4 100644 --- a/shell_client.h +++ b/shell_client.h @@ -81,6 +81,7 @@ public: const WindowRules *rules() const override; void setFullScreen(bool set, bool user = true) override; void setNoBorder(bool set) override; + void updateDecoration(bool check_workspace_pos, bool force = false) override; void setOnAllActivities(bool set) override; void setShortcut(const QString &cut) override; const QKeySequence &shortcut() const override; @@ -139,6 +140,7 @@ private Q_SLOTS: private: void requestGeometry(const QRect &rect); void doSetGeometry(const QRect &rect); + void createDecoration(const QRect &oldgeom); void destroyClient(); void unmap(); void createWindowId(); @@ -164,6 +166,7 @@ private: QPointer m_plasmaShellSurface; QPointer m_qtExtendedSurface; KWayland::Server::ServerSideDecorationInterface *m_serverDecoration = nullptr; + bool m_userNoBorder = false; bool m_fullScreen = false; bool m_transient = false; }; diff --git a/workspace.cpp b/workspace.cpp index 07f7fe041..206caab98 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -372,6 +372,7 @@ void Workspace::init() if (auto w = waylandServer()) { connect(w, &WaylandServer::shellClientAdded, this, [this] (ShellClient *c) { + c->updateDecoration(false); updateClientLayer(c); if (!c->isInternal()) { QRect area = clientArea(PlacementArea, Screens::self()->current(), c->desktop()); -- GitLab