Commit 5e96f652 authored by Martin Flöser's avatar Martin Flöser

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.
parent 5cfe9428
...@@ -523,6 +523,11 @@ public: ...@@ -523,6 +523,11 @@ public:
bool processDecorationButtonPress(QMouseEvent *event, bool ignoreMenu = false); bool processDecorationButtonPress(QMouseEvent *event, bool ignoreMenu = false);
void processDecorationButtonRelease(QMouseEvent *event); 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, * 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 * you should show a help menu item or a help button like '?' and call
......
...@@ -209,7 +209,7 @@ public: ...@@ -209,7 +209,7 @@ public:
void takeFocus() override; void takeFocus() override;
void updateDecoration(bool check_workspace_pos, bool force = false); void updateDecoration(bool check_workspace_pos, bool force = false) override;
void updateShape(); void updateShape();
......
...@@ -26,6 +26,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -26,6 +26,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "workspace.h" #include "workspace.h"
#include "virtualdesktops.h" #include "virtualdesktops.h"
#include "workspace.h" #include "workspace.h"
#include "decorations/decorationbridge.h"
#include "decorations/decoratedclient.h"
#include <KDecoration2/Decoration>
#include <KDecoration2/DecoratedClient>
#include <KWayland/Client/surface.h> #include <KWayland/Client/surface.h>
#include <KWayland/Server/seat_interface.h> #include <KWayland/Server/seat_interface.h>
...@@ -78,7 +82,7 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface) ...@@ -78,7 +82,7 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface)
connect(surface->surface(), &SurfaceInterface::sizeChanged, this, connect(surface->surface(), &SurfaceInterface::sizeChanged, this,
[this] { [this] {
m_clientSize = m_shellSurface->surface()->buffer()->size(); 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(); discardWindowPixmap();
} }
); );
...@@ -153,6 +157,8 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface) ...@@ -153,6 +157,8 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface)
if (ServerSideDecorationInterface *deco = ServerSideDecorationInterface::get(surface->surface())) { if (ServerSideDecorationInterface *deco = ServerSideDecorationInterface::get(surface->surface())) {
installServerSideDecoration(deco); installServerSideDecoration(deco);
} }
updateColorScheme(QString());
} }
ShellClient::~ShellClient() = default; ShellClient::~ShellClient() = default;
...@@ -165,6 +171,7 @@ void ShellClient::destroyClient() ...@@ -165,6 +171,7 @@ void ShellClient::destroyClient()
del = Deleted::create(this); del = Deleted::create(this);
} }
emit windowClosed(this, del); emit windowClosed(this, del);
destroyDecoration();
if (workspace()) { if (workspace()) {
StackingUpdatesBlocker blocker(workspace()); StackingUpdatesBlocker blocker(workspace());
...@@ -276,7 +283,7 @@ void ShellClient::addDamage(const QRegion &damage) ...@@ -276,7 +283,7 @@ void ShellClient::addDamage(const QRegion &damage)
position = m_positionAfterResize.point(); position = m_positionAfterResize.point();
m_positionAfterResize.clear(); m_positionAfterResize.clear();
} }
doSetGeometry(QRect(position, m_clientSize)); doSetGeometry(QRect(position, m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
} }
markAsMapped(); markAsMapped();
setDepth(m_shellSurface->surface()->buffer()->hasAlphaChannel() ? 32 : 24); setDepth(m_shellSurface->surface()->buffer()->hasAlphaChannel() ? 32 : 24);
...@@ -301,11 +308,56 @@ void ShellClient::markAsMapped() ...@@ -301,11 +308,56 @@ void ShellClient::markAsMapped()
if (!m_unmapped) { if (!m_unmapped) {
return; return;
} }
m_unmapped = false; m_unmapped = false;
setReadyForPainting(); setReadyForPainting();
setupWindowManagementInterface(); 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) void ShellClient::setGeometry(int x, int y, int w, int h, ForceGeometry_t force)
{ {
Q_UNUSED(force) Q_UNUSED(force)
...@@ -339,6 +391,7 @@ void ShellClient::doSetGeometry(const QRect &rect) ...@@ -339,6 +391,7 @@ void ShellClient::doSetGeometry(const QRect &rect)
if (!m_unmapped) { if (!m_unmapped) {
addWorkspaceRepaint(visibleRect()); addWorkspaceRepaint(visibleRect());
} }
triggerDecorationRepaint();
emit geometryShapeChanged(this, old); emit geometryShapeChanged(this, old);
} }
...@@ -492,6 +545,14 @@ MaximizeMode ShellClient::maximizeMode() const ...@@ -492,6 +545,14 @@ MaximizeMode ShellClient::maximizeMode() const
bool ShellClient::noBorder() const bool ShellClient::noBorder() const
{ {
if (isInternal()) {
return true;
}
if (m_serverDecoration) {
if (m_serverDecoration->mode() == ServerSideDecorationManagerInterface::Mode::Server) {
return m_userNoBorder;
}
}
return true; return true;
} }
...@@ -509,7 +570,16 @@ void ShellClient::setFullScreen(bool set, bool user) ...@@ -509,7 +570,16 @@ void ShellClient::setFullScreen(bool set, bool user)
void ShellClient::setNoBorder(bool set) 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) void ShellClient::setOnAllActivities(bool set)
...@@ -662,7 +732,7 @@ xcb_window_t ShellClient::window() const ...@@ -662,7 +732,7 @@ xcb_window_t ShellClient::window() const
void ShellClient::requestGeometry(const QRect &rect) void ShellClient::requestGeometry(const QRect &rect)
{ {
m_positionAfterResize.setPoint(rect.topLeft()); 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) void ShellClient::clientFullScreenChanged(bool fullScreen)
...@@ -717,7 +787,7 @@ void ShellClient::installPlasmaShellSurface(PlasmaShellSurfaceInterface *surface ...@@ -717,7 +787,7 @@ void ShellClient::installPlasmaShellSurface(PlasmaShellSurfaceInterface *surface
{ {
m_plasmaShellSurface = surface; m_plasmaShellSurface = surface;
auto updatePosition = [this, 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] { auto updateRole = [this, surface] {
NET::WindowType type = NET::Unknown; NET::WindowType type = NET::Unknown;
...@@ -860,18 +930,20 @@ void ShellClient::installServerSideDecoration(KWayland::Server::ServerSideDecora ...@@ -860,18 +930,20 @@ void ShellClient::installServerSideDecoration(KWayland::Server::ServerSideDecora
m_serverDecoration = deco; m_serverDecoration = deco;
connect(m_serverDecoration, &ServerSideDecorationInterface::destroyed, this, connect(m_serverDecoration, &ServerSideDecorationInterface::destroyed, this,
[this] { [this] {
// TODO: update decoration
m_serverDecoration = nullptr; m_serverDecoration = nullptr;
updateDecoration(true);
} }
); );
// TODO: update decoration if (!m_unmapped) {
updateDecoration(true);
}
connect(m_serverDecoration, &ServerSideDecorationInterface::modeRequested, this, connect(m_serverDecoration, &ServerSideDecorationInterface::modeRequested, this,
[this] (ServerSideDecorationManagerInterface::Mode mode) { [this] (ServerSideDecorationManagerInterface::Mode mode) {
const bool changed = mode != m_serverDecoration->mode(); const bool changed = mode != m_serverDecoration->mode();
// always acknowledge the requested mode // always acknowledge the requested mode
m_serverDecoration->setMode(mode); m_serverDecoration->setMode(mode);
if (changed) { if (changed && !m_unmapped) {
// TODO: update decoration updateDecoration(false);
} }
} }
); );
......
...@@ -81,6 +81,7 @@ public: ...@@ -81,6 +81,7 @@ public:
const WindowRules *rules() const override; const WindowRules *rules() const override;
void setFullScreen(bool set, bool user = true) override; void setFullScreen(bool set, bool user = true) override;
void setNoBorder(bool set) override; void setNoBorder(bool set) override;
void updateDecoration(bool check_workspace_pos, bool force = false) override;
void setOnAllActivities(bool set) override; void setOnAllActivities(bool set) override;
void setShortcut(const QString &cut) override; void setShortcut(const QString &cut) override;
const QKeySequence &shortcut() const override; const QKeySequence &shortcut() const override;
...@@ -139,6 +140,7 @@ private Q_SLOTS: ...@@ -139,6 +140,7 @@ private Q_SLOTS:
private: private:
void requestGeometry(const QRect &rect); void requestGeometry(const QRect &rect);
void doSetGeometry(const QRect &rect); void doSetGeometry(const QRect &rect);
void createDecoration(const QRect &oldgeom);
void destroyClient(); void destroyClient();
void unmap(); void unmap();
void createWindowId(); void createWindowId();
...@@ -164,6 +166,7 @@ private: ...@@ -164,6 +166,7 @@ private:
QPointer<KWayland::Server::PlasmaShellSurfaceInterface> m_plasmaShellSurface; QPointer<KWayland::Server::PlasmaShellSurfaceInterface> m_plasmaShellSurface;
QPointer<KWayland::Server::QtExtendedSurfaceInterface> m_qtExtendedSurface; QPointer<KWayland::Server::QtExtendedSurfaceInterface> m_qtExtendedSurface;
KWayland::Server::ServerSideDecorationInterface *m_serverDecoration = nullptr; KWayland::Server::ServerSideDecorationInterface *m_serverDecoration = nullptr;
bool m_userNoBorder = false;
bool m_fullScreen = false; bool m_fullScreen = false;
bool m_transient = false; bool m_transient = false;
}; };
......
...@@ -372,6 +372,7 @@ void Workspace::init() ...@@ -372,6 +372,7 @@ void Workspace::init()
if (auto w = waylandServer()) { if (auto w = waylandServer()) {
connect(w, &WaylandServer::shellClientAdded, this, connect(w, &WaylandServer::shellClientAdded, this,
[this] (ShellClient *c) { [this] (ShellClient *c) {
c->updateDecoration(false);
updateClientLayer(c); updateClientLayer(c);
if (!c->isInternal()) { if (!c->isInternal()) {
QRect area = clientArea(PlacementArea, Screens::self()->current(), c->desktop()); QRect area = clientArea(PlacementArea, Screens::self()->current(), c->desktop());
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment