Commit 77f30eae authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Drop support for the remote-access protocol

It's been replaced by PipeWire stuff.
parent 97fa1fb3
......@@ -353,17 +353,6 @@ target_link_libraries( testServerSideDecorationPalette Qt5::Test Qt5::Gui KF5::W
add_test(NAME kwayland-testServerSideDecorationPalette COMMAND testServerSideDecorationPalette)
ecm_mark_as_test(testServerSideDecorationPalette)
########################################################
# Test RemoteAccess
########################################################
set( testRemoteAccess_SRCS
test_remote_access.cpp
)
add_executable(testRemoteAccess ${testRemoteAccess_SRCS})
target_link_libraries( testRemoteAccess Qt5::Test Qt5::Gui KF5::WaylandClient Plasma::KWaylandServer)
add_test(NAME kwayland-testRemoteAccess COMMAND testRemoteAccess)
ecm_mark_as_test(testRemoteAccess)
########################################################
# Test VirtualDesktop
########################################################
......
/*
SPDX-FileCopyrightText: 2016 Oleg Chernovskiy <kanedias@xaker.ru>
SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
// Qt
#include <QtTest>
// client
#include "KWayland/Client/connection_thread.h"
#include "KWayland/Client/event_queue.h"
#include "KWayland/Client/remote_access.h"
#include "KWayland/Client/registry.h"
#include "KWayland/Client/output.h"
// server
#include "../../src/server/display.h"
#include "../../src/server/output_interface.h"
#include "../../src/server/remote_access_interface.h"
using namespace KWayland::Client;
using namespace KWaylandServer;
Q_DECLARE_METATYPE(const BufferHandle *)
Q_DECLARE_METATYPE(const RemoteBuffer *)
Q_DECLARE_METATYPE(const void *)
class RemoteAccessTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void init();
void cleanup();
void testSendReleaseSingle();
void testSendReleaseMultiple();
void testSendReleaseCrossScreen();
void testSendClientGone();
void testSendReceiveClientGone();
private:
Display *m_display = nullptr;
OutputInterface *m_outputInterface[2] = {nullptr};
RemoteAccessManagerInterface *m_remoteAccessInterface = nullptr;
};
class MockupClient : public QObject
{
Q_OBJECT
public:
MockupClient(QObject *parent = nullptr);
~MockupClient();
void bindOutput(int index);
ConnectionThread *connection = nullptr;
QThread *thread = nullptr;
EventQueue *queue = nullptr;
Registry *registry = nullptr;
RemoteAccessManager *remoteAccess = nullptr;
Output *outputs[2] = {nullptr};
};
static const QString s_socketName = QStringLiteral("kwayland-test-remote-access-0");
MockupClient::MockupClient(QObject *parent)
: QObject(parent)
{
// setup connection
connection = new KWayland::Client::ConnectionThread;
QSignalSpy connectedSpy(connection, &ConnectionThread::connected);
QVERIFY(connectedSpy.isValid());
connection->setSocketName(s_socketName);
thread = new QThread(this);
connection->moveToThread(thread);
thread->start();
connection->initConnection();
QVERIFY(connectedSpy.wait());
queue = new EventQueue(this);
queue->setup(connection);
registry = new Registry(this);
QSignalSpy interfacesAnnouncedSpy(registry, &Registry::interfacesAnnounced);
QVERIFY(interfacesAnnouncedSpy.isValid());
registry->setEventQueue(queue);
registry->create(connection);
QVERIFY(registry->isValid());
registry->setup();
QVERIFY(interfacesAnnouncedSpy.wait());
remoteAccess = registry->createRemoteAccessManager(
registry->interface(Registry::Interface::RemoteAccessManager).name,
registry->interface(Registry::Interface::RemoteAccessManager).version,
this);
QVERIFY(remoteAccess->isValid());
connection->flush();
}
MockupClient::~MockupClient()
{
#define CLEANUP(variable) \
if (variable) { \
delete variable; \
variable = nullptr; \
}
CLEANUP(outputs[0])
CLEANUP(outputs[1])
CLEANUP(remoteAccess)
CLEANUP(queue)
CLEANUP(registry)
if (thread) {
if (connection) {
connection->flush();
connection->deleteLater();
connection = nullptr;
}
thread->quit();
thread->wait();
delete thread;
thread = nullptr;
}
#undef CLEANUP
}
void MockupClient::bindOutput(int index)
{
// client-bound output
outputs[index] = registry->createOutput(registry->interfaces(Registry::Interface::Output)[index].name,
registry->interfaces(Registry::Interface::Output)[index].version,
this);
QVERIFY(outputs[index]->isValid());
connection->flush();
}
void RemoteAccessTest::init()
{
qRegisterMetaType<const BufferHandle *>();
qRegisterMetaType<const RemoteBuffer *>();
qRegisterMetaType<const void *>();
delete m_display;
m_display = new Display(this);
m_display->setSocketName(s_socketName);
m_display->start();
QVERIFY(m_display->isRunning());
m_display->createShm();
auto initOutputIface = [this](int i) {
m_outputInterface[i] = m_display->createOutput();
m_outputInterface[i]->create();
};
initOutputIface(0);
initOutputIface(1);
m_remoteAccessInterface = m_display->createRemoteAccessManager();
m_remoteAccessInterface->create();
QSignalSpy bufferReleasedSpy(m_remoteAccessInterface, &RemoteAccessManagerInterface::bufferReleased);
QVERIFY(bufferReleasedSpy.isValid());
}
void RemoteAccessTest::cleanup()
{
#define CLEANUP(variable) \
if (variable) { \
delete variable; \
variable = nullptr; \
}
CLEANUP(m_outputInterface[0])
CLEANUP(m_outputInterface[1])
CLEANUP(m_remoteAccessInterface)
CLEANUP(m_display)
#undef CLEANUP
}
void RemoteAccessTest::testSendReleaseSingle()
{
// this test verifies that a buffer is sent to client and returned back
// setup
QVERIFY(!m_remoteAccessInterface->isBound());
auto *client = new MockupClient(this);
client->bindOutput(0);
m_display->dispatchEvents();
QVERIFY(m_remoteAccessInterface->isBound()); // we have one client now
QSignalSpy bufferReadySpy(client->remoteAccess, &RemoteAccessManager::bufferReady);
QVERIFY(bufferReadySpy.isValid());
BufferHandle *buf = new BufferHandle();
QTemporaryFile *tmpFile = new QTemporaryFile(this);
tmpFile->open();
buf->setFd(tmpFile->handle());
buf->setSize(50, 50);
buf->setFormat(100500);
buf->setStride(7800);
m_remoteAccessInterface->sendBufferReady(m_outputInterface[0], buf);
// receive buffer
QVERIFY(bufferReadySpy.wait());
auto rbuf = bufferReadySpy.takeFirst()[1].value<const RemoteBuffer *>();
QSignalSpy paramsObtainedSpy(rbuf, &RemoteBuffer::parametersObtained);
QVERIFY(paramsObtainedSpy.isValid());
// wait for params
QVERIFY(paramsObtainedSpy.wait());
// client fd is different, not subject to check
QCOMPARE(rbuf->width(), 50u);
QCOMPARE(rbuf->height(), 50u);
QCOMPARE(rbuf->format(), 100500u);
QCOMPARE(rbuf->stride(), 7800u);
// release
QSignalSpy bufferReleasedSpy(m_remoteAccessInterface, &RemoteAccessManagerInterface::bufferReleased);
QVERIFY(bufferReleasedSpy.isValid());
delete rbuf;
QVERIFY(bufferReleasedSpy.wait());
// cleanup
delete buf;
delete client;
m_display->dispatchEvents();
QVERIFY(!m_remoteAccessInterface->isBound());
}
void RemoteAccessTest::testSendReleaseMultiple()
{
// this test verifies that a buffer is sent to 2 clients and returned back
// setup
QVERIFY(!m_remoteAccessInterface->isBound());
auto *client1 = new MockupClient(this);
auto *client2 = new MockupClient(this);
client1->bindOutput(0);
client2->bindOutput(0);
m_display->dispatchEvents();
QVERIFY(m_remoteAccessInterface->isBound()); // now we have 2 clients
BufferHandle *buf = new BufferHandle();
QTemporaryFile *tmpFile = new QTemporaryFile(this);
tmpFile->open();
buf->setFd(tmpFile->handle());
buf->setSize(50, 50);
buf->setFormat(100500);
buf->setStride(7800);
bool buffer1ParametersReceived = false;
bool buffer2ParametersReceived = false;
const RemoteBuffer *rbuf1 = nullptr;
const RemoteBuffer *rbuf2 = nullptr;
client1->connection->flush();
client2->connection->flush();
{
QEventLoop e;
QTimer::singleShot(1000, &e, &QEventLoop::quit); //safety timer
connect(client1->remoteAccess, &RemoteAccessManager::bufferReady, [&] (const void*, const RemoteBuffer *buffer) {
rbuf1 = buffer;
connect(rbuf1, &RemoteBuffer::parametersObtained, [&]() {
buffer1ParametersReceived = true;
if (buffer1ParametersReceived && buffer2ParametersReceived) {
e.quit();
}
});
});
connect(client2->remoteAccess, &RemoteAccessManager::bufferReady, [&] (const void*, const RemoteBuffer *buffer) {
rbuf2 = buffer;
connect(rbuf2, &RemoteBuffer::parametersObtained, [&]() {
buffer2ParametersReceived = true;
if (buffer1ParametersReceived && buffer2ParametersReceived) {
e.quit();
}
});
});
m_remoteAccessInterface->sendBufferReady(m_outputInterface[0], buf);
e.exec();
}
QVERIFY(rbuf1);
QVERIFY(rbuf2);
QVERIFY(buffer1ParametersReceived);
QVERIFY(buffer2ParametersReceived);
// release
QSignalSpy bufferReleasedSpy(m_remoteAccessInterface, &RemoteAccessManagerInterface::bufferReleased);
delete rbuf1;
QVERIFY(!bufferReleasedSpy.wait(1000)); // one client released, second still holds buffer!
delete rbuf2;
QVERIFY(bufferReleasedSpy.wait()); // all clients released, buffer should be freed
// cleanup
delete buf;
delete client1;
delete client2;
m_display->dispatchEvents();
QVERIFY(!m_remoteAccessInterface->isBound());
}
void RemoteAccessTest::testSendReleaseCrossScreen()
{
// this test verifies that multiple buffers for multiple screens are sent to
// multiple clients and returned back
// setup
QVERIFY(!m_remoteAccessInterface->isBound());
auto *client1 = new MockupClient(this);
auto *client2 = new MockupClient(this);
client1->bindOutput(1);
client2->bindOutput(0);
m_display->dispatchEvents();
QVERIFY(m_remoteAccessInterface->isBound()); // now we have 2 clients
QSignalSpy bufferReadySpy1(client1->remoteAccess, &RemoteAccessManager::bufferReady);
QVERIFY(bufferReadySpy1.isValid());
QSignalSpy bufferReadySpy2(client2->remoteAccess, &RemoteAccessManager::bufferReady);
QVERIFY(bufferReadySpy2.isValid());
BufferHandle *buf1 = new BufferHandle();
QTemporaryFile *tmpFile1 = new QTemporaryFile(this);
tmpFile1->open();
BufferHandle *buf2 = new BufferHandle();
QTemporaryFile *tmpFile2 = new QTemporaryFile(this);
tmpFile2->open();
buf1->setFd(tmpFile1->handle());
buf1->setSize(50, 50);
buf1->setFormat(100500);
buf1->setStride(7800);
buf2->setFd(tmpFile2->handle());
buf2->setSize(100, 100);
buf2->setFormat(100500);
buf2->setStride(7800);
m_remoteAccessInterface->sendBufferReady(m_outputInterface[0], buf1);
m_remoteAccessInterface->sendBufferReady(m_outputInterface[1], buf2);
// wait for event loop
QVERIFY(bufferReadySpy1.wait());
if (bufferReadySpy2.size() == 0) {
QVERIFY(bufferReadySpy2.wait());
}
// receive buffer at client 1
QCOMPARE(bufferReadySpy1.size(), 1);
auto rbuf1 = bufferReadySpy1.takeFirst()[1].value<const RemoteBuffer *>();
QSignalSpy paramsObtainedSpy1(rbuf1, &RemoteBuffer::parametersObtained);
QVERIFY(paramsObtainedSpy1.isValid());
// receive buffer at client 2
QCOMPARE(bufferReadySpy2.size(), 1);
auto rbuf2 = bufferReadySpy2.takeFirst()[1].value<const RemoteBuffer *>();
QSignalSpy paramsObtainedSpy2(rbuf2, &RemoteBuffer::parametersObtained);
QVERIFY(paramsObtainedSpy2.isValid());
// wait for event loop
if (paramsObtainedSpy1.isEmpty()) {
QVERIFY(paramsObtainedSpy1.wait());
}
if (paramsObtainedSpy2.isEmpty()) {
QVERIFY(paramsObtainedSpy2.wait());
}
QCOMPARE(paramsObtainedSpy1.size(), 1);
QCOMPARE(paramsObtainedSpy2.size(), 1);
// release
QSignalSpy bufferReleasedSpy(m_remoteAccessInterface, &RemoteAccessManagerInterface::bufferReleased);
QVERIFY(bufferReleasedSpy.isValid());
delete rbuf1;
QVERIFY(bufferReleasedSpy.wait());
delete rbuf2;
QVERIFY(bufferReleasedSpy.wait());
QCOMPARE(bufferReleasedSpy.size(), 2);
// cleanup
delete buf1;
delete buf2;
delete client1;
delete client2;
m_display->dispatchEvents();
QVERIFY(!m_remoteAccessInterface->isBound());
}
void RemoteAccessTest::testSendClientGone()
{
// this test verifies that when buffer is sent and client is gone, server will release buffer correctly
QVERIFY(!m_remoteAccessInterface->isBound());
auto *client = new MockupClient(this);
client->bindOutput(0);
m_display->dispatchEvents();
QVERIFY(m_remoteAccessInterface->isBound()); // we have one client now
QSignalSpy bufferReadySpy(client->remoteAccess, &RemoteAccessManager::bufferReady);
QVERIFY(bufferReadySpy.isValid());
BufferHandle *buf = new BufferHandle();
QTemporaryFile *tmpFile = new QTemporaryFile(this);
tmpFile->open();
buf->setFd(tmpFile->handle());
buf->setSize(50, 50);
buf->setFormat(100500);
buf->setStride(7800);
m_remoteAccessInterface->sendBufferReady(m_outputInterface[0], buf);
// release forcefully
QSignalSpy bufferReleasedSpy(m_remoteAccessInterface, &RemoteAccessManagerInterface::bufferReleased);
QVERIFY(bufferReleasedSpy.isValid());
delete client;
QVERIFY(bufferReleasedSpy.wait());
// cleanup
delete buf;
m_display->dispatchEvents();
QVERIFY(!m_remoteAccessInterface->isBound());
}
void RemoteAccessTest::testSendReceiveClientGone()
{
// this test verifies that when buffer is sent, received and client is gone,
// both client and server will release buffer correctly
QVERIFY(!m_remoteAccessInterface->isBound());
auto *client = new MockupClient(this);
client->bindOutput(0);
m_display->dispatchEvents();
QVERIFY(m_remoteAccessInterface->isBound()); // we have one client now
QSignalSpy bufferReadySpy(client->remoteAccess, &RemoteAccessManager::bufferReady);
QVERIFY(bufferReadySpy.isValid());
BufferHandle *buf = new BufferHandle();
QTemporaryFile *tmpFile = new QTemporaryFile(this);
tmpFile->open();
buf->setFd(tmpFile->handle());
buf->setSize(50, 50);
buf->setFormat(100500);
buf->setStride(7800);
m_remoteAccessInterface->sendBufferReady(m_outputInterface[0], buf);
// receive buffer
QVERIFY(bufferReadySpy.wait());
auto rbuf = bufferReadySpy.takeFirst()[1].value<const RemoteBuffer *>();
QSignalSpy paramsObtainedSpy(rbuf, &RemoteBuffer::parametersObtained);
QVERIFY(paramsObtainedSpy.isValid());
// wait for params
QVERIFY(paramsObtainedSpy.wait());
// client fd is different, not subject to check
QCOMPARE(rbuf->width(), 50u);
QCOMPARE(rbuf->height(), 50u);
QCOMPARE(rbuf->format(), 100500u);
QCOMPARE(rbuf->stride(), 7800u);
// release forcefully
QSignalSpy bufferReleasedSpy(m_remoteAccessInterface, &RemoteAccessManagerInterface::bufferReleased);
QVERIFY(bufferReleasedSpy.isValid());
delete client;
QVERIFY(bufferReleasedSpy.wait());
// cleanup
delete buf;
m_display->dispatchEvents();
QVERIFY(!m_remoteAccessInterface->isBound());
}
QTEST_GUILESS_MAIN(RemoteAccessTest)
#include "test_remote_access.moc"
......@@ -47,7 +47,6 @@ set(SERVER_LIB_SRCS
region_interface.cpp
relativepointer_interface.cpp
relativepointer_interface_v1.cpp
remote_access_interface.cpp
resource.cpp
seat_interface.cpp
server_decoration_interface.cpp
......@@ -199,11 +198,6 @@ ecm_add_qtwayland_server_protocol(SERVER_LIB_SRCS
BASENAME server-decoration-palette
)
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/remote-access.xml
BASENAME remote-access
)
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/xdg-output/xdg-output-unstable-v1.xml
BASENAME xdg-output
......@@ -403,7 +397,6 @@ set(SERVER_LIB_HEADERS
primaryselectiondevicemanager_v1_interface.h
region_interface.h
relativepointer_interface.h
remote_access_interface.h
resource.h
screencast_interface.h
seat_interface.h
......
......@@ -31,7 +31,6 @@
#include "pointergestures_interface_p.h"
#include "primaryselectiondevicemanager_v1_interface.h"
#include "relativepointer_interface_p.h"
#include "remote_access_interface.h"
#include "seat_interface.h"
#include "screencast_interface.h"
#include "server_decoration_interface.h"
......@@ -279,13 +278,6 @@ PlasmaWindowManagementInterface *Display::createPlasmaWindowManagement(QObject *
return wm;
}
RemoteAccessManagerInterface *Display::createRemoteAccessManager(QObject *parent)
{
auto i = new RemoteAccessManagerInterface(this, parent);
connect(this, &Display::aboutToTerminate, i, [i] { delete i; });
return i;
}
IdleInterface *Display::createIdle(QObject *parent)
{
auto i = new IdleInterface(this, parent);
......
......@@ -39,7 +39,6 @@ class DataDeviceManagerInterface;
class DpmsManagerInterface;
class IdleInterface;
enum class IdleInhibitManagerInterfaceVersion;
class RemoteAccessManagerInterface;
class IdleInhibitManagerInterface;
class FakeInputInterface;
class OutputInterface;
......@@ -180,7 +179,6 @@ public:
PlasmaWindowManagementInterface *createPlasmaWindowManagement(QObject *parent = nullptr);
QtSurfaceExtensionInterface *createQtSurfaceExtension(QObject *parent = nullptr);
IdleInterface *createIdle(QObject *parent = nullptr);
RemoteAccessManagerInterface *createRemoteAccessManager(QObject *parent = nullptr);
FakeInputInterface *createFakeInput(QObject *parent = nullptr);
ShadowManagerInterface *createShadowManager(QObject *parent = nullptr);
BlurManagerInterface *createBlurManager(QObject *parent = nullptr);
......
/*
SPDX-FileCopyrightText: 2016 Oleg Chernovskiy <kanedias@xaker.ru>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "remote_access_interface.h"
#include "remote_access_interface_p.h"
#include "output_interface.h"
#include "display.h"
#include "global_p.h"
#include "resource_p.h"
#include "logging.h"
#include <wayland-remote-access-server-protocol.h>
#include <QHash>
#include <QMutableHashIterator>
#include <functional>
namespace KWaylandServer
{
class BufferHandle::Private // @see gbm_import_fd_data
{
public:
// Note that on client side received fd number will be different
// and meaningful only for client process!
// Thus we can use server-side fd as an implicit unique id
qint32 fd = 0; ///< also internal buffer id for client
quint32 width = 0;
quint32 height = 0;
quint32 stride = 0;
quint32 format = 0;
};
BufferHandle::BufferHandle()
: d(new Private)
{
}