Wayland foreign protocol

Summary:
Implement the "foreign" wayland protocol.
A client can export a surface with an unique string as handle,
then another client can refer to that surface and set an own surface as
child of that surface.
Potential use cases are out-of-process dialogs, such as file dialogs,
meant to be used by sandboxed processes that may not have the access
it needs to implement such dialogs.
The handle needs to be shared between the processes with other means,
such as dbus or command line paramenters.

The public api of the server side only tracks parent/child relationships as this is the only data kwin would need it for, the rest of the api is not exported so should be safer from eventual protocol changes

Test Plan:
the autotest works, but has a lot of random crashes when deleting surfaces,
unfortunately backtraces don't tell much and the crashes never occur when running into valgrind
behavior may still be wrong, depending on how the protocol is supposed
to work if more clients try to set the same exported surface as parent

Reviewers: #plasma, #kwin, davidedmundson, graesslin

Reviewed By: #plasma, #kwin, graesslin

Subscribers: davidedmundson, graesslin, plasma-devel, #frameworks

Tags: #frameworks, #plasma_on_wayland

Differential Revision: https://phabricator.kde.org/D7369
This commit is contained in:
Marco Martin 2017-10-13 11:29:17 +02:00
parent 4abf4183e0
commit 9feb359676
11 changed files with 1407 additions and 0 deletions

View file

