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.
This commit is contained in:
Martin Gräßlin 2015-12-17 15:47:36 +01:00
parent 5cfe9428aa
commit 5e96f65224
5 changed files with 91 additions and 10 deletions

View file

@ -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

View file

@ -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();

View file

@ -26,6 +26,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "workspace.h"
#include "virtualdesktops.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/Server/seat_interface.h>
@ -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);
}
}
);

View file

@ -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<KWayland::Server::PlasmaShellSurfaceInterface> m_plasmaShellSurface;
QPointer<KWayland::Server::QtExtendedSurfaceInterface> m_qtExtendedSurface;
KWayland::Server::ServerSideDecorationInterface *m_serverDecoration = nullptr;
bool m_userNoBorder = false;
bool m_fullScreen = false;
bool m_transient = false;
};

View file

@ -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());