1/*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6#include "../src/client/compositor.h"
7#include "../src/client/connection_thread.h"
8#include "../src/client/datadevice.h"
9#include "../src/client/datadevicemanager.h"
10#include "../src/client/datasource.h"
11#include "../src/client/event_queue.h"
12#include "../src/client/keyboard.h"
13#include "../src/client/pointer.h"
14#include "../src/client/registry.h"
15#include "../src/client/seat.h"
16#include "../src/client/shell.h"
17#include "../src/client/shm_pool.h"
18#include "../src/client/surface.h"
19// Qt
20#include <QCoreApplication>
21#include <QDebug>
22#include <QFile>
23#include <QImage>
24#include <QThread>
25
26using namespace KWayland::Client;
27
28class CopyClient : public QObject
29{
30 Q_OBJECT
31public:
32 explicit CopyClient(QObject *parent = nullptr);
33 ~CopyClient() override;
34
35 void init();
36
37private:
38 void setupRegistry(Registry *registry);
39 void render();
40 void copy(const QString &mimeType, qint32 fd);
41 QThread *m_connectionThread;
42 ConnectionThread *m_connectionThreadObject;
43 EventQueue *m_eventQueue = nullptr;
44 Compositor *m_compositor = nullptr;
45 DataDeviceManager *m_dataDeviceManager = nullptr;
46 DataDevice *m_dataDevice = nullptr;
47 DataSource *m_copySource = nullptr;
48 Seat *m_seat = nullptr;
49 Shell *m_shell = nullptr;
50 ShellSurface *m_shellSurface = nullptr;
51 ShmPool *m_shm = nullptr;
52 Surface *m_surface = nullptr;
53};
54
55CopyClient::CopyClient(QObject *parent)
56 : QObject(parent)
57 , m_connectionThread(new QThread(this))
58 , m_connectionThreadObject(new ConnectionThread())
59{
60}
61
62CopyClient::~CopyClient()
63{
64 m_connectionThread->quit();
65 m_connectionThread->wait();
66 m_connectionThreadObject->deleteLater();
67}
68
69void CopyClient::init()
70{
71 connect(
72 sender: m_connectionThreadObject,
73 signal: &ConnectionThread::connected,
74 context: this,
75 slot: [this] {
76 m_eventQueue = new EventQueue(this);
77 m_eventQueue->setup(m_connectionThreadObject);
78
79 Registry *registry = new Registry(this);
80 setupRegistry(registry);
81 },
82 type: Qt::QueuedConnection);
83 m_connectionThreadObject->moveToThread(thread: m_connectionThread);
84 m_connectionThread->start();
85
86 m_connectionThreadObject->initConnection();
87}
88
89void CopyClient::setupRegistry(Registry *registry)
90{
91 connect(sender: registry, signal: &Registry::compositorAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
92 m_compositor = registry->createCompositor(name, version, parent: this);
93 });
94 connect(sender: registry, signal: &Registry::shellAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
95 m_shell = registry->createShell(name, version, parent: this);
96 });
97 connect(sender: registry, signal: &Registry::shmAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
98 m_shm = registry->createShmPool(name, version, parent: this);
99 });
100 connect(sender: registry, signal: &Registry::seatAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
101 m_seat = registry->createSeat(name, version, parent: this);
102 connect(sender: m_seat, signal: &Seat::hasPointerChanged, context: this, slot: [this] {
103 auto p = m_seat->createPointer(parent: this);
104 connect(sender: p, signal: &Pointer::entered, context: this, slot: [this](quint32 serial) {
105 if (m_copySource) {
106 m_dataDevice->setSelection(serial, source: m_copySource);
107 }
108 });
109 });
110 });
111 connect(sender: registry, signal: &Registry::dataDeviceManagerAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
112 m_dataDeviceManager = registry->createDataDeviceManager(name, version, parent: this);
113 });
114 connect(sender: registry, signal: &Registry::interfacesAnnounced, context: this, slot: [this] {
115 Q_ASSERT(m_compositor);
116 Q_ASSERT(m_dataDeviceManager);
117 Q_ASSERT(m_seat);
118 Q_ASSERT(m_shell);
119 Q_ASSERT(m_shm);
120 m_surface = m_compositor->createSurface(parent: this);
121 Q_ASSERT(m_surface);
122 m_shellSurface = m_shell->createSurface(surface: m_surface, parent: this);
123 Q_ASSERT(m_shellSurface);
124 m_shellSurface->setFullscreen();
125 connect(sender: m_shellSurface, signal: &ShellSurface::sizeChanged, context: this, slot: &CopyClient::render);
126
127 m_dataDevice = m_dataDeviceManager->getDataDevice(seat: m_seat, parent: this);
128 m_copySource = m_dataDeviceManager->createDataSource(parent: this);
129 m_copySource->offer(QStringLiteral("text/plain"));
130 connect(sender: m_copySource, signal: &DataSource::sendDataRequested, context: this, slot: &CopyClient::copy);
131 });
132 registry->setEventQueue(m_eventQueue);
133 registry->create(connection: m_connectionThreadObject);
134 registry->setup();
135}
136
137void CopyClient::render()
138{
139 const QSize &size = m_shellSurface->size();
140 auto buffer = m_shm->getBuffer(size, stride: size.width() * 4).toStrongRef();
141 buffer->setUsed(true);
142 QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
143 image.fill(color: Qt::green);
144
145 m_surface->attachBuffer(buffer: *buffer);
146 m_surface->damage(rect: QRect(QPoint(0, 0), size));
147 m_surface->commit(flag: Surface::CommitFlag::None);
148 buffer->setUsed(false);
149}
150
151void CopyClient::copy(const QString &mimeType, qint32 fd)
152{
153 qDebug() << "Requested to copy for mimeType" << mimeType;
154 QFile c;
155 if (c.open(fd, ioFlags: QFile::WriteOnly, handleFlags: QFile::AutoCloseHandle)) {
156 c.write(QByteArrayLiteral("foo"));
157 c.close();
158 qDebug() << "Copied foo";
159 }
160}
161
162int main(int argc, char **argv)
163{
164 QCoreApplication app(argc, argv);
165 CopyClient client;
166 client.init();
167
168 return app.exec();
169}
170
171#include "copyclient.moc"
172

source code of kwayland/tests/copyclient.cpp