@ -45,6 +45,8 @@ set(SERVER_LIB_SRCS
textinput_interface_v2.cpp textinput_interface_v2.cpp
xdgshell_interface.cpp xdgshell_interface.cpp
xdgshell_v5_interface.cpp xdgshell_v5_interface.cpp
xdgforeign_v2_interface.cpp
xdgforeign_interface.cpp
xdgshell_v6_interface.cpp xdgshell_v6_interface.cpp
) )
@ -147,6 +149,11 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
BASENAME pointer-constraints-unstable-v1 BASENAME pointer-constraints-unstable-v1
) )
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-foreign-unstable-v2.xml
BASENAME xdg-foreign-unstable-v2
)
add_library(KF5WaylandServer ${SERVER_LIB_SRCS}) add_library(KF5WaylandServer ${SERVER_LIB_SRCS})
generate_export_header(KF5WaylandServer generate_export_header(KF5WaylandServer
BASE_NAME BASE_NAME
@ -216,6 +223,7 @@ set(SERVER_LIB_HEADERS
textinput_interface.h textinput_interface.h
touch_interface.h touch_interface.h
xdgshell_interface.h xdgshell_interface.h
xdgforeign_interface.h
) )
install(FILES install(FILES

View file

@ -349,6 +349,17 @@ target_link_libraries( testXdgShellV5 Qt5::Test Qt5::Gui KF5::WaylandServer KF5:
add_test(NAME kwayland-testXdgShellV5 COMMAND testXdgShellV5) add_test(NAME kwayland-testXdgShellV5 COMMAND testXdgShellV5)
ecm_mark_as_test(testXdgShellV5) ecm_mark_as_test(testXdgShellV5)
########################################################
# Test XdgForeign
########################################################
set( testXdgForeign_SRCS
test_xdg_foreign.cpp
)
add_executable(testXdgForeign ${testXdgForeign_SRCS})
target_link_libraries( testXdgForeign Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client)
add_test(NAME kwayland-testXdgForeign COMMAND testXdgForeign)
ecm_mark_as_test(testXdgForeign)
######################################################## ########################################################
# Test XdgShellV6 # Test XdgShellV6
######################################################## ########################################################

View file

@ -0,0 +1,401 @@
/********************************************************************
Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
Copyright 2017 Marco Martin <mart@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
// Qt
#include <QtTest/QtTest>
// KWin
#include "../../src/client/compositor.h"
#include "../../src/client/connection_thread.h"
#include "../../src/client/event_queue.h"
#include "../../src/client/region.h"
#include "../../src/client/registry.h"
#include "../../src/client/surface.h"
#include "../../src/client/xdgforeign.h"
#include "../../src/server/display.h"
#include "../../src/server/compositor_interface.h"
#include "../../src/server/surface_interface.h"
#include "../../src/server/xdgforeign_interface.h"
using namespace KWayland::Client;
class TestForeign : public QObject
{
Q_OBJECT
public:
explicit TestForeign(QObject *parent = nullptr);
private Q_SLOTS:
void init();
void cleanup();
void testExport();
void testDeleteImported();
void testDeleteChildSurface();
void testDeleteParentSurface();
void testDeleteExported();
void testExportTwoTimes();
void testImportTwoTimes();
private:
void doExport();
KWayland::Server::Display *m_display;
KWayland::Server::CompositorInterface *m_compositorInterface;
KWayland::Server::XdgForeignInterface *m_foreignInterface;
KWayland::Client::ConnectionThread *m_connection;
KWayland::Client::Compositor *m_compositor;
KWayland::Client::EventQueue *m_queue;
KWayland::Client::XdgExporter *m_exporter;
KWayland::Client::XdgImporter *m_importer;
QPointer<KWayland::Client::Surface> m_exportedSurface;
QPointer<KWayland::Server::SurfaceInterface> m_exportedSurfaceInterface;
QPointer<KWayland::Client::XdgExported> m_exported;
QPointer<KWayland::Client::XdgImported> m_imported;
QPointer<KWayland::Client::Surface> m_childSurface;
QPointer<KWayland::Server::SurfaceInterface> m_childSurfaceInterface;
QThread *m_thread;
};
static const QString s_socketName = QStringLiteral("kwayland-test-xdg-foreign-0");
TestForeign::TestForeign(QObject *parent)
: QObject(parent)
, m_display(nullptr)
, m_compositorInterface(nullptr)
, m_connection(nullptr)
, m_compositor(nullptr)
, m_queue(nullptr)
, m_exporter(nullptr)
, m_importer(nullptr)
, m_thread(nullptr)
{
}
void TestForeign::init()
{
using namespace KWayland::Server;
delete m_display;
m_display = new Display(this);
m_display->setSocketName(s_socketName);
m_display->start();
QVERIFY(m_display->isRunning());
qRegisterMetaType<KWayland::Server::SurfaceInterface*>("KWayland::Server::SurfaceInterface");
// setup connection
m_connection = new KWayland::Client::ConnectionThread;
QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected);
QVERIFY(connectedSpy.isValid());
m_connection->setSocketName(s_socketName);
m_thread = new QThread(this);
m_connection->moveToThread(m_thread);
m_thread->start();
m_connection->initConnection();
QVERIFY(connectedSpy.wait());
m_queue = new KWayland::Client::EventQueue(this);
QVERIFY(!m_queue->isValid());
m_queue->setup(m_connection);
QVERIFY(m_queue->isValid());
Registry registry;
QSignalSpy compositorSpy(&registry, &Registry::compositorAnnounced);
QVERIFY(compositorSpy.isValid());
QSignalSpy exporterSpy(&registry, &Registry::exporterUnstableV2Announced);
QVERIFY(exporterSpy.isValid());
QSignalSpy importerSpy(&registry, &Registry::importerUnstableV2Announced);
QVERIFY(importerSpy.isValid());
QVERIFY(!registry.eventQueue());
registry.setEventQueue(m_queue);
QCOMPARE(registry.eventQueue(), m_queue);
registry.create(m_connection->display());
QVERIFY(registry.isValid());
registry.setup();
m_compositorInterface = m_display->createCompositor(m_display);
m_compositorInterface->create();
QVERIFY(m_compositorInterface->isValid());
QVERIFY(compositorSpy.wait());
m_compositor = registry.createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
m_foreignInterface = m_display->createXdgForeignInterface(m_display);
m_foreignInterface->create();
QVERIFY(m_foreignInterface->isValid());
QVERIFY(exporterSpy.wait());
//Both importer and exporter should have been triggered by now
QCOMPARE(exporterSpy.count(), 1);
QCOMPARE(importerSpy.count(), 1);
m_exporter = registry.createXdgExporter(exporterSpy.first().first().value<quint32>(), exporterSpy.first().last().value<quint32>(), this);
m_importer = registry.createXdgImporter(importerSpy.first().first().value<quint32>(), importerSpy.first().last().value<quint32>(), this);
}
void TestForeign::cleanup()
{
#define CLEANUP(variable) \
if (variable) { \
delete variable; \
variable = nullptr; \
}
//some tests delete it beforehand
if (m_exportedSurfaceInterface) {
QSignalSpy exportedSurfaceDestroyedSpy(m_exportedSurfaceInterface.data(), &QObject::destroyed);
QVERIFY(exportedSurfaceDestroyedSpy.isValid());
CLEANUP(m_exportedSurface)
exportedSurfaceDestroyedSpy.wait();
}
if (m_childSurfaceInterface) {
QSignalSpy childSurfaceDestroyedSpy(m_childSurfaceInterface.data(), &QObject::destroyed);
QVERIFY(childSurfaceDestroyedSpy.isValid());
CLEANUP(m_childSurface)
childSurfaceDestroyedSpy.wait();
}
CLEANUP(m_compositor)
CLEANUP(m_exporter)
CLEANUP(m_importer)
CLEANUP(m_queue)
if (m_connection) {
m_connection->deleteLater();
m_connection = nullptr;
}
if (m_thread) {
m_thread->quit();
m_thread->wait();
delete m_thread;
m_thread = nullptr;
}
CLEANUP(m_compositorInterface)
CLEANUP(m_foreignInterface)
CLEANUP(m_display)
#undef CLEANUP
}
void TestForeign::doExport()
{
QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*)));
QVERIFY(serverSurfaceCreated.isValid());
m_exportedSurface = m_compositor->createSurface();
QVERIFY(serverSurfaceCreated.wait());
m_exportedSurfaceInterface = serverSurfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
//Export a window
m_exported = m_exporter->exportTopLevel(m_exportedSurface, this);
QVERIFY(m_exported->handle().isEmpty());
QSignalSpy doneSpy(m_exported.data(), &XdgExported::done);
QVERIFY(doneSpy.wait());
QVERIFY(!m_exported->handle().isEmpty());
QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignInterface::transientChanged);
QVERIFY(transientSpy.isValid());
//Import the just exported window
m_imported = m_importer->importTopLevel(m_exported->handle(), this);
QVERIFY(m_imported->isValid());
QSignalSpy childSurfaceInterfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*)));
QVERIFY(serverSurfaceCreated.isValid());
m_childSurface = m_compositor->createSurface();
QVERIFY(childSurfaceInterfaceCreated.wait());
m_childSurfaceInterface = childSurfaceInterfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
m_childSurface->commit(Surface::CommitFlag::None);
m_imported->setParentOf(m_childSurface);
QVERIFY(transientSpy.wait());
QCOMPARE(transientSpy.first().first().value<KWayland::Server::SurfaceInterface *>(), m_childSurfaceInterface.data());
QCOMPARE(transientSpy.first().at(1).value<KWayland::Server::SurfaceInterface *>(), m_exportedSurfaceInterface.data());
//transientFor api
QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), m_exportedSurfaceInterface.data());
}
void TestForeign::testExport()
{
doExport();
}
void TestForeign::testDeleteImported()
{
doExport();
QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignInterface::transientChanged);
QVERIFY(transientSpy.isValid());
m_imported->deleteLater();
m_imported = nullptr;
QVERIFY(transientSpy.wait());
QCOMPARE(transientSpy.first().first().value<KWayland::Server::SurfaceInterface *>(), m_childSurfaceInterface.data());
QCOMPARE(transientSpy.first().at(1).value<KWayland::Server::SurfaceInterface *>(), nullptr);
QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), nullptr);
}
void TestForeign::testDeleteChildSurface()
{
doExport();
QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignInterface::transientChanged);
QVERIFY(transientSpy.isValid());
m_childSurface->deleteLater();
QVERIFY(transientSpy.wait());
//when the client surface dies, the server one will eventually die too
QSignalSpy surfaceDestroyedSpy(m_childSurfaceInterface, SIGNAL(destroyed()));
QVERIFY(surfaceDestroyedSpy.wait());
QCOMPARE(transientSpy.first().at(0).value<KWayland::Server::SurfaceInterface *>(), nullptr);
QCOMPARE(transientSpy.first().at(1).value<KWayland::Server::SurfaceInterface *>(), m_exportedSurfaceInterface.data());
}
void TestForeign::testDeleteParentSurface()
{
doExport();
QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignInterface::transientChanged);
QVERIFY(transientSpy.isValid());
m_exportedSurface->deleteLater();
QSignalSpy exportedSurfaceDestroyedSpy(m_exportedSurfaceInterface.data(), &QObject::destroyed);
QVERIFY(exportedSurfaceDestroyedSpy.isValid());
exportedSurfaceDestroyedSpy.wait();
QVERIFY(transientSpy.wait());
QCOMPARE(transientSpy.first().first().value<KWayland::Server::SurfaceInterface *>(), m_childSurfaceInterface.data());
QCOMPARE(transientSpy.first().at(1).value<KWayland::Server::SurfaceInterface *>(), nullptr);
QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), nullptr);
}
void TestForeign::testDeleteExported()
{
doExport();
QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignInterface::transientChanged);
QSignalSpy destroyedSpy(m_imported.data(), &KWayland::Client::XdgImported::importedDestroyed);
QVERIFY(transientSpy.isValid());
m_exported->deleteLater();
m_exported = nullptr;
QVERIFY(transientSpy.wait());
QVERIFY(destroyedSpy.wait());
QCOMPARE(transientSpy.first().first().value<KWayland::Server::SurfaceInterface *>(), m_childSurfaceInterface.data());
QCOMPARE(transientSpy.first().at(1).value<KWayland::Server::SurfaceInterface *>(), nullptr);
QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), nullptr);
QVERIFY(!m_imported->isValid());
}
void TestForeign::testExportTwoTimes()
{
doExport();
//Export second window
KWayland::Client::XdgExported *exported2 = m_exporter->exportTopLevel(m_exportedSurface, this);
QVERIFY(exported2->handle().isEmpty());
QSignalSpy doneSpy(exported2, &XdgExported::done);
QVERIFY(doneSpy.wait());
QVERIFY(!exported2->handle().isEmpty());
QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignInterface::transientChanged);
QVERIFY(transientSpy.isValid());
//Import the just exported window
KWayland::Client::XdgImported *imported2 = m_importer->importTopLevel(exported2->handle(), this);
QVERIFY(imported2->isValid());
//create a second child surface
QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*)));
QVERIFY(serverSurfaceCreated.isValid());
KWayland::Client::Surface *childSurface2 = m_compositor->createSurface();
QVERIFY(serverSurfaceCreated.wait());
KWayland::Server::SurfaceInterface *childSurface2Interface = serverSurfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
imported2->setParentOf(childSurface2);
QVERIFY(transientSpy.wait());
QCOMPARE(transientSpy.first().first().value<KWayland::Server::SurfaceInterface *>(), childSurface2Interface);
QCOMPARE(transientSpy.first().at(1).value<KWayland::Server::SurfaceInterface *>(), m_exportedSurfaceInterface.data());
//transientFor api
//check the old relationship is still here
QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), m_exportedSurfaceInterface.data());
//check the new relationship
QCOMPARE(m_foreignInterface->transientFor(childSurface2Interface), m_exportedSurfaceInterface.data());
}
void TestForeign::testImportTwoTimes()
{
doExport();
QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignInterface::transientChanged);
QVERIFY(transientSpy.isValid());
//Import another time the exported window
KWayland::Client::XdgImported *imported2 = m_importer->importTopLevel(m_exported->handle(), this);
QVERIFY(imported2->isValid());
//create a second child surface
QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*)));
QVERIFY(serverSurfaceCreated.isValid());
KWayland::Client::Surface *childSurface2 = m_compositor->createSurface();
QVERIFY(serverSurfaceCreated.wait());
KWayland::Server::SurfaceInterface *childSurface2Interface = serverSurfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
imported2->setParentOf(childSurface2);
QVERIFY(transientSpy.wait());
QCOMPARE(transientSpy.first().first().value<KWayland::Server::SurfaceInterface *>(), childSurface2Interface);
QCOMPARE(transientSpy.first().at(1).value<KWayland::Server::SurfaceInterface *>(), m_exportedSurfaceInterface.data());
//transientFor api
//check the old relationship is still here
QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), m_exportedSurfaceInterface.data());
//check the new relationship
QCOMPARE(m_foreignInterface->transientFor(childSurface2Interface), m_exportedSurfaceInterface.data());
}
QTEST_GUILESS_MAIN(TestForeign)
#include "test_xdg_foreign.moc"

View file

@ -44,6 +44,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "subcompositor_interface.h" #include "subcompositor_interface.h"
#include "textinput_interface_p.h" #include "textinput_interface_p.h"
#include "xdgshell_v5_interface_p.h" #include "xdgshell_v5_interface_p.h"
#include "xdgforeign_interface.h"
#include "xdgshell_v6_interface_p.h" #include "xdgshell_v6_interface_p.h"
#include <QCoreApplication> #include <QCoreApplication>
@ -412,6 +413,13 @@ PointerConstraintsInterface *Display::createPointerConstraints(const PointerCons
return p; return p;
} }
XdgForeignInterface *Display::createXdgForeignInterface(QObject *parent)
{
XdgForeignInterface *foreign = new XdgForeignInterface(this, parent);
connect(this, &Display::aboutToTerminate, foreign, [this,foreign] { delete foreign; });
return foreign;
}
void Display::createShm() void Display::createShm()
{ {
Q_ASSERT(d->display); Q_ASSERT(d->display);

View file

@ -80,6 +80,7 @@ enum class PointerGesturesInterfaceVersion;
class PointerGesturesInterface; class PointerGesturesInterface;
enum class PointerConstraintsInterfaceVersion; enum class PointerConstraintsInterfaceVersion;
class PointerConstraintsInterface; class PointerConstraintsInterface;
class XdgForeignInterface;
/** /**
* @brief Class holding the Wayland server display loop. * @brief Class holding the Wayland server display loop.
@ -219,6 +220,13 @@ public:
**/ **/
PointerConstraintsInterface *createPointerConstraints(const PointerConstraintsInterfaceVersion &version, QObject *parent = nullptr); PointerConstraintsInterface *createPointerConstraints(const PointerConstraintsInterfaceVersion &version, QObject *parent = nullptr);
/**
* Creates the XdgForeignInterface in interface @p version
*
* @returns The created manager object
* @since 5.40
**/
XdgForeignInterface *createXdgForeignInterface(QObject *parent = nullptr);
/** /**
* Gets the ClientConnection for the given @p client. * Gets the ClientConnection for the given @p client.
* If there is no ClientConnection yet for the given @p client, it will be created. * If there is no ClientConnection yet for the given @p client, it will be created.

View file

@ -0,0 +1,79 @@
/****************************************************************************
Copyright 2017 Marco Martin <notmart@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "xdgforeign_interface.h"
#include "xdgforeign_v2_interface_p.h"
#include "display.h"
#include "global_p.h"
#include "resource_p.h"
#include "surface_interface_p.h"
#include "wayland-xdg-foreign-unstable-v2-server-protocol.h"
#include <QUuid>
#include <QDebug>
namespace KWayland
{
namespace Server
{
XdgForeignInterface::Private::Private(Display *display, XdgForeignInterface *q)
: q(q)
{
exporter = new XdgExporterUnstableV2Interface(display, q);
importer = new XdgImporterUnstableV2Interface(display, q);
connect(importer, &XdgImporterUnstableV2Interface::transientChanged,
q, &XdgForeignInterface::transientChanged);
}
XdgForeignInterface::XdgForeignInterface(Display *display, QObject *parent)
: QObject(parent),
d(new Private(display, this))
{
}
XdgForeignInterface::~XdgForeignInterface()
{
delete d->exporter;
delete d->importer;
delete d;
}
void XdgForeignInterface::create()
{
d->exporter->create();
d->importer->create();
}
bool XdgForeignInterface::isValid()
{
return d->exporter->isValid() && d->importer->isValid();
}
SurfaceInterface *XdgForeignInterface::transientFor(SurfaceInterface *surface)
{
return d->importer->transientFor(surface);
}
}
}

View file

@ -0,0 +1,97 @@
/****************************************************************************
Copyright 2017 Marco Martin <notmart@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef KWAYLAND_SERVER_XDGFOREIGN_H
#define KWAYLAND_SERVER_XDGFOREIGN_H
#include "global.h"
#include "resource.h"
#include <KWayland/Server/kwaylandserver_export.h>
namespace KWayland
{
namespace Server
{
class Display;
class SurfaceInterface;
class XdgExporterUnstableV2Interface;
class XdgImporterUnstableV2Interface;
/**
* This class encapsulates the server side logic of the XdgForeign protocol.
* a process can export a surface to be identifiable by a server-wide unique
* string handle, and another process can in turn import that surface, and set it
* as transient parent for one of its own surfaces.
* This parent relationship is traced by the transientChanged signal and the
* transientFor method.
*
* @since 5.40
*/
class KWAYLANDSERVER_EXPORT XdgForeignInterface : public QObject
{
Q_OBJECT
public:
XdgForeignInterface(Display *display, QObject *parent = nullptr);
~XdgForeignInterface();
/**
* Creates the native zxdg_exporter_v2 and zxdg_importer_v2 interfaces
* and announces them to the client.
*/
void create();
/**
* @returns true if theimporter and exporter are valid and functional
*/
bool isValid();
/**
* If a client did import a surface and set one of its own as child of the
* imported one, this returns the mapping.
* @param surface the child surface we want to search an imported transientParent for.
* @returns the transient parent of the surface, if found, nullptr otherwise.
*/
SurfaceInterface *transientFor(SurfaceInterface *surface);
Q_SIGNALS:
/**
* A surface got a new imported transient parent
* @param parent is the surface exported by one client and imported into another, which will act as parent.
* @param child is the surface that the importer client did set as child of the surface
* that it imported.
* If one of the two paramenters is nullptr, it means that a previously relation is not
* valid anymore and either one of the surfaces has been unmapped, or the parent surface
* is not exported anymore.
*/
void transientChanged(KWayland::Server::SurfaceInterface *child, KWayland::Server::SurfaceInterface *parent);
private:
friend class Display;
friend class XdgExporterUnstableV2Interface;
friend class XdgImporterUnstableV2Interface;
class Private;
Private *d;
};
}
}
#endif

View file

@ -60,7 +60,11 @@ add_executable(plasmasurface-test plasmasurfacetest.cpp)
target_link_libraries(plasmasurface-test Qt5::Gui KF5::WaylandClient) target_link_libraries(plasmasurface-test Qt5::Gui KF5::WaylandClient)
ecm_mark_as_test(plasmasurface-test) ecm_mark_as_test(plasmasurface-test)
add_executable(xdgforeign-test xdgforeigntest.cpp)
target_link_libraries(xdgforeign-test Qt5::Gui KF5::WaylandClient)
ecm_mark_as_test(xdgforeign-test)
add_executable(xdg-test xdgtest.cpp) add_executable(xdg-test xdgtest.cpp)
target_link_libraries(xdg-test Qt5::Gui KF5::WaylandClient) target_link_libraries(xdg-test Qt5::Gui KF5::WaylandClient)
ecm_mark_as_test(xdg-test) ecm_mark_as_test(xdg-test)

View file

@ -0,0 +1,208 @@
/********************************************************************
Copyright 2016 Martin Gräßlin <mgraesslin@kde.org>
Copyright 2017 Marco Martin <mart@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "../src/client/compositor.h"
#include "../src/client/connection_thread.h"
#include "../src/client/event_queue.h"
#include "../src/client/registry.h"
#include "../src/client/shell.h"
#include "../src/client/shm_pool.h"
#include "../src/client/server_decoration.h"
#include "../src/client/xdgshell.h"
#include "../src/client/xdgforeign.h"
// Qt
#include <QCommandLineParser>
#include <QGuiApplication>
#include <QImage>
#include <QThread>
#include <QDebug>
using namespace KWayland::Client;
class XdgForeignTest : public QObject
{
Q_OBJECT
public:
explicit XdgForeignTest(QObject *parent = nullptr);
virtual ~XdgForeignTest();
void init();
private:
void setupRegistry(Registry *registry);
void render();
QThread *m_connectionThread;
ConnectionThread *m_connectionThreadObject;
EventQueue *m_eventQueue = nullptr;
Compositor *m_compositor = nullptr;
XdgShell *m_shell = nullptr;
XdgShellSurface *m_shellSurface = nullptr;
ShmPool *m_shm = nullptr;
Surface *m_surface = nullptr;
XdgShellSurface *m_childShellSurface = nullptr;
Surface *m_childSurface = nullptr;
KWayland::Client::XdgExporter *m_exporter = nullptr;
KWayland::Client::XdgImporter *m_importer = nullptr;
KWayland::Client::XdgExported *m_exported = nullptr;
KWayland::Client::XdgImported *m_imported = nullptr;
KWayland::Client::ServerSideDecorationManager *m_decoration = nullptr;
};
XdgForeignTest::XdgForeignTest(QObject *parent)
: QObject(parent)
, m_connectionThread(new QThread(this))
, m_connectionThreadObject(new ConnectionThread())
{
}
XdgForeignTest::~XdgForeignTest()
{
m_connectionThread->quit();
m_connectionThread->wait();
m_connectionThreadObject->deleteLater();
}
void XdgForeignTest::init()
{
connect(m_connectionThreadObject, &ConnectionThread::connected, this,
[this] {
m_eventQueue = new EventQueue(this);
m_eventQueue->setup(m_connectionThreadObject);
Registry *registry = new Registry(this);
setupRegistry(registry);
},
Qt::QueuedConnection
);
m_connectionThreadObject->moveToThread(m_connectionThread);
m_connectionThread->start();
m_connectionThreadObject->initConnection();
}
void XdgForeignTest::setupRegistry(Registry *registry)
{
connect(registry, &Registry::compositorAnnounced, this,
[this, registry](quint32 name, quint32 version) {
m_compositor = registry->createCompositor(name, version, this);
}
);
connect(registry, &Registry::xdgShellUnstableV5Announced, this,
[this, registry](quint32 name, quint32 version) {
m_shell = registry->createXdgShell(name, version, this);
}
);
connect(registry, &Registry::shmAnnounced, this,
[this, registry](quint32 name, quint32 version) {
m_shm = registry->createShmPool(name, version, this);
}
);
connect(registry, &Registry::exporterUnstableV2Announced, this,
[this, registry](quint32 name, quint32 version) {
m_exporter = registry->createXdgExporter(name, version, this);
m_exporter->setEventQueue(m_eventQueue);
}
);
connect(registry, &Registry::importerUnstableV2Announced, this,
[this, registry](quint32 name, quint32 version) {
m_importer = registry->createXdgImporter(name, version, this);
m_importer->setEventQueue(m_eventQueue);
}
);
connect(registry, &Registry::serverSideDecorationManagerAnnounced, this,
[this, registry](quint32 name, quint32 version) {
m_decoration = registry->createServerSideDecorationManager(name, version, this);
m_decoration->setEventQueue(m_eventQueue);
}
);
connect(registry, &Registry::interfacesAnnounced, this,
[this] {
Q_ASSERT(m_compositor);
Q_ASSERT(m_shell);
Q_ASSERT(m_shm);
Q_ASSERT(m_exporter);
Q_ASSERT(m_importer);
m_surface = m_compositor->createSurface(this);
Q_ASSERT(m_surface);
auto parentDeco = m_decoration->create(m_surface, this);
m_shellSurface = m_shell->createSurface(m_surface, this);
Q_ASSERT(m_shellSurface);
connect(m_shellSurface, &XdgShellSurface::sizeChanged, this, &XdgForeignTest::render);
m_childSurface = m_compositor->createSurface(this);
Q_ASSERT(m_childSurface);
auto childDeco = m_decoration->create(m_childSurface, this);
m_childShellSurface = m_shell->createSurface(m_childSurface, this);
Q_ASSERT(m_childShellSurface);
connect(m_childShellSurface, &XdgShellSurface::sizeChanged, this, &XdgForeignTest::render);
m_exported = m_exporter->exportTopLevel(m_surface, this);
Q_ASSERT(m_decoration);
connect(m_exported, &XdgExported::done, this, [this]() {
m_imported = m_importer->importTopLevel(m_exported->handle(), this);
m_imported->setParentOf(m_childSurface);
});
render();
}
);
registry->setEventQueue(m_eventQueue);
registry->create(m_connectionThreadObject);
registry->setup();
}
void XdgForeignTest::render()
{
QSize size = m_shellSurface->size().isValid() ? m_shellSurface->size() : QSize(500, 500);
auto buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef();
buffer->setUsed(true);
QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
image.fill(QColor(255, 255, 255, 255));
m_surface->attachBuffer(*buffer);
m_surface->damage(QRect(QPoint(0, 0), size));
m_surface->commit(Surface::CommitFlag::None);
buffer->setUsed(false);
size = m_childShellSurface->size().isValid() ? m_childShellSurface->size() : QSize(200, 200);
buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef();
buffer->setUsed(true);
image = QImage(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
image.fill(QColor(255, 0, 0, 255));
m_childSurface->attachBuffer(*buffer);
m_childSurface->damage(QRect(QPoint(0, 0), size));
m_childSurface->commit(Surface::CommitFlag::None);
buffer->setUsed(false);
}
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
XdgForeignTest client;
client.init();
return app.exec();
}
#include "xdgforeigntest.moc"

View file

@ -0,0 +1,459 @@
/****************************************************************************
Copyright 2017 Marco Martin <notmart@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "xdgforeign_interface.h"
#include "xdgforeign_v2_interface_p.h"
#include "display.h"
#include "global_p.h"
#include "resource_p.h"
#include "surface_interface_p.h"
#include "wayland-xdg-foreign-unstable-v2-server-protocol.h"
#include <QUuid>
#include <QDebug>
namespace KWayland
{
namespace Server
{
class Q_DECL_HIDDEN XdgExporterUnstableV2Interface::Private : public Global::Private
{
public:
Private(XdgExporterUnstableV2Interface *q, Display *d, XdgForeignInterface *foreignInterface);
XdgForeignInterface *foreignInterface;
QHash<QString, XdgExportedUnstableV2Interface *> exportedSurfaces;
private:
void bind(wl_client *client, uint32_t version, uint32_t id) override;
static void unbind(wl_resource *resource);
static Private *cast(wl_resource *r) {
return reinterpret_cast<Private*>(wl_resource_get_user_data(r));
}
static void destroyCallback(wl_client *client, wl_resource *resource);
static void exportCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface);
XdgExporterUnstableV2Interface *q;
static const struct zxdg_exporter_v2_interface s_interface;
static const quint32 s_version;
};
const quint32 XdgExporterUnstableV2Interface::Private::s_version = 1;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
const struct zxdg_exporter_v2_interface XdgExporterUnstableV2Interface::Private::s_interface = {
destroyCallback,
exportCallback
};
#endif
XdgExporterUnstableV2Interface::XdgExporterUnstableV2Interface(Display *display, XdgForeignInterface *parent)
: Global(new Private(this, display, parent), parent)
{
}
XdgExporterUnstableV2Interface::~XdgExporterUnstableV2Interface()
{}
XdgExporterUnstableV2Interface::Private *XdgExporterUnstableV2Interface::d_func() const
{
return reinterpret_cast<Private*>(d.data());
}
XdgExportedUnstableV2Interface *XdgExporterUnstableV2Interface::exportedSurface(const QString &handle)
{
Q_D();
auto it = d->exportedSurfaces.constFind(handle);
if (it != d->exportedSurfaces.constEnd()) {
return it.value();
}
return nullptr;
}
void XdgExporterUnstableV2Interface::Private::destroyCallback(wl_client *client, wl_resource *resource)
{
Q_UNUSED(client)
}
void XdgExporterUnstableV2Interface::Private::exportCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface)
{
auto s = cast(resource);
QPointer <XdgExportedUnstableV2Interface> e = new XdgExportedUnstableV2Interface(s->q, surface);
e->create(s->display->getConnection(client), wl_resource_get_version(resource), id);
if (!e->resource()) {
wl_resource_post_no_memory(resource);
delete e;
return;
}
const QString handle = QUuid::createUuid().toString();
//a surface not exported anymore
connect(e.data(), &XdgExportedUnstableV2Interface::unbound,
s->q, [s, handle]() {
s->exportedSurfaces.remove(handle);
emit s->q->surfaceUnexported(handle);
});
//if the surface dies before this, this dies too
connect(SurfaceInterface::get(surface), &Resource::unbound,
s->q, [s, e, handle]() {
if (e) {
e->deleteLater();
}
s->exportedSurfaces.remove(handle);
emit s->q->surfaceUnexported(handle);
});
s->exportedSurfaces[handle] = e;
zxdg_exported_v2_send_handle(e->resource(), handle.toUtf8().constData());
emit s->q->surfaceExported(handle, e);
}
XdgExporterUnstableV2Interface::Private::Private(XdgExporterUnstableV2Interface *q, Display *d,XdgForeignInterface *foreignInterface)
: Global::Private(d, &zxdg_exporter_v2_interface, s_version)
, foreignInterface(foreignInterface)
, q(q)
{
}
void XdgExporterUnstableV2Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
{
auto c = display->getConnection(client);
wl_resource *resource = c->createResource(&zxdg_exporter_v2_interface, qMin(version, s_version), id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &s_interface, this, unbind);
// TODO: should we track?
}
void XdgExporterUnstableV2Interface::Private::unbind(wl_resource *resource)
{
Q_UNUSED(resource)
// TODO: implement?
}
class Q_DECL_HIDDEN XdgImporterUnstableV2Interface::Private : public Global::Private
{
public:
Private(XdgImporterUnstableV2Interface *q, Display *d, XdgForeignInterface *foreignInterface);
XdgForeignInterface *foreignInterface;
QHash<QString, XdgImportedUnstableV2Interface *> importedSurfaces;
//child->parent hash
QHash<SurfaceInterface *, XdgImportedUnstableV2Interface *> parents;
//parent->child hash
QHash<XdgImportedUnstableV2Interface *, SurfaceInterface *> children;
private:
void bind(wl_client *client, uint32_t version, uint32_t id) override;
static void unbind(wl_resource *resource);
static Private *cast(wl_resource *r) {
return reinterpret_cast<Private*>(wl_resource_get_user_data(r));
}
static void destroyCallback(wl_client *client, wl_resource *resource);
static void importCallback(wl_client *client, wl_resource *resource, uint32_t id, const char * handle);
XdgImporterUnstableV2Interface *q;
static const struct zxdg_importer_v2_interface s_interface;
static const quint32 s_version;
};
const quint32 XdgImporterUnstableV2Interface::Private::s_version = 1;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
const struct zxdg_importer_v2_interface XdgImporterUnstableV2Interface::Private::s_interface = {
destroyCallback,
importCallback
};
#endif
XdgImporterUnstableV2Interface::XdgImporterUnstableV2Interface(Display *display, XdgForeignInterface *parent)
: Global(new Private(this, display, parent), parent)
{
}
XdgImporterUnstableV2Interface::~XdgImporterUnstableV2Interface()
{
}
XdgImportedUnstableV2Interface *XdgImporterUnstableV2Interface::importedSurface(const QString &handle)
{
Q_D();
auto it = d->importedSurfaces.constFind(handle);
if (it != d->importedSurfaces.constEnd()) {
return it.value();
}
return nullptr;
}
SurfaceInterface *XdgImporterUnstableV2Interface::transientFor(SurfaceInterface *surface)
{
Q_D();
auto it = d->parents.constFind(surface);
if (it == d->parents.constEnd()) {
return nullptr;
}
return SurfaceInterface::get((*it)->parentResource());
}
XdgImporterUnstableV2Interface::Private *XdgImporterUnstableV2Interface::d_func() const
{
return reinterpret_cast<Private*>(d.data());
}
void XdgImporterUnstableV2Interface::Private::destroyCallback(wl_client *client, wl_resource *resource)
{
Q_UNUSED(client)
}
void XdgImporterUnstableV2Interface::Private::importCallback(wl_client *client, wl_resource *resource, uint32_t id, const char * handle)
{
auto s = cast(resource);
Q_ASSERT(s->foreignInterface);
XdgExportedUnstableV2Interface *exp = s->foreignInterface->d->exporter->exportedSurface(QString::fromUtf8(handle));
if (!exp) {
zxdg_imported_v2_send_destroyed(resource);
return;
}
wl_resource *surface = exp->parentResource();
if (!surface) {
zxdg_imported_v2_send_destroyed(resource);
return;
}
QPointer<XdgImportedUnstableV2Interface> imp = new XdgImportedUnstableV2Interface(s->q, surface);
imp->create(s->display->getConnection(client), wl_resource_get_version(resource), id);
//surface no longer exported
connect(exp, &XdgExportedUnstableV2Interface::unbound,
s->q, [s, imp, handle]() {
//imp valid when the exported is deleted before the imported
if (imp) {
zxdg_imported_v2_send_destroyed(imp->resource());
imp->deleteLater();
}
s->importedSurfaces.remove(QString::fromUtf8(handle));
emit s->q->surfaceUnimported(QString::fromUtf8(handle));
});
connect(imp.data(), &XdgImportedUnstableV2Interface::childChanged,
s->q, [s, imp](SurfaceInterface *child) {
//remove any previous association
auto it = s->children.find(imp);
if (it != s->children.end()) {
s->parents.remove(*it);
s->children.erase(it);
}
s->parents[child] = imp;
s->children[imp] = child;
SurfaceInterface *parent = SurfaceInterface::get(imp->parentResource());
emit s->q->transientChanged(child, parent);
//child surface destroyed
connect(child, &Resource::unbound,
s->q, [s, child]() {
auto it = s->parents.find(child);
if (it != s->parents.end()) {
s->children.remove(*it);
s->parents.erase(it);
emit s->q->transientChanged(nullptr, SurfaceInterface::get((*it)->parentResource()));
}
});
});
//surface no longer imported
connect(imp.data(), &XdgImportedUnstableV2Interface::unbound,
s->q, [s, handle, imp]() {
s->importedSurfaces.remove(QString::fromUtf8(handle));
emit s->q->surfaceUnimported(QString::fromUtf8(handle));
auto it = s->children.find(imp);
if (it != s->children.end()) {
s->parents.remove(*it);
s->children.erase(it);
emit s->q->transientChanged(*it, nullptr);
}
});
if (!imp->resource()) {
wl_resource_post_no_memory(resource);
delete imp;
return;
}
s->importedSurfaces[QString::fromUtf8(handle)] = imp;
emit s->q->surfaceImported(QString::fromUtf8(handle), imp);
}
XdgImporterUnstableV2Interface::Private::Private(XdgImporterUnstableV2Interface *q, Display *d, XdgForeignInterface *foreignInterface)
: Global::Private(d, &zxdg_importer_v2_interface, s_version)
, foreignInterface(foreignInterface)
, q(q)
{
}
void XdgImporterUnstableV2Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
{
auto c = display->getConnection(client);
wl_resource *resource = c->createResource(&zxdg_importer_v2_interface, qMin(version, s_version), id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &s_interface, this, unbind);
// TODO: should we track?
}
void XdgImporterUnstableV2Interface::Private::unbind(wl_resource *resource)
{
Q_UNUSED(resource)
// TODO: implement?
}
class Q_DECL_HIDDEN XdgExportedUnstableV2Interface::Private : public Resource::Private
{
public:
Private(XdgExportedUnstableV2Interface *q, XdgExporterUnstableV2Interface *c, wl_resource *parentResource);
~Private();
private:
XdgExportedUnstableV2Interface *q_func() {
return reinterpret_cast<XdgExportedUnstableV2Interface *>(q);
}
static const struct zxdg_exported_v2_interface s_interface;
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
const struct zxdg_exported_v2_interface XdgExportedUnstableV2Interface::Private::s_interface = {
resourceDestroyedCallback
};
#endif
XdgExportedUnstableV2Interface::XdgExportedUnstableV2Interface(XdgExporterUnstableV2Interface *parent, wl_resource *parentResource)
: Resource(new Private(this, parent, parentResource))
{
}
XdgExportedUnstableV2Interface::~XdgExportedUnstableV2Interface()
{}
XdgExportedUnstableV2Interface::Private *XdgExportedUnstableV2Interface::d_func() const
{
return reinterpret_cast<Private*>(d.data());
}
XdgExportedUnstableV2Interface::Private::Private(XdgExportedUnstableV2Interface *q, XdgExporterUnstableV2Interface *c, wl_resource *parentResource)
: Resource::Private(q, c, parentResource, &zxdg_exported_v2_interface, &s_interface)
{
}
XdgExportedUnstableV2Interface::Private::~Private()
{}
class Q_DECL_HIDDEN XdgImportedUnstableV2Interface::Private : public Resource::Private
{
public:
Private(XdgImportedUnstableV2Interface *q, XdgImporterUnstableV2Interface *c, wl_resource *parentResource);
~Private();
QPointer<SurfaceInterface> parentOf;
private:
static void setParentOfCallback(wl_client *client, wl_resource *resource, wl_resource * surface);
XdgImportedUnstableV2Interface *q_func() {
return reinterpret_cast<XdgImportedUnstableV2Interface *>(q);
}
static const struct zxdg_imported_v2_interface s_interface;
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
const struct zxdg_imported_v2_interface XdgImportedUnstableV2Interface::Private::s_interface = {
resourceDestroyedCallback,
setParentOfCallback
};
#endif
XdgImportedUnstableV2Interface::XdgImportedUnstableV2Interface(XdgImporterUnstableV2Interface *parent, wl_resource *parentResource)
: Resource(new Private(this, parent, parentResource))
{
}
XdgImportedUnstableV2Interface::~XdgImportedUnstableV2Interface()
{}
XdgImportedUnstableV2Interface::Private *XdgImportedUnstableV2Interface::d_func() const
{
return reinterpret_cast<Private*>(d.data());
}
SurfaceInterface *XdgImportedUnstableV2Interface::child() const
{
Q_D();
return d->parentOf.data();
}
void XdgImportedUnstableV2Interface::Private::setParentOfCallback(wl_client *client, wl_resource *resource, wl_resource * surface)
{
auto s = cast<Private>(resource);
SurfaceInterface *surf = SurfaceInterface::get(surface);
if (!surf) {
return;
}
s->parentOf = surf;
emit s->q_func()->childChanged(surf);
}
XdgImportedUnstableV2Interface::Private::Private(XdgImportedUnstableV2Interface *q, XdgImporterUnstableV2Interface *c, wl_resource *parentResource)
: Resource::Private(q, c, parentResource, &zxdg_imported_v2_interface, &s_interface)
{
}
XdgImportedUnstableV2Interface::Private::~Private()
{}
}
}

View file

@ -0,0 +1,124 @@
/****************************************************************************
Copyright 2017 Marco Martin <notmart@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef KWAYLAND_SERVER_XDGFOREIGNV2_P_H
#define KWAYLAND_SERVER_XDGFOREIGNV2_P_H
#include "global.h"
#include "resource.h"
namespace KWayland
{
namespace Server
{
class Display;
class SurfaceInterface;
class XdgExportedUnstableV2Interface;
class XdgImportedUnstableV2Interface;
class Q_DECL_HIDDEN XdgForeignInterface::Private
{
public:
Private(Display *display, XdgForeignInterface *q);
XdgForeignInterface *q;
XdgExporterUnstableV2Interface *exporter;
XdgImporterUnstableV2Interface *importer;
};
class Q_DECL_HIDDEN XdgExporterUnstableV2Interface : public Global
{
Q_OBJECT
public:
virtual ~XdgExporterUnstableV2Interface();
XdgExportedUnstableV2Interface *exportedSurface(const QString &handle);
Q_SIGNALS:
void surfaceExported(const QString &handle, XdgExportedUnstableV2Interface *exported);
void surfaceUnexported(const QString &handle);
private:
explicit XdgExporterUnstableV2Interface(Display *display, XdgForeignInterface *parent = nullptr);
friend class Display;
friend class XdgForeignInterface;
class Private;
Private *d_func() const;
};
class Q_DECL_HIDDEN XdgImporterUnstableV2Interface : public Global
{
Q_OBJECT
public:
virtual ~XdgImporterUnstableV2Interface();
XdgImportedUnstableV2Interface *importedSurface(const QString &handle);
SurfaceInterface *transientFor(SurfaceInterface *surface);
Q_SIGNALS:
void surfaceImported(const QString &handle, XdgImportedUnstableV2Interface *imported);
void surfaceUnimported(const QString &handle);
void transientChanged(KWayland::Server::SurfaceInterface *child, KWayland::Server::SurfaceInterface *parent);
private:
explicit XdgImporterUnstableV2Interface(Display *display, XdgForeignInterface *parent = nullptr);
friend class Display;
friend class XdgForeignInterface;
class Private;
Private *d_func() const;
};
class Q_DECL_HIDDEN XdgExportedUnstableV2Interface : public Resource
{
Q_OBJECT
public:
virtual ~XdgExportedUnstableV2Interface();
private:
explicit XdgExportedUnstableV2Interface(XdgExporterUnstableV2Interface *parent, wl_resource *parentResource);
friend class XdgExporterUnstableV2Interface;
class Private;
Private *d_func() const;
};
class Q_DECL_HIDDEN XdgImportedUnstableV2Interface : public Resource
{
Q_OBJECT
public:
virtual ~XdgImportedUnstableV2Interface();
SurfaceInterface *child() const;
Q_SIGNALS:
void childChanged(KWayland::Server::SurfaceInterface *child);
private:
explicit XdgImportedUnstableV2Interface(XdgImporterUnstableV2Interface *parent, wl_resource *parentResource);
friend class XdgImporterUnstableV2Interface;
class Private;
Private *d_func() const;
};
}
}
#endif