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 | |
30 | using namespace KWayland::Client; |
31 | |
32 | class PasteClient : public QObject |
33 | { |
34 | Q_OBJECT |
35 | public: |
36 | explicit PasteClient(QObject *parent = nullptr); |
37 | ~PasteClient() override; |
38 | |
39 | void init(); |
40 | |
41 | private: |
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 | |
57 | PasteClient::PasteClient(QObject *parent) |
58 | : QObject(parent) |
59 | , m_connectionThread(new QThread(this)) |
60 | , m_connectionThreadObject(new ConnectionThread()) |
61 | { |
62 | } |
63 | |
64 | PasteClient::~PasteClient() |
65 | { |
66 | m_connectionThread->quit(); |
67 | m_connectionThread->wait(); |
68 | m_connectionThreadObject->deleteLater(); |
69 | } |
70 | |
71 | void 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 | |
91 | void 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 | |
155 | void 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 | |
169 | int 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 | |