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/dataoffer.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 <QMimeType>
25#include <QThread>
26#include <QtConcurrentRun>
27// system
28#include <unistd.h>
29
30using namespace KWayland::Client;
31
32class PasteClient : public QObject
33{
34 Q_OBJECT
35public:
36 explicit PasteClient(QObject *parent = nullptr);
37 ~PasteClient() override;
38
39 void init();
40
41private:
42 void setupRegistry(Registry *registry);
43 void render();
44 QThread *m_connectionThread;
45 ConnectionThread *m_connectionThreadObject;
46 EventQueue *m_eventQueue = nullptr;
47 Compositor *m_compositor = nullptr;
48 DataDeviceManager *m_dataDeviceManager = nullptr;
49 DataDevice *m_dataDevice = nullptr;
50 Seat *m_seat = nullptr;
51 Shell *m_shell = nullptr;
52 ShellSurface *m_shellSurface = nullptr;
53 ShmPool *m_shm = nullptr;
54 Surface *m_surface = nullptr;
55};
56
57PasteClient::PasteClient(QObject *parent)
58 : QObject(parent)
59 , m_connectionThread(new QThread(this))
60 , m_connectionThreadObject(new ConnectionThread())
61{
62}
63
64PasteClient::~PasteClient()
65{
66 m_connectionThread->quit();
67 m_connectionThread->wait();
68 m_connectionThreadObject->deleteLater();
69}
70
71void PasteClient::init()
72{
73 connect(
74 sender: m_connectionThreadObject,
75 signal: &ConnectionThread::connected,
76 context: this,
77 slot: [this] {
78 m_eventQueue = new EventQueue(this);
79 m_eventQueue->setup(m_connectionThreadObject);
80
81 Registry *registry = new Registry(this);
82 setupRegistry(registry);
83 },
84 type: Qt::QueuedConnection);
85 m_connectionThreadObject->moveToThread(thread: m_connectionThread);
86 m_connectionThread->start();
87
88 m_connectionThreadObject->initConnection();
89}
90
91void PasteClient::setupRegistry(Registry *registry)
92{
93 connect(sender: registry, signal: &Registry::compositorAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
94 m_compositor = registry->createCompositor(name, version, parent: this);
95 });
96 connect(sender: registry, signal: &Registry::shellAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
97 m_shell = registry->createShell(name, version, parent: this);
98 });
99 connect(sender: registry, signal: &Registry::shmAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
100 m_shm = registry->createShmPool(name, version, parent: this);
101 });
102 connect(sender: registry, signal: &Registry::seatAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
103 m_seat = registry->createSeat(name, version, parent: this);
104 });
105 connect(sender: registry, signal: &Registry::dataDeviceManagerAnnounced, context: this, slot: [this, registry](quint32 name, quint32 version) {
106 m_dataDeviceManager = registry->createDataDeviceManager(name, version, parent: this);
107 });
108 connect(sender: registry, signal: &Registry::interfacesAnnounced, context: this, slot: [this] {
109 Q_ASSERT(m_compositor);
110 Q_ASSERT(m_dataDeviceManager);
111 Q_ASSERT(m_seat);
112 Q_ASSERT(m_shell);
113 Q_ASSERT(m_shm);
114 m_surface = m_compositor->createSurface(parent: this);
115 Q_ASSERT(m_surface);
116 m_shellSurface = m_shell->createSurface(surface: m_surface, parent: this);
117 Q_ASSERT(m_shellSurface);
118 m_shellSurface->setFullscreen();
119 connect(sender: m_shellSurface, signal: &ShellSurface::sizeChanged, context: this, slot: &PasteClient::render);
120
121 m_dataDevice = m_dataDeviceManager->getDataDevice(seat: m_seat, parent: this);
122 connect(sender: m_dataDevice, signal: &DataDevice::selectionOffered, context: this, slot: [this] {
123 auto dataOffer = m_dataDevice->offeredSelection();
124 if (!dataOffer) {
125 return;
126 }
127 const auto &mimeTypes = dataOffer->offeredMimeTypes();
128 auto it = std::find_if(first: mimeTypes.constBegin(), last: mimeTypes.constEnd(), pred: [](const QMimeType &type) {
129 return type.inherits(QStringLiteral("text/plain"));
130 });
131 if (it == mimeTypes.constEnd()) {
132 return;
133 }
134 int pipeFds[2];
135 if (pipe(pipedes: pipeFds) != 0) {
136 return;
137 }
138 dataOffer->receive(mimeType: (*it).name(), fd: pipeFds[1]);
139 close(fd: pipeFds[1]);
140 QtConcurrent::run(f: [pipeFds] {
141 QFile readPipe;
142 if (readPipe.open(fd: pipeFds[0], ioFlags: QIODevice::ReadOnly)) {
143 qDebug() << "Pasted: " << readPipe.readLine();
144 }
145 close(fd: pipeFds[0]);
146 QCoreApplication::quit();
147 });
148 });
149 });
150 registry->setEventQueue(m_eventQueue);
151 registry->create(connection: m_connectionThreadObject);
152 registry->setup();
153}
154
155void PasteClient::render()
156{
157 const QSize &size = m_shellSurface->size();
158 auto buffer = m_shm->getBuffer(size, stride: size.width() * 4).toStrongRef();
159 buffer->setUsed(true);
160 QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
161 image.fill(color: Qt::blue);
162
163 m_surface->attachBuffer(buffer: *buffer);
164 m_surface->damage(rect: QRect(QPoint(0, 0), size));
165 m_surface->commit(flag: Surface::CommitFlag::None);
166 buffer->setUsed(false);
167}
168
169int main(int argc, char **argv)
170{
171 QCoreApplication app(argc, argv);
172 PasteClient client;
173 client.init();
174
175 return app.exec();
176}
177
178#include "pasteclient.moc"
179

source code of kwayland/tests/pasteclient.cpp