GCC Code Coverage Report


Directory: ./
File: server/layer_shell_v1.cpp
Date: 2024-01-22 17:25:27
Exec Total Coverage
Lines: 208 249 83.5%
Branches: 70 131 53.4%

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 "layer_shell_v1_p.h"
7
8 #include "display.h"
9 #include "surface_p.h"
10 #include "wl_output_p.h"
11 #include "xdg_shell_popup.h"
12
13 namespace Wrapland::Server
14 {
15
16 const struct zwlr_layer_shell_v1_interface LayerShellV1::Private::s_interface = {
17 cb<getCallback>,
18 cb<destroyCallback>,
19 };
20
21 10 LayerShellV1::Private::Private(Display* display, LayerShellV1* qptr)
22 10 : LayerShellV1Global(qptr, display, &zwlr_layer_shell_v1_interface, &s_interface)
23 10 {
24
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 create();
25 10 }
26
27 11 LayerSurfaceV1::Layer get_layer(uint32_t layer)
28 {
29
2/5
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
11 switch (layer) {
30 case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM:
31 return Layer::Bottom;
32 case ZWLR_LAYER_SHELL_V1_LAYER_TOP:
33 1 return Layer::Top;
34 case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY:
35 return Layer::Overlay;
36 10 case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND:
37 default:
38 10 return Layer::Background;
39 }
40 11 }
41
42 10 void LayerShellV1::Private::getCallback(LayerShellV1Bind* bind,
43 uint32_t id,
44 wl_resource* wlSurface,
45 wl_resource* wlOutput,
46 uint32_t wlLayer,
47 char const* nspace)
48 {
49 10 auto surface = Wayland::Resource<Surface>::get_handle(wlSurface);
50
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 auto output = wlOutput ? WlOutputGlobal::get_handle(wlOutput)->output() : nullptr;
51 10 auto layer = get_layer(wlLayer);
52
53
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (surface->d_ptr->has_role()) {
54 bind->post_error(ZWLR_LAYER_SHELL_V1_ERROR_ROLE, "Surface already has a role.");
55 return;
56 }
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (surface->d_ptr->had_buffer_attached) {
58 bind->post_error(ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED,
59 "Creation after a buffer was already attached.");
60 return;
61 }
62
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 if (wlLayer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND && layer == Layer::Background) {
63 bind->post_error(ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, "Invalid layer set.");
64 return;
65 }
66
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 auto layer_surface = new LayerSurfaceV1(
67
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 bind->client->handle, bind->version, id, surface, output, layer, std::string(nspace));
68
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (!layer_surface->d_ptr->resource) {
69 bind->post_no_memory();
70 delete layer_surface;
71 return;
72 }
73 10 Q_EMIT bind->global()->handle->surface_created(layer_surface);
74 10 }
75
76 10 void LayerShellV1::Private::destroyCallback([[maybe_unused]] LayerShellV1Bind* bind)
77 {
78 // TODO(romangg): unregister the client?
79 }
80 10
81 10 LayerShellV1::LayerShellV1(Display* display)
82
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 : d_ptr(new Private(display, this))
83 10 {
84 10 }
85
86 20 LayerShellV1::~LayerShellV1() = default;
87
88 const struct zwlr_layer_surface_v1_interface LayerSurfaceV1::Private::s_interface = {
89 setSizeCallback,
90 setAnchorCallback,
91 setExclusiveZoneCallback,
92 setMarginCallback,
93 setKeyboardInteractivityCallback,
94 getPopupCallback,
95 ackConfigureCallback,
96 destroyCallback,
97 setLayerCallback,
98 };
99
100
3/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
30 LayerSurfaceV1::Private::Private(Client* client,
101 uint32_t version,
102 uint32_t id,
103 Surface* surface,
104 Server::output* output,
105 Layer layer,
106 std::string domain,
107 LayerSurfaceV1* qptr)
108 20 : Wayland::Resource<LayerSurfaceV1>(client,
109 10 version,
110 10 id,
111 &zwlr_layer_surface_v1_interface,
112 &s_interface,
113 10 qptr)
114 10 , surface{surface}
115 10 , domain{std::move(domain)}
116 10 {
117
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 if (output) {
118
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 set_output(output);
119 2 }
120 10 current.layer = layer;
121 10 pending.layer = layer;
122
123 // First commit must be processed.
124 10 current.set = true;
125 10 pending.set = true;
126
127 10 surface->d_ptr->layer_surface = qptr;
128
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
20 QObject::connect(surface, &Surface::resourceDestroyed, qptr, [this] {
129 10 this->surface = nullptr;
130
131 // TODO(romangg): do not use that but an extra signal or automatic with surface.
132 10 Q_EMIT handle->resourceDestroyed();
133 10 });
134 10 }
135
136 20 LayerSurfaceV1::Private::~Private()
137 20 {
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (surface) {
139 surface->d_ptr->layer_surface = nullptr;
140 }
141 20 }
142
143 9 void LayerSurfaceV1::Private::setSizeCallback([[maybe_unused]] wl_client* wlClient,
144 wl_resource* wlResource,
145 uint32_t width,
146 uint32_t height)
147 {
148 9 auto priv = get_handle(wlResource)->d_ptr;
149 9 priv->pending.size = QSize(static_cast<int>(width), static_cast<int>(height));
150 9 priv->pending.set = true;
151 9 }
152
153 8 void LayerSurfaceV1::Private::setAnchorCallback([[maybe_unused]] wl_client* wlClient,
154 wl_resource* wlResource,
155 uint32_t anchor)
156 {
157 16 auto get_anchor = [](auto anchor) {
158 8 Qt::Edges ret;
159
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
160 2 ret |= Qt::TopEdge;
161 2 }
162
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 if (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
163 3 ret |= Qt::BottomEdge;
164 3 }
165
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
166 6 ret |= Qt::LeftEdge;
167 6 }
168
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 if (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
169 3 ret |= Qt::RightEdge;
170 3 }
171 8 return ret;
172 };
173
174 8 auto priv = get_handle(wlResource)->d_ptr;
175 8 priv->pending.anchor = get_anchor(anchor);
176 8 priv->pending.set = true;
177 8 }
178
179 11 void LayerSurfaceV1::Private::setExclusiveZoneCallback([[maybe_unused]] wl_client* wlClient,
180 wl_resource* wlResource,
181 int zone)
182 {
183 11 auto priv = get_handle(wlResource)->d_ptr;
184 11 priv->pending.exclusive_zone = zone;
185 11 priv->pending.set = true;
186 11 }
187
188 3 void LayerSurfaceV1::Private::setMarginCallback([[maybe_unused]] wl_client* wlClient,
189 wl_resource* wlResource,
190 int top,
191 int right,
192 int bottom,
193 int left)
194 {
195 3 auto priv = get_handle(wlResource)->d_ptr;
196 3 priv->pending.margins = QMargins(left, top, right, bottom);
197 3 priv->pending.set = true;
198 3 }
199
200 1 void LayerSurfaceV1::Private::setKeyboardInteractivityCallback([[maybe_unused]] wl_client* wlClient,
201 wl_resource* wlResource,
202 uint32_t interactivity)
203 {
204 1 auto priv = get_handle(wlResource)->d_ptr;
205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
206 priv->pending.keyboard_interactivity = KeyboardInteractivity::Exclusive;
207
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) {
208 1 priv->pending.keyboard_interactivity = KeyboardInteractivity::OnDemand;
209 1 } else {
210 priv->pending.keyboard_interactivity = KeyboardInteractivity::None;
211 }
212 1 priv->pending.set = true;
213 1 }
214
215 1 void LayerSurfaceV1::Private::getPopupCallback([[maybe_unused]] wl_client* wlClient,
216 wl_resource* wlResource,
217 wl_resource* wlPopup)
218 {
219 1 auto priv = get_handle(wlResource)->d_ptr;
220 1 auto popup = Wayland::Resource<XdgShellPopup>::get_handle(wlPopup);
221
222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (popup->transientFor()) {
223 // TODO(romangg): * transientFor() does not cover the case where popup was assigned through
224 // another request like this get_popup call. On the other side the protocol
225 // only talks about it in regards to the creation time anyways.
226 // * Should we send an error? Protocol doesn't say so.
227 return;
228 }
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (popup->surface()->surface()->d_ptr->had_buffer_attached) {
230 // TODO(romangg): Should we send an error? Protocol doesn't say so.
231 return;
232 }
233
234 // TODO(romangg): check that the popup has a null parent and initial state already set.
235 1 Q_EMIT priv->handle->got_popup(popup);
236 1 }
237
238 2 void LayerSurfaceV1::Private::ackConfigureCallback([[maybe_unused]] wl_client* wlClient,
239 wl_resource* wlResource,
240 uint32_t serial)
241 {
242 2 auto priv = get_handle(wlResource)->d_ptr;
243
244 2 auto& serials = priv->configure_serials;
245
246
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (std::count(serials.cbegin(), serials.cend(), serial) == 0) {
247 return;
248 }
249
250 2 for (;;) {
251
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (serials.empty()) {
252 break;
253 }
254
255 2 auto next = serials.front();
256 2 serials.pop_front();
257
258
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (next == serial) {
259 2 break;
260 }
261 }
262 2 Q_EMIT priv->handle->configure_acknowledged(serial);
263 2 }
264
265 1 void LayerSurfaceV1::Private::setLayerCallback([[maybe_unused]] wl_client* wlClient,
266 wl_resource* wlResource,
267 uint32_t layer)
268 {
269 1 auto priv = get_handle(wlResource)->d_ptr;
270 1 priv->pending.layer = get_layer(layer);
271 1 priv->pending.set = true;
272 1 }
273
274 2 void LayerSurfaceV1::Private::set_output(Server::output* output)
275 {
276
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 assert(output);
277 2 this->output = output;
278 3 connect(output->wayland_output(), &WlOutput::removed, handle, [this]() {
279 1 this->output = nullptr;
280 1 handle->close();
281 1 Q_EMIT handle->resourceDestroyed();
282 1 });
283 2 }
284
285 19 bool LayerSurfaceV1::Private::commit()
286 {
287
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17 times.
19 if (closed) {
288 2 return false;
289 }
290
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
17 if (!pending.set) {
291 1 current.set = false;
292 1 return true;
293 }
294
295
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (pending.size.width() == 0) {
296 if (!(pending.anchor & Qt::LeftEdge) || !(pending.anchor & Qt::RightEdge)) {
297 postError(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE,
298 "Width zero while not anchoring to both vertical edges.");
299 return false;
300 }
301 }
302
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (pending.size.height() == 0) {
303 if (!(pending.anchor & Qt::TopEdge) || !(pending.anchor & Qt::BottomEdge)) {
304 postError(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE,
305 "Height zero while not anchoring to both horizontal edges.");
306 return false;
307 }
308 }
309
310 16 current = pending;
311 16 pending.set = false;
312 16 return true;
313 19 }
314
315 10 LayerSurfaceV1::LayerSurfaceV1(Client* client,
316 uint32_t version,
317 uint32_t id,
318 Surface* surface,
319 Server::output* output,
320 Layer layer,
321 std::string domain)
322
2/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10 : d_ptr(new Private(client, version, id, surface, output, layer, std::move(domain), this))
323 10 {
324 10 }
325
326 10 Surface* LayerSurfaceV1::surface() const
327 {
328 10 return d_ptr->surface;
329 }
330
331 1 Server::output* LayerSurfaceV1::output() const
332 {
333 1 return d_ptr->output;
334 }
335
336 void LayerSurfaceV1::set_output(Server::output* output)
337 {
338 assert(output);
339 assert(!d_ptr->output);
340 d_ptr->set_output(output);
341 }
342
343 std::string LayerSurfaceV1::domain() const
344 {
345 return d_ptr->domain;
346 }
347
348 1 QSize LayerSurfaceV1::size() const
349 {
350 1 return d_ptr->current.size;
351 }
352
353 1 Qt::Edges LayerSurfaceV1::anchor() const
354 {
355 1 return d_ptr->current.anchor;
356 }
357
358 5 QMargins LayerSurfaceV1::margins() const
359 {
360 5 auto const anchor = d_ptr->current.anchor;
361 5 auto margins = d_ptr->current.margins;
362
363
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if (!(anchor & Qt::LeftEdge)) {
364 2 margins.setLeft(0);
365 2 }
366
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (!(anchor & Qt::TopEdge)) {
367 4 margins.setTop(0);
368 4 }
369
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (!(anchor & Qt::RightEdge)) {
370 3 margins.setRight(0);
371 3 }
372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!(anchor & Qt::BottomEdge)) {
373 5 margins.setBottom(0);
374 5 }
375
376 5 return margins;
377 }
378
379 1 LayerSurfaceV1::Layer LayerSurfaceV1::layer() const
380 {
381 1 return d_ptr->current.layer;
382 }
383
384 LayerSurfaceV1::KeyboardInteractivity LayerSurfaceV1::keyboard_interactivity() const
385 {
386 return d_ptr->current.keyboard_interactivity;
387 }
388
389 16 int LayerSurfaceV1::exclusive_zone() const
390 {
391 16 auto zone = d_ptr->current.exclusive_zone;
392
393
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 if (zone <= 0) {
394 10 return zone;
395 }
396
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (exclusive_edge() == 0) {
397 // By protocol when no exclusive edge is well defined, a positive zone is set to 0.
398 3 return 0;
399 }
400
401 3 return zone;
402 16 }
403
404 16 Qt::Edge LayerSurfaceV1::exclusive_edge() const
405 {
406 16 auto const& state = d_ptr->current;
407
408
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 11 times.
16 if (state.exclusive_zone <= 0) {
409 5 return Qt::Edge();
410 }
411
412 11 auto anchor = state.anchor;
413
414
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
11 if (anchor & Qt::TopEdge) {
415
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (anchor & Qt::BottomEdge) {
416 2 return Qt::Edge();
417 }
418 if (anchor == Qt::TopEdge) {
419 return Qt::TopEdge;
420 }
421 if ((anchor & Qt::LeftEdge) && (anchor & Qt::RightEdge)) {
422 return Qt::TopEdge;
423 }
424 return Qt::Edge();
425 }
426
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (anchor & Qt::BottomEdge) {
427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (anchor == Qt::BottomEdge) {
428 return Qt::BottomEdge;
429 }
430
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
4 if ((anchor & Qt::LeftEdge) && (anchor & Qt::RightEdge)) {
431 2 return Qt::BottomEdge;
432 }
433 2 }
434
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (anchor == Qt::LeftEdge) {
435 3 return Qt::LeftEdge;
436 }
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (anchor == Qt::RightEdge) {
438 return Qt::RightEdge;
439 }
440 4 return Qt::Edge();
441 16 }
442
443 2 uint32_t LayerSurfaceV1::configure(QSize const& size)
444 {
445 2 auto serial = d_ptr->client->display()->handle->nextSerial();
446 2 d_ptr->configure_serials.push_back(serial);
447 2 d_ptr->send<zwlr_layer_surface_v1_send_configure>(serial, size.width(), size.height());
448 2 return serial;
449 }
450
451 1 void LayerSurfaceV1::close()
452 {
453 1 d_ptr->closed = true;
454 1 d_ptr->send<zwlr_layer_surface_v1_send_closed>();
455 1 }
456
457 bool LayerSurfaceV1::change_pending() const
458 {
459 return d_ptr->current.set;
460 }
461
462 }
463