GCC Code Coverage Report


Directory: ./
File: server/data_control_v1.cpp
Date: 2024-01-22 17:25:27
Exec Total Coverage
Lines: 189 230 82.2%
Branches: 83 146 56.8%

Line Branch Exec Source
1 /*
2 SPDX-FileCopyrightText: 2021 Roman Gilg <subdiff@gmail.com>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only
5 */
6 #include "data_control_v1_p.h"
7
8 #include "client.h"
9 #include "data_device.h"
10 #include "data_source_p.h"
11 #include "display.h"
12 #include "primary_selection_p.h"
13 #include "selection_device_manager_p.h"
14 #include "selection_p.h"
15 #include "selection_pool.h"
16
17 #include "wayland/bind.h"
18 #include "wayland/global.h"
19
20 #include <wayland-server.h>
21
22 namespace Wrapland::Server
23 {
24
25 struct zwlr_data_control_manager_v1_interface const data_control_manager_v1::Private::s_interface
26 = {
27 cb<create_source>,
28 cb<get_device>,
29 resourceDestroyCallback,
30 };
31
32 38 data_control_manager_v1::Private::Private(data_control_manager_v1* q_ptr, Display* display)
33 76 : device_manager<data_control_manager_v1_global>(q_ptr,
34 38 display,
35 &zwlr_data_control_manager_v1_interface,
36 &s_interface)
37 38 {
38 38 display->globals.data_control_manager_v1 = q_ptr;
39 38 }
40
41 38 data_control_manager_v1::data_control_manager_v1(Display* display)
42
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
38 : d_ptr(new Private(this, display))
43 38 {
44
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 d_ptr->create();
45 38 }
46
47 76 data_control_manager_v1::~data_control_manager_v1() = default;
48
49 2 void data_control_manager_v1::create_source(Client* client, uint32_t version, uint32_t id)
50 {
51
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 [[maybe_unused]] auto src_res = new data_control_source_v1_res(client, version, id);
52 // TODO(romangg): Catch oom.
53
54 2 Q_EMIT source_created();
55 2 }
56
57 3 void data_control_manager_v1::get_device(Client* client, uint32_t version, uint32_t id, Seat* seat)
58 {
59
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 auto device = new data_control_device_v1(client, version, id, seat);
60 // TODO(romangg): Catch oom exception.
61
62
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (auto src = seat->d_ptr->data_devices.focus.source) {
63 device->send_selection(src);
64 }
65
66 7 QObject::connect(seat, &Seat::selectionChanged, device, [seat, device] {
67
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
4 if (auto source = seat->d_ptr->data_devices.focus.source;
68
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 !source || source != device->selection()) {
69 3 device->send_selection(source);
70 3 }
71 4 });
72
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (version >= ZWLR_DATA_CONTROL_DEVICE_V1_PRIMARY_SELECTION_SINCE_VERSION) {
74
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (auto src = seat->d_ptr->primary_selection_devices.focus.source) {
75 device->send_primary_selection(src);
76 }
77 7 QObject::connect(seat, &Seat::primarySelectionChanged, device, [seat, device] {
78
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
4 if (auto source = seat->d_ptr->primary_selection_devices.focus.source;
79
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 !source || source != device->primary_selection()) {
80 3 device->send_primary_selection(source);
81 3 }
82 4 });
83 3 }
84
85 3 Q_EMIT device_created(device);
86 3 }
87
88 template<typename Source>
89 2 data_control_offer_v1_res* data_control_device_v1::impl::send_data_offer_impl(Source source)
90 {
91
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 assert(source);
92
93
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 auto offer = new data_control_offer_v1_res(client->handle, version, source);
94
95
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (!offer->impl->resource) {
96 delete offer;
97 return nullptr;
98 }
99
100 2 send<zwlr_data_control_device_v1_send_data_offer>(offer->impl->resource);
101 2 offer->send_offers();
102 2 return offer;
103 2 }
104
105 1 data_control_offer_v1_res* data_control_device_v1::impl::send_data_offer(data_source* source)
106 {
107 1 return send_data_offer_impl(source);
108 }
109
110 data_control_offer_v1_res*
111 1 data_control_device_v1::impl::send_data_offer(primary_selection_source* source)
112 {
113 1 return send_data_offer_impl(source);
114 }
115
116 struct zwlr_data_control_device_v1_interface const data_control_device_v1::impl::s_interface = {
117 set_selection_callback,
118 destroyCallback,
119 set_primary_selection_callback,
120 };
121
122 // Similar to set_selection in selection_p.h
123 4 void set_control_selection(data_control_device_v1* handle,
124 selection_source_holder& holder,
125 data_control_source_v1_res* source_res)
126 {
127
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 auto source = source_res ? source_res->src() : nullptr;
128
129
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (holder.source == source) {
130 return;
131 }
132
133 4 QObject::disconnect(holder.destroyed_notifier);
134
135
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (holder.source) {
136 2 holder.source->cancel();
137 2 }
138
139 4 holder.source = source;
140
141
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (source) {
142 2 holder.destroyed_notifier = QObject::connect(
143 2 source_res, &data_control_source_v1_res::resourceDestroyed, handle, [handle, &holder] {
144 set_control_selection(handle, holder, nullptr);
145 });
146 2 } else {
147 2 holder.destroyed_notifier = QMetaObject::Connection();
148 }
149 4 Q_EMIT handle->selection_changed();
150 4 }
151
152
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
6 data_control_device_v1::impl::impl(Client* client,
153 uint32_t version,
154 uint32_t id,
155 Seat* seat,
156 data_control_device_v1* q_ptr)
157 6 : Wayland::Resource<data_control_device_v1>(client,
158 3 version,
159 3 id,
160 &zwlr_data_control_device_v1_interface,
161 &s_interface,
162 3 q_ptr)
163 3 , m_seat{seat}
164 3 {
165 3 }
166
167 template<typename Source, typename Devices>
168 4 void data_control_device_v1::impl::set_selection_impl(Devices& seat_devices,
169 selection_source_holder& selection_holder,
170 data_control_device_v1* handle,
171 wl_resource* wlSource)
172 {
173
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
4 if (!wlSource) {
174 2 set_control_selection(handle, selection_holder, nullptr);
175 2 seat_devices.set_selection(nullptr);
176 2 return;
177 }
178
179 2 auto source = Resource<data_control_source_v1_res>::get_handle(wlSource);
180
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (!std::holds_alternative<std::monostate>(source->data_src)) {
181 handle->d_ptr->postError(ZWLR_DATA_CONTROL_DEVICE_V1_ERROR_USED_SOURCE,
182 "Source already used");
183 return;
184 }
185
186
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 auto src = std::unique_ptr<Source>(new Source);
187
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 src->d_ptr->mimeTypes = source->src()->early_mime_types;
188
189 2 src->d_ptr->res = source;
190
4/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
4 QObject::connect(source,
191 &data_control_source_v1_res::resourceDestroyed,
192 2 src.get(),
193 2 &Source::resourceDestroyed);
194
195
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 set_control_selection(handle, selection_holder, source);
196
197 // A connection from the set_selection call accesses data_src field. So move it over before.
198 2 auto src_ptr = src.get();
199 2 source->data_src = std::move(src);
200
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 seat_devices.set_selection(src_ptr);
201 4 }
202
203 2 void data_control_device_v1::impl::set_selection_callback(wl_client* /*wlClient*/,
204 wl_resource* wlResource,
205 wl_resource* wlSource)
206 {
207 2 auto handle = Resource::get_handle(wlResource);
208 2 auto& seat_devices = handle->d_ptr->m_seat->d_ptr->data_devices;
209 2 auto& selection_holder = handle->d_ptr->selection;
210
211 2 set_selection_impl<data_source>(seat_devices, selection_holder, handle, wlSource);
212 2 }
213
214 2 void data_control_device_v1::impl::set_primary_selection_callback(wl_client* /*wlClient*/,
215 wl_resource* wlResource,
216 wl_resource* wlSource)
217 {
218 2 auto handle = Resource::get_handle(wlResource);
219 2 auto& seat_devices = handle->d_ptr->m_seat->d_ptr->primary_selection_devices;
220 2 auto& selection_holder = handle->d_ptr->primary_selection;
221
222 2 set_selection_impl<primary_selection_source>(seat_devices, selection_holder, handle, wlSource);
223 2 }
224
225 3 data_control_device_v1::data_control_device_v1(Client* client,
226 uint32_t version,
227 uint32_t id,
228 Seat* seat)
229
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 : d_ptr(new data_control_device_v1::impl(client, version, id, seat, this))
230 3 {
231 3 }
232
233 template<typename Source>
234 15 Source* data_control_device_v1::impl::get_selection(selection_source_holder const& holder)
235 {
236
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
15 if (holder.source) {
237
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
4 if (auto src = std::get_if<std::unique_ptr<Source>>(&holder.source->data_src)) {
238 4 return src->get();
239 }
240 }
241
242 11 return nullptr;
243 15 }
244
245 11 data_source* data_control_device_v1::selection() const
246 {
247 11 return d_ptr->get_selection<data_source>(d_ptr->selection);
248 }
249
250 4 primary_selection_source* data_control_device_v1::primary_selection() const
251 {
252 4 return d_ptr->get_selection<primary_selection_source>(d_ptr->primary_selection);
253 }
254
255 3 void data_control_device_v1::send_selection(data_source* source) const
256 {
257
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (!source) {
258 2 d_ptr->send<zwlr_data_control_device_v1_send_selection>(nullptr);
259 2 return;
260 }
261
262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (auto offer = d_ptr->send_data_offer(source)) {
263 1 d_ptr->send<zwlr_data_control_device_v1_send_selection>(offer->impl->resource);
264 1 }
265 3 }
266
267 3 void data_control_device_v1::send_primary_selection(primary_selection_source* source) const
268 {
269
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 assert(d_ptr->version >= ZWLR_DATA_CONTROL_DEVICE_V1_PRIMARY_SELECTION_SINCE_VERSION);
270
271
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (!source) {
272 2 d_ptr->send<zwlr_data_control_device_v1_send_primary_selection>(nullptr);
273 2 return;
274 }
275
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (auto offer = d_ptr->send_data_offer(source)) {
277 1 d_ptr->send<zwlr_data_control_device_v1_send_primary_selection>(offer->impl->resource);
278 1 }
279 3 }
280
281 2 data_control_source_v1_res::res_impl::res_impl(Client* client,
282 uint32_t version,
283 uint32_t id,
284 data_control_source_v1_res* q_ptr)
285 4 : Wayland::Resource<data_control_source_v1_res>(client,
286 2 version,
287 2 id,
288 &zwlr_data_control_source_v1_interface,
289 &s_interface,
290 2 q_ptr)
291 2 , q_ptr{q_ptr}
292 2 {
293 2 }
294
295 struct zwlr_data_control_source_v1_interface const data_control_source_v1_res::res_impl::s_interface
296 = {
297 offer_callback,
298 destroyCallback,
299 };
300
301 template<class... Ts>
302 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
303 struct overload : Ts... {
304 using Ts::operator()...;
305 };
306 template<class... Ts>
307 overload(Ts...) -> overload<Ts...>;
308
309 void data_control_source_v1_res::res_impl::offer_callback(wl_client* /*wlClient*/,
310 wl_resource* wlResource,
311 char const* mimeType)
312 {
313 auto handle = Resource::get_handle(wlResource);
314
315 std::visit(overload{[&](std::unique_ptr<data_source>& src) {
316 offer_mime_type(src->d_ptr.get(), mimeType);
317 },
318 [&](std::unique_ptr<primary_selection_source>& src) {
319 offer_mime_type(src->d_ptr.get(), mimeType);
320 },
321 [&](std::monostate /*unused*/) {
322 handle->src()->early_mime_types.emplace_back(mimeType);
323 }},
324 handle->data_src);
325 }
326
327 4 data_control_source_v1_res::data_control_source_v1_res(Client* client,
328 uint32_t version,
329 uint32_t id)
330
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 : impl{new data_control_source_v1_res::res_impl(client, version, id, this)}
331 2 {
332 2 }
333
334 4 data_control_source_v1_res::~data_control_source_v1_res() = default;
335
336 void data_control_source_v1_res::request_data(std::string const& mime_type, int32_t fd) const
337 {
338 // TODO(unknown author): does this require a sanity check on the possible mime type?
339 impl->send<zwlr_data_control_source_v1_send_send>(mime_type.c_str(), fd);
340 close(fd);
341 }
342
343 4 void data_control_source_v1_res::cancel() const
344 {
345 4 impl->send<zwlr_data_control_source_v1_send_cancelled>();
346 4 }
347
348 4 data_control_source_v1_res* data_control_source_v1_res::src()
349 {
350 4 return this;
351 }
352
353 struct zwlr_data_control_offer_v1_interface const data_control_offer_v1_res_impl::s_interface = {
354 receive_callback,
355 destroyCallback,
356 };
357
358 4 data_control_offer_v1_res_impl::data_control_offer_v1_res_impl(Client* client,
359 uint32_t version,
360 data_control_offer_v1_res* q_ptr)
361 4 : Wayland::Resource<data_control_offer_v1_res>(client,
362 2 version,
363 0,
364 &zwlr_data_control_offer_v1_interface,
365 &s_interface,
366 2 q_ptr)
367 2 {
368 2 }
369
370 void data_control_offer_v1_res_impl::receive_callback(wl_client* /*wlClient*/,
371 wl_resource* wlResource,
372 char const* mime_type,
373 int32_t fd)
374 {
375 auto handle = Resource::get_handle(wlResource);
376
377 std::visit(overload{[&](data_source* src) {
378 assert(src);
379 receive_mime_type_offer(src, mime_type, fd);
380 },
381 [&](primary_selection_source* src) {
382 assert(src);
383 receive_mime_type_offer(src, mime_type, fd);
384 },
385 [&](std::monostate /*unused*/) { close(fd); }},
386 handle->impl->src);
387 }
388
389 1 data_control_offer_v1_res::data_control_offer_v1_res(Client* client,
390 uint32_t version,
391 data_source* source)
392
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 : impl(new data_control_offer_v1_res_impl(client, version, this))
393 1 {
394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(source);
395 1 impl->src = source;
396
397
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 QObject::connect(source, &data_source::mime_type_offered, this, [this](auto const& mime_type) {
398 impl->send<zwlr_data_control_offer_v1_send_offer>(mime_type.c_str());
399 });
400
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 QObject::connect(source, &data_source::resourceDestroyed, this, [this] { impl->src = {}; });
401 1 }
402
403 1 data_control_offer_v1_res::data_control_offer_v1_res(Client* client,
404 uint32_t version,
405 primary_selection_source* source)
406
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 : impl(new data_control_offer_v1_res_impl(client, version, this))
407 1 {
408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(source);
409 1 impl->src = source;
410
411
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 QObject::connect(
412 1 source, &primary_selection_source::mime_type_offered, this, [this](auto const& mime_type) {
413 impl->send<zwlr_data_control_offer_v1_send_offer>(mime_type.c_str());
414 });
415
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 QObject::connect(
416 1 source, &primary_selection_source::resourceDestroyed, this, [this] { impl->src = {}; });
417 1 }
418
419 2 void data_control_offer_v1_res::send_offers() const
420 {
421 4 auto send_mime_types = [this](auto const& mime_types) {
422
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (auto const& mt : mime_types) {
423 2 impl->send<zwlr_data_control_offer_v1_send_offer>(mt.c_str());
424 }
425 2 };
426
427 5 std::visit(overload{[&](data_source* src) {
428
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 assert(src);
429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 send_mime_types(src->mime_types());
430 1 },
431 3 [&](primary_selection_source* src) {
432
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 assert(src);
433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 send_mime_types(src->mime_types());
434 1 },
435 [](std::monostate /*unused*/) { assert(false); }},
436 2 impl->src);
437 2 }
438
439 }
440