Commit c3af4c3f authored by Martin Flöser's avatar Martin Flöser

Add support for xdg-shell version 5 interface

Summary:
The WaylandServer creates the XdgShellV5 interface and hooks it up
to create a ShellSurface whenever an xdg surface or xdg popup is created.

ShellClient gains some new ctors for the different variants and is
adjusted to delegate to xdg surface respectively.

With this change KWin mostly supports xdg-shell protocol. Still missing
is support for the "geometry" request which is rather difficult to
implement in KWin.

Reviewers: #kwin, #plasma_on_wayland

Subscribers: plasma-devel, kwin

Tags: #plasma_on_wayland, #kwin

Differential Revision: https://phabricator.kde.org/D2108
parent dbdbee9a
......@@ -49,6 +49,7 @@ private Q_SLOTS:
void topLevelTest();
void testX11Client();
void testX11Unmanaged();
void testWaylandClient_data();
void testWaylandClient();
void testInternalWindow();
};
......@@ -292,6 +293,14 @@ void DebugConsoleTest::testX11Unmanaged()
QVERIFY(!model2.hasChildren(model2.index(1, 0, QModelIndex())));
}
void DebugConsoleTest::testWaylandClient_data()
{
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
}
void DebugConsoleTest::testWaylandClient()
{
DebugConsoleModel model;
......@@ -318,8 +327,9 @@ void DebugConsoleTest::testWaylandClient()
using namespace KWayland::Client;
QScopedPointer<Surface> surface(Test::createSurface());
QVERIFY(surface->isValid());
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
QVERIFY(shellSurface->isValid());
QFETCH(Test::ShellSurfaceType, type);
QScopedPointer<QObject> shellSurface(Test::createShellSurface(type, surface.data()));
QVERIFY(!shellSurface.isNull());
Test::render(surface.data(), QSize(10, 10), Qt::red);
// now we have the window, it should be added to our model
......@@ -380,11 +390,13 @@ void DebugConsoleTest::testWaylandClient()
shellSurface.reset();
Test::flushWaylandConnection();
qDebug() << rowsRemovedSpy.count();
QEXPECT_FAIL("", "Deleting a ShellSurface does not result in the server removing the ShellClient", Continue);
QEXPECT_FAIL("wlShell", "Deleting a ShellSurface does not result in the server removing the ShellClient", Continue);
QVERIFY(rowsRemovedSpy.wait());
surface.reset();
QVERIFY(rowsRemovedSpy.wait());
if (rowsRemovedSpy.isEmpty()) {
QVERIFY(rowsRemovedSpy.wait());
}
QCOMPARE(rowsRemovedSpy.count(), 1);
QCOMPARE(rowsRemovedSpy.first().first().value<QModelIndex>(), waylandTopLevelIndex);
QCOMPARE(rowsRemovedSpy.first().at(1).value<int>(), 0);
......
......@@ -64,6 +64,7 @@ private Q_SLOTS:
void testDoubleClick();
void testDoubleTap_data();
void testDoubleTap();
void testHover_data();
void testHover();
void testPressToMove_data();
void testPressToMove();
......@@ -71,7 +72,7 @@ private Q_SLOTS:
void testTapToMove();
private:
AbstractClient *showWindow();
AbstractClient *showWindow(Test::ShellSurfaceType type);
};
#define MOTION(target) \
......@@ -83,7 +84,7 @@ private:
#define RELEASE \
kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++)
AbstractClient *DecorationInputTest::showWindow()
AbstractClient *DecorationInputTest::showWindow(Test::ShellSurfaceType type)
{
using namespace KWayland::Client;
#define VERIFY(statement) \
......@@ -95,7 +96,7 @@ AbstractClient *DecorationInputTest::showWindow()
Surface *surface = Test::createSurface(Test::waylandCompositor());
VERIFY(surface);
ShellSurface *shellSurface = Test::createShellSurface(surface, surface);
auto shellSurface = Test::createShellSurface(type, surface, surface);
VERIFY(shellSurface);
auto deco = Test::waylandServerSideDecoration()->create(surface, surface);
QSignalSpy decoSpy(deco, &ServerSideDecoration::modeChanged);
......@@ -162,15 +163,20 @@ void DecorationInputTest::testAxis_data()
{
QTest::addColumn<QPoint>("decoPoint");
QTest::addColumn<Qt::WindowFrameSection>("expectedSection");
QTest::newRow("topLeft") << QPoint(0, 0) << Qt::TopLeftSection;
QTest::newRow("top") << QPoint(250, 0) << Qt::TopSection;
QTest::newRow("topRight") << QPoint(499, 0) << Qt::TopRightSection;
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("topLeft") << QPoint(0, 0) << Qt::TopLeftSection << Test::ShellSurfaceType::WlShell;
QTest::newRow("top") << QPoint(250, 0) << Qt::TopSection << Test::ShellSurfaceType::WlShell;
QTest::newRow("topRight") << QPoint(499, 0) << Qt::TopRightSection << Test::ShellSurfaceType::WlShell;
QTest::newRow("topLeft|xdg") << QPoint(0, 0) << Qt::TopLeftSection << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("top|xdg") << QPoint(250, 0) << Qt::TopSection << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("topRight|xdg") << QPoint(499, 0) << Qt::TopRightSection << Test::ShellSurfaceType::XdgShellV5;
}
void DecorationInputTest::testAxis()
{
AbstractClient *c = showWindow();
QFETCH(Test::ShellSurfaceType, type);
AbstractClient *c = showWindow(type);
QVERIFY(c);
QVERIFY(c->isDecorated());
QVERIFY(!c->noBorder());
......@@ -211,15 +217,20 @@ void DecorationInputTest::testDoubleClick_data()
{
QTest::addColumn<QPoint>("decoPoint");
QTest::addColumn<Qt::WindowFrameSection>("expectedSection");
QTest::newRow("topLeft") << QPoint(0, 0) << Qt::TopLeftSection;
QTest::newRow("top") << QPoint(250, 0) << Qt::TopSection;
QTest::newRow("topRight") << QPoint(499, 0) << Qt::TopRightSection;
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("topLeft") << QPoint(0, 0) << Qt::TopLeftSection << Test::ShellSurfaceType::WlShell;
QTest::newRow("top") << QPoint(250, 0) << Qt::TopSection << Test::ShellSurfaceType::WlShell;
QTest::newRow("topRight") << QPoint(499, 0) << Qt::TopRightSection << Test::ShellSurfaceType::WlShell;
QTest::newRow("topLeft|xdg") << QPoint(0, 0) << Qt::TopLeftSection << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("top|xdg") << QPoint(250, 0) << Qt::TopSection << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("topRight|xdg") << QPoint(499, 0) << Qt::TopRightSection << Test::ShellSurfaceType::XdgShellV5;
}
void KWin::DecorationInputTest::testDoubleClick()
{
AbstractClient *c = showWindow();
QFETCH(Test::ShellSurfaceType, type);
AbstractClient *c = showWindow(type);
QVERIFY(c);
QVERIFY(c->isDecorated());
QVERIFY(!c->noBorder());
......@@ -261,15 +272,20 @@ void DecorationInputTest::testDoubleTap_data()
{
QTest::addColumn<QPoint>("decoPoint");
QTest::addColumn<Qt::WindowFrameSection>("expectedSection");
QTest::newRow("topLeft") << QPoint(0, 0) << Qt::TopLeftSection;
QTest::newRow("top") << QPoint(250, 0) << Qt::TopSection;
QTest::newRow("topRight") << QPoint(499, 0) << Qt::TopRightSection;
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("topLeft") << QPoint(0, 0) << Qt::TopLeftSection << Test::ShellSurfaceType::WlShell;
QTest::newRow("top") << QPoint(250, 0) << Qt::TopSection << Test::ShellSurfaceType::WlShell;
QTest::newRow("topRight") << QPoint(499, 0) << Qt::TopRightSection << Test::ShellSurfaceType::WlShell;
QTest::newRow("topLeft|xdg") << QPoint(0, 0) << Qt::TopLeftSection << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("top|xdg") << QPoint(250, 0) << Qt::TopSection << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("topRight|xdg") << QPoint(499, 0) << Qt::TopRightSection << Test::ShellSurfaceType::XdgShellV5;
}
void KWin::DecorationInputTest::testDoubleTap()
{
AbstractClient *c = showWindow();
QFETCH(Test::ShellSurfaceType, type);
AbstractClient *c = showWindow(type);
QVERIFY(c);
QVERIFY(c->isDecorated());
QVERIFY(!c->noBorder());
......@@ -306,9 +322,18 @@ void KWin::DecorationInputTest::testDoubleTap()
QVERIFY(c->isOnAllDesktops());
}
void DecorationInputTest::testHover_data()
{
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
}
void DecorationInputTest::testHover()
{
AbstractClient *c = showWindow();
QFETCH(Test::ShellSurfaceType, type);
AbstractClient *c = showWindow(type);
QVERIFY(c);
QVERIFY(c->isDecorated());
QVERIFY(!c->noBorder());
......@@ -347,16 +372,22 @@ void DecorationInputTest::testPressToMove_data()
QTest::addColumn<QPoint>("offset");
QTest::addColumn<QPoint>("offset2");
QTest::addColumn<QPoint>("offset3");
QTest::newRow("To right") << QPoint(10, 0) << QPoint(20, 0) << QPoint(30, 0);
QTest::newRow("To left") << QPoint(-10, 0) << QPoint(-20, 0) << QPoint(-30, 0);
QTest::newRow("To bottom") << QPoint(0, 10) << QPoint(0, 20) << QPoint(0, 30);
QTest::newRow("To top") << QPoint(0, -10) << QPoint(0, -20) << QPoint(0, -30);
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("To right") << QPoint(10, 0) << QPoint(20, 0) << QPoint(30, 0) << Test::ShellSurfaceType::WlShell;
QTest::newRow("To left") << QPoint(-10, 0) << QPoint(-20, 0) << QPoint(-30, 0) << Test::ShellSurfaceType::WlShell;
QTest::newRow("To bottom") << QPoint(0, 10) << QPoint(0, 20) << QPoint(0, 30) << Test::ShellSurfaceType::WlShell;
QTest::newRow("To top") << QPoint(0, -10) << QPoint(0, -20) << QPoint(0, -30) << Test::ShellSurfaceType::WlShell;
QTest::newRow("To right|xdg") << QPoint(10, 0) << QPoint(20, 0) << QPoint(30, 0) << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("To left|xdg") << QPoint(-10, 0) << QPoint(-20, 0) << QPoint(-30, 0) << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("To bottom|xdg") << QPoint(0, 10) << QPoint(0, 20) << QPoint(0, 30) << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("To top|xdg") << QPoint(0, -10) << QPoint(0, -20) << QPoint(0, -30) << Test::ShellSurfaceType::XdgShellV5;
}
void DecorationInputTest::testPressToMove()
{
AbstractClient *c = showWindow();
QFETCH(Test::ShellSurfaceType, type);
AbstractClient *c = showWindow(type);
QVERIFY(c);
QVERIFY(c->isDecorated());
QVERIFY(!c->noBorder());
......@@ -406,16 +437,22 @@ void DecorationInputTest::testTapToMove_data()
QTest::addColumn<QPoint>("offset");
QTest::addColumn<QPoint>("offset2");
QTest::addColumn<QPoint>("offset3");
QTest::newRow("To right") << QPoint(10, 0) << QPoint(20, 0) << QPoint(30, 0);
QTest::newRow("To left") << QPoint(-10, 0) << QPoint(-20, 0) << QPoint(-30, 0);
QTest::newRow("To bottom") << QPoint(0, 10) << QPoint(0, 20) << QPoint(0, 30);
QTest::newRow("To top") << QPoint(0, -10) << QPoint(0, -20) << QPoint(0, -30);
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("To right") << QPoint(10, 0) << QPoint(20, 0) << QPoint(30, 0) << Test::ShellSurfaceType::WlShell;
QTest::newRow("To left") << QPoint(-10, 0) << QPoint(-20, 0) << QPoint(-30, 0) << Test::ShellSurfaceType::WlShell;
QTest::newRow("To bottom") << QPoint(0, 10) << QPoint(0, 20) << QPoint(0, 30) << Test::ShellSurfaceType::WlShell;
QTest::newRow("To top") << QPoint(0, -10) << QPoint(0, -20) << QPoint(0, -30) << Test::ShellSurfaceType::WlShell;
QTest::newRow("To right|xdg") << QPoint(10, 0) << QPoint(20, 0) << QPoint(30, 0) << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("To left|xdg") << QPoint(-10, 0) << QPoint(-20, 0) << QPoint(-30, 0) << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("To bottom|xdg") << QPoint(0, 10) << QPoint(0, 20) << QPoint(0, 30) << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("To top|xdg") << QPoint(0, -10) << QPoint(0, -20) << QPoint(0, -30) << Test::ShellSurfaceType::XdgShellV5;
}
void DecorationInputTest::testTapToMove()
{
AbstractClient *c = showWindow();
QFETCH(Test::ShellSurfaceType, type);
AbstractClient *c = showWindow(type);
QVERIFY(c);
QVERIFY(c->isDecorated());
QVERIFY(!c->noBorder());
......
......@@ -49,6 +49,7 @@ private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void testCreateWindow_data();
void testCreateWindow();
};
......@@ -94,6 +95,14 @@ void DontCrashNoBorder::cleanup()
Test::destroyWaylandConnection();
}
void DontCrashNoBorder::testCreateWindow_data()
{
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
}
void DontCrashNoBorder::testCreateWindow()
{
// create a window and ensure that this doesn't crash
......@@ -101,7 +110,8 @@ void DontCrashNoBorder::testCreateWindow()
QScopedPointer<Surface> surface(Test::createSurface());
QVERIFY(!surface.isNull());
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
QFETCH(Test::ShellSurfaceType, type);
QScopedPointer<QObject> shellSurface(Test::createShellSurface(type, surface.data()));
QVERIFY(shellSurface);
QScopedPointer<ServerSideDecoration> deco(Test::waylandServerSideDecoration()->create(surface.data()));
QSignalSpy decoSpy(deco.data(), &ServerSideDecoration::modeChanged);
......
......@@ -53,6 +53,7 @@ private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void testPointerFocusUpdatesOnStackingOrderChange_data();
void testPointerFocusUpdatesOnStackingOrderChange();
private:
......@@ -100,6 +101,14 @@ void InputStackingOrderTest::render(KWayland::Client::Surface *surface)
Test::flushWaylandConnection();
}
void InputStackingOrderTest::testPointerFocusUpdatesOnStackingOrderChange_data()
{
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
}
void InputStackingOrderTest::testPointerFocusUpdatesOnStackingOrderChange()
{
// this test creates two windows which overlap
......@@ -121,7 +130,8 @@ void InputStackingOrderTest::testPointerFocusUpdatesOnStackingOrderChange()
QVERIFY(clientAddedSpy.isValid());
Surface *surface1 = Test::createSurface(Test::waylandCompositor());
QVERIFY(surface1);
ShellSurface *shellSurface1 = Test::createShellSurface(surface1, surface1);
QFETCH(Test::ShellSurfaceType, type);
auto shellSurface1 = Test::createShellSurface(type, surface1, surface1);
QVERIFY(shellSurface1);
render(surface1);
QVERIFY(clientAddedSpy.wait());
......@@ -130,7 +140,7 @@ void InputStackingOrderTest::testPointerFocusUpdatesOnStackingOrderChange()
Surface *surface2 = Test::createSurface(Test::waylandCompositor());
QVERIFY(surface2);
ShellSurface *shellSurface2 = Test::createShellSurface(surface2, surface2);
auto shellSurface2 = Test::createShellSurface(type, surface2, surface2);
QVERIFY(shellSurface2);
render(surface2);
QVERIFY(clientAddedSpy.wait());
......
......@@ -39,6 +39,7 @@ class Shell;
class ShellSurface;
class ShmPool;
class Surface;
class XdgShellSurface;
}
}
......@@ -112,7 +113,13 @@ bool waitForWaylandTouch();
void flushWaylandConnection();
KWayland::Client::Surface *createSurface(QObject *parent = nullptr);
enum class ShellSurfaceType {
WlShell,
XdgShellV5
};
QObject *createShellSurface(ShellSurfaceType type, KWayland::Client::Surface *surface, QObject *parent = nullptr);
KWayland::Client::ShellSurface *createShellSurface(KWayland::Client::Surface *surface, QObject *parent = nullptr);
KWayland::Client::XdgShellSurface *createXdgShellV5Surface(KWayland::Client::Surface *surface, QObject *parent = nullptr);
/**
* Creates a shared memory buffer of @p size in @p color and attaches it to the @p surface.
......@@ -140,6 +147,7 @@ bool waitForWindowDestroyed(AbstractClient *client);
}
Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::Test::AdditionalWaylandInterfaces)
Q_DECLARE_METATYPE(KWin::Test::ShellSurfaceType)
#define WAYLANDTEST_MAIN_HELPER(TestObject, DPI) \
int main(int argc, char *argv[]) \
......
......@@ -47,6 +47,7 @@ private Q_SLOTS:
void cleanup();
void testStartFrame();
void testCursorMoving();
void testWindow_data();
void testWindow();
};
......@@ -133,14 +134,24 @@ void SceneQPainterTest::testCursorMoving()
QCOMPARE(referenceImage, *scene->backend()->buffer());
}
void SceneQPainterTest::testWindow_data()
{
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
}
void SceneQPainterTest::testWindow()
{
KWin::Cursor::setPos(45, 45);
// this test verifies that a window is rendered correctly
using namespace KWayland::Client;
QVERIFY(Test::setupWaylandConnection(s_socketName, Test::AdditionalWaylandInterface::Seat));
QVERIFY(Test::waitForWaylandPointer());
QScopedPointer<Surface> s(Test::createSurface());
QScopedPointer<ShellSurface> ss(Test::createShellSurface(s.data()));
QFETCH(Test::ShellSurfaceType, type);
QScopedPointer<QObject> ss(Test::createShellSurface(type, s.data()));
QScopedPointer<Pointer> p(Test::waylandSeat()->createPointer());
auto scene = qobject_cast<SceneQPainter*>(KWin::Compositor::self()->scene());
......
......@@ -46,6 +46,7 @@ private Q_SLOTS:
void init();
void cleanup();
void testMapUnmapMap_data();
void testMapUnmapMap();
void testDesktopPresenceChanged();
};
......@@ -81,6 +82,14 @@ void TestShellClient::cleanup()
Test::destroyWaylandConnection();
}
void TestShellClient::testMapUnmapMap_data()
{
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
}
void TestShellClient::testMapUnmapMap()
{
// this test verifies that mapping a previously mapped window works correctly
......@@ -92,7 +101,8 @@ void TestShellClient::testMapUnmapMap()
QVERIFY(effectsWindowHiddenSpy.isValid());
QScopedPointer<Surface> surface(Test::createSurface());
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
QFETCH(Test::ShellSurfaceType, type);
QScopedPointer<QObject> shellSurface(Test::createShellSurface(type, surface.data()));
// now let's render
Test::render(surface.data(), QSize(100, 50), Qt::blue);
......
......@@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Client/shell.h>
#include <KWayland/Client/shm_pool.h>
#include <KWayland/Client/surface.h>
#include <KWayland/Client/xdgshell.h>
#include <QThread>
......@@ -48,6 +49,7 @@ static struct {
Compositor *compositor = nullptr;
ServerSideDecorationManager *decoration = nullptr;
Shell *shell = nullptr;
XdgShell *xdgShellV5 = nullptr;
ShmPool *shm = nullptr;
Seat *seat = nullptr;
PlasmaShell *plasmaShell = nullptr;
......@@ -110,6 +112,10 @@ bool setupWaylandConnection(const QString &socketName, AdditionalWaylandInterfac
if (!s_waylandConnection.shell->isValid()) {
return false;
}
s_waylandConnection.xdgShellV5 = registry.createXdgShell(registry.interface(Registry::Interface::XdgShellUnstableV5).name, registry.interface(Registry::Interface::XdgShellUnstableV5).version);
if (!s_waylandConnection.xdgShellV5->isValid()) {
return false;
}
if (flags.testFlag(AdditionalWaylandInterface::Seat)) {
s_waylandConnection.seat = registry.createSeat(registry.interface(Registry::Interface::Seat).name, registry.interface(Registry::Interface::Seat).version);
if (!s_waylandConnection.seat->isValid()) {
......@@ -155,6 +161,8 @@ void destroyWaylandConnection()
s_waylandConnection.decoration = nullptr;
delete s_waylandConnection.seat;
s_waylandConnection.seat = nullptr;
delete s_waylandConnection.xdgShellV5;
s_waylandConnection.xdgShellV5 = nullptr;
delete s_waylandConnection.shell;
s_waylandConnection.shell = nullptr;
delete s_waylandConnection.shm;
......@@ -305,6 +313,32 @@ ShellSurface *createShellSurface(Surface *surface, QObject *parent)
return s;
}
XdgShellSurface *createXdgShellV5Surface(Surface *surface, QObject *parent)
{
if (!s_waylandConnection.xdgShellV5) {
return nullptr;
}
auto s = s_waylandConnection.xdgShellV5->createSurface(surface, parent);
if (!s->isValid()) {
delete s;
return nullptr;
}
return s;
}
QObject *createShellSurface(ShellSurfaceType type, KWayland::Client::Surface *surface, QObject *parent)
{
switch (type) {
case ShellSurfaceType::WlShell:
return createShellSurface(surface, parent);
case ShellSurfaceType::XdgShellV5:
return createXdgShellV5Surface(surface, parent);
default:
Q_UNREACHABLE();
return nullptr;
}
}
bool waitForWindowDestroyed(AbstractClient *client)
{
QSignalSpy destroyedSpy(client, &QObject::destroyed);
......
......@@ -41,7 +41,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Server/server_decoration_interface.h>
#include <KWayland/Server/qtsurfaceextension_interface.h>
#include <KWayland/Server/plasmawindowmanagement_interface.h>
#include <KDesktopFile>
#include <QOpenGLFramebufferObject>
......@@ -55,6 +54,30 @@ namespace KWin
ShellClient::ShellClient(ShellSurfaceInterface *surface)
: AbstractClient()
, m_shellSurface(surface)
, m_xdgShellSurface(nullptr)
, m_xdgShellPopup(nullptr)
, m_internal(surface->client() == waylandServer()->internalConnection())
{
setSurface(surface->surface());
init();
}
ShellClient::ShellClient(XdgShellSurfaceInterface *surface)
: AbstractClient()
, m_shellSurface(nullptr)
, m_xdgShellSurface(surface)
, m_xdgShellPopup(nullptr)
, m_internal(surface->client() == waylandServer()->internalConnection())
{
setSurface(surface->surface());
init();
}
ShellClient::ShellClient(XdgShellPopupInterface *surface)
: AbstractClient()
, m_shellSurface(nullptr)
, m_xdgShellSurface(nullptr)
, m_xdgShellPopup(surface)
, m_internal(surface->client() == waylandServer()->internalConnection())
{
setSurface(surface->surface());
......@@ -63,6 +86,78 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface)
ShellClient::~ShellClient() = default;
template <class T>
void ShellClient::initSurface(T *shellSurface)
{
m_caption = shellSurface->title();
connect(shellSurface, &T::titleChanged, this, &ShellClient::captionChanged);
connect(shellSurface, &T::destroyed, this, &ShellClient::destroyClient);
connect(shellSurface, &T::titleChanged, this,
[this] (const QString &s) {
m_caption = s;
emit captionChanged();
}
);
connect(shellSurface, &T::moveRequested, this,
[this] {
// TODO: check the seat and serial
performMouseCommand(Options::MouseMove, Cursor::pos());
}
);
connect(shellSurface, &T::windowClassChanged, this, &ShellClient::updateIcon);
setResourceClass(shellSurface->windowClass());
connect(shellSurface, &T::windowClassChanged, this,
[this] (const QByteArray &windowClass) {
setResourceClass(windowClass);
}
);
connect(shellSurface, &T::resizeRequested, this,
[this] (SeatInterface *seat, quint32 serial, Qt::Edges edges) {
// TODO: check the seat and serial
Q_UNUSED(seat)
Q_UNUSED(serial)
if (!isResizable() || isShade()) {
return;
}
if (isMoveResize()) {
finishMoveResize(false);
}
setMoveResizePointerButtonDown(true);
setMoveOffset(Cursor::pos() - pos()); // map from global
setInvertedMoveOffset(rect().bottomRight() - moveOffset());
setUnrestrictedMoveResize(false);
auto toPosition = [edges] {
Position pos = PositionCenter;
if (edges.testFlag(Qt::TopEdge)) {
pos = PositionTop;
} else if (edges.testFlag(Qt::BottomEdge)) {
pos = PositionBottom;
}
if (edges.testFlag(Qt::LeftEdge)) {
pos = Position(pos | PositionLeft);
} else if (edges.testFlag(Qt::RightEdge)) {
pos = Position(pos | PositionRight);
}
return pos;
};
setMoveResizePointerMode(toPosition());
if (!startMoveResize())
setMoveResizePointerButtonDown(false);
updateCursor();
}
);
connect(shellSurface, &T::maximizedChanged, this,
[this] (bool maximized) {
maximize(maximized ? MaximizeFull : MaximizeRestore);
}
);
// TODO: consider output!
connect(shellSurface, &T::fullscreenChanged, this, &ShellClient::clientFullScreenChanged);
connect(shellSurface, &T::transientForChanged, this, &ShellClient::setTransient);
}
void ShellClient::init()
{
findInternalWindow();
......@@ -101,71 +196,33 @@ void ShellClient::init()
connect(s, &SurfaceInterface::unmapped, this, &ShellClient::unmap);
connect(s, &SurfaceInterface::destroyed, this, &ShellClient::destroyClient);
if (m_shellSurface) {
m_caption = m_shellSurface->title();
connect(m_shellSurface, &ShellSurfaceInterface::destroyed, this, &ShellClient::destroyClient);
connect(m_shellSurface, &ShellSurfaceInterface::titleChanged, this,
[this] {
m_caption = m_shellSurface->title();
emit captionChanged();
}
);
connect(m_shellSurface, &ShellSurfaceInterface::fullscreenChanged, this, &ShellClient::clientFullScreenChanged);
connect(m_shellSurface, &ShellSurfaceInterface::maximizedChanged, this,
[this] (bool maximized) {
maximize(maximized ? MaximizeFull : MaximizeRestore);
}