[wayland] Introduce a ShellClient

The ShellClient is a Toplevel subclass for a
KWayland::Server::ShellSurfaceInterface. It gets created when a new
ShellSurfaceInterface is created and destoryed when it gets unmapped.

So far the usage is still rather limited. The ShellClient is opened
at position (0/0). While it's possible to pass pointer events to it,
it's not yet possible to activate it, so no keyboard focus.
This commit is contained in:
Martin Gräßlin 2015-03-04 09:21:10 +01:00
parent 8fad5830f1
commit d60c377890
9 changed files with 327 additions and 1 deletions

View file

@ -442,6 +442,7 @@ if(HAVE_WAYLAND)
${kwin_KDEINIT_SRCS}
abstract_backend.cpp
virtual_terminal.cpp
shell_client.cpp
wayland_server.cpp
)
if(HAVE_WAYLAND_CURSOR)

View file

@ -39,6 +39,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "xcbutils.h"
#if HAVE_WAYLAND
#include "abstract_backend.h"
#include "shell_client.h"
#include "wayland_server.h"
#endif
#include "decorations/decoratedclient.h"
@ -743,6 +744,16 @@ bool Compositor::windowRepaintsPending() const
foreach (Toplevel * c, Workspace::self()->deletedList())
if (!c->repaints().isEmpty())
return true;
#if HAVE_WAYLAND
if (auto w = waylandServer()) {
const auto &clients = w->clients();
for (auto c : clients) {
if (!c->repaints().isEmpty()) {
return true;
}
}
}
#endif
return false;
}

View file

@ -57,6 +57,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "xcbutils.h"
#if HAVE_WAYLAND
#include "abstract_backend.h"
#include "shell_client.h"
#include "wayland_server.h"
#endif
@ -297,6 +298,18 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene)
for (Unmanaged *u : ws->unmanagedList()) {
setupUnmanagedConnections(u);
}
#if HAVE_WAYLAND
if (auto w = waylandServer()) {
connect(w, &WaylandServer::shellClientAdded, this,
[this](ShellClient *c) {
if (c->readyForPainting())
slotShellClientShown(c);
else
connect(c, &Toplevel::windowShown, this, &EffectsHandlerImpl::slotShellClientShown);
}
);
}
#endif
reconfigure();
}
@ -565,6 +578,16 @@ void EffectsHandlerImpl::slotClientShown(KWin::Toplevel *t)
emit windowAdded(c->effectWindow());
}
void EffectsHandlerImpl::slotShellClientShown(Toplevel *t)
{
#if HAVE_WAYLAND
ShellClient *c = static_cast<ShellClient*>(t);
connect(c, &ShellClient::windowClosed, this, &EffectsHandlerImpl::slotWindowClosed);
connect(c, &ShellClient::geometryShapeChanged, this, &EffectsHandlerImpl::slotGeometryShapeChanged);
emit windowAdded(t->effectWindow());
#endif
}
void EffectsHandlerImpl::slotUnmanagedShown(KWin::Toplevel *t)
{ // regardless, unmanaged windows are -yet?- not synced anyway
Q_ASSERT(dynamic_cast<Unmanaged*>(t));

View file

@ -234,6 +234,7 @@ public Q_SLOTS:
protected Q_SLOTS:
void slotClientShown(KWin::Toplevel*);
void slotShellClientShown(KWin::Toplevel*);
void slotUnmanagedShown(KWin::Toplevel*);
void slotWindowClosed(KWin::Toplevel *c);
void slotClientMaximized(KWin::Client *c, MaximizeMode maxMode);

161
shell_client.cpp Normal file
View file

@ -0,0 +1,161 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "shell_client.h"
#include "deleted.h"
#include "wayland_server.h"
#include <KWayland/Server/shell_interface.h>
#include <KWayland/Server/surface_interface.h>
#include <KWayland/Server/buffer_interface.h>
using namespace KWayland::Server;
namespace KWin
{
ShellClient::ShellClient(ShellSurfaceInterface *surface)
: Toplevel()
, m_shellSurface(surface)
{
setSurface(surface->surface());
setupCompositing();
if (surface->surface()->buffer()) {
setReadyForPainting();
m_clientSize = surface->surface()->buffer()->size();
} else {
ready_for_painting = false;
}
setGeometry(QRect(QPoint(0, 0), m_clientSize));
connect(surface->surface(), &SurfaceInterface::sizeChanged, this,
[this] {
m_clientSize = m_shellSurface->surface()->buffer()->size();
setGeometry(QRect(QPoint(0, 0), m_clientSize));
}
);
connect(surface, &ShellSurfaceInterface::destroyed, this, &ShellClient::destroyClient);
connect(surface->surface(), &SurfaceInterface::unmapped, this, &ShellClient::destroyClient);
}
ShellClient::~ShellClient() = default;
void ShellClient::destroyClient()
{
Deleted *del = Deleted::create(this);
emit windowClosed(this, del);
waylandServer()->removeClient(this);
del->unrefWindow();
m_shellSurface = nullptr;
deleteClient(this);
}
void ShellClient::deleteClient(ShellClient *c)
{
delete c;
}
QStringList ShellClient::activities() const
{
// TODO: implement
return QStringList();
}
QPoint ShellClient::clientPos() const
{
return QPoint(0, 0);
}
QSize ShellClient::clientSize() const
{
// TODO: connect for changes
return m_clientSize;
}
void ShellClient::debug(QDebug &stream) const
{
// TODO: implement
Q_UNUSED(stream)
}
int ShellClient::desktop() const
{
// TODO: implement
return -1;
}
Layer ShellClient::layer() const
{
// TODO: implement
return KWin::NormalLayer;
}
bool ShellClient::shouldUnredirect() const
{
// TODO: unredirect for fullscreen
return false;
}
QRect ShellClient::transparentRect() const
{
// TODO: implement
return QRect();
}
NET::WindowType ShellClient::windowType(bool direct, int supported_types) const
{
// TODO: implement
Q_UNUSED(direct)
Q_UNUSED(supported_types)
return NET::Normal;
}
double ShellClient::opacity() const
{
return 1.0;
}
void ShellClient::addDamage(const QRegion &damage)
{
setReadyForPainting();
if (m_shellSurface->surface()->buffer()->size().isValid()) {
m_clientSize = m_shellSurface->surface()->buffer()->size();
setGeometry(QRect(QPoint(0, 0), m_clientSize));
}
Toplevel::addDamage(damage);
}
void ShellClient::setGeometry(const QRect &rect)
{
if (geom == rect) {
return;
}
const QRect old = geom;
geom = rect;
emit geometryChanged();
emit geometryShapeChanged(this, old);
}
QByteArray ShellClient::windowRole() const
{
return QByteArray();
}
}

73
shell_client.h Normal file
View file

@ -0,0 +1,73 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_SHELL_CLIENT_H
#define KWIN_SHELL_CLIENT_H
#include "toplevel.h"
namespace KWayland
{
namespace Server
{
class ShellSurfaceInterface;
}
}
namespace KWin
{
class ShellClient : public Toplevel
{
Q_OBJECT
public:
ShellClient(KWayland::Server::ShellSurfaceInterface *surface);
virtual ~ShellClient();
QStringList activities() const override;
QPoint clientPos() const override;
QSize clientSize() const override;
int desktop() const override;
Layer layer() const override;
QRect transparentRect() const override;
bool shouldUnredirect() const override;
NET::WindowType windowType(bool direct = false, int supported_types = 0) const override;
void debug(QDebug &stream) const override;
double opacity() const override;
QByteArray windowRole() const override;
KWayland::Server::ShellSurfaceInterface *shellSurface() const {
return m_shellSurface;
}
protected:
void addDamage(const QRegion &damage) override;
private:
void setGeometry(const QRect &rect);
void destroyClient();
static void deleteClient(ShellClient *c);
KWayland::Server::ShellSurfaceInterface *m_shellSurface;
QSize m_clientSize;
};
}
#endif

View file

@ -19,8 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "wayland_server.h"
#include "abstract_backend.h"
#include "composite.h"
#include "screens.h"
#include "toplevel.h"
#include "shell_client.h"
#include "workspace.h"
// Client
@ -78,6 +79,20 @@ void WaylandServer::init(const QByteArray &socketName)
);
m_shell = m_display->createShell(m_display);
m_shell->create();
connect(m_shell, &ShellInterface::surfaceCreated, this,
[this] (ShellSurfaceInterface *surface) {
if (surface->client() == m_xwaylandConnection) {
// skip Xwayland clients, those are created using standard X11 way
return;
}
auto client = new ShellClient(surface);
if (auto c = Compositor::self()) {
connect(client, &Toplevel::needsRepaint, c, &Compositor::scheduleRepaint);
}
m_clients << client;
emit shellClientAdded(client);
}
);
m_display->createShm();
m_seat = m_display->createSeat(m_display);
m_seat->create();
@ -163,4 +178,10 @@ void WaylandServer::uninstallBackend(AbstractBackend *backend)
m_backend = nullptr;
}
void WaylandServer::removeClient(ShellClient *c)
{
m_clients.removeAll(c);
emit shellClientRemoved(c);
}
}

View file

@ -44,6 +44,7 @@ class OutputInterface;
namespace KWin
{
class ShellClient;
class AbstractBackend;
@ -67,6 +68,10 @@ public:
KWayland::Server::ShellInterface *shell() {
return m_shell;
}
QList<ShellClient*> clients() const {
return m_clients;
}
void removeClient(ShellClient *c);
AbstractBackend *backend() const {
return m_backend;
@ -98,6 +103,10 @@ public:
return m_internalConnection.client;
}
Q_SIGNALS:
void shellClientAdded(ShellClient*);
void shellClientRemoved(ShellClient*);
private:
KWayland::Server::Display *m_display = nullptr;
KWayland::Server::CompositorInterface *m_compositor = nullptr;
@ -112,6 +121,7 @@ private:
} m_internalConnection;
AbstractBackend *m_backend = nullptr;
QList<ShellClient*> m_clients;
KWIN_SINGLETON(WaylandServer)
};

View file

@ -52,6 +52,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "unmanaged.h"
#include "useractions.h"
#include "virtualdesktops.h"
#if HAVE_WAYLAND
#include "shell_client.h"
#include "wayland_server.h"
#endif
#include "xcbutils.h"
#include "main.h"
#include "decorations/decorationbridge.h"
@ -370,6 +374,27 @@ void Workspace::init()
Scripting::create(this);
#if HAVE_WAYLAND
if (auto w = waylandServer()) {
connect(w, &WaylandServer::shellClientAdded, this,
[this] (ShellClient *c) {
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
stacking_order.append(c); // c to be in stacking_order
x_stacking_dirty = true;
updateStackingOrder(true);
}
);
connect(w, &WaylandServer::shellClientRemoved, this,
[this] {
x_stacking_dirty = true;
updateStackingOrder(true);
}
);
}
#endif
// SELI TODO: This won't work with unreasonable focus policies,
// and maybe in rare cases also if the selected client doesn't
// want focus