GCC Code Coverage Report


Directory: ./
File: server/xdg_shell_surface.cpp
Date: 2024-01-22 17:25:27
Exec Total Coverage
Lines: 90 111 81.1%
Branches: 34 52 65.4%

Line Branch Exec Source
1 /****************************************************************************
2 Copyright © 2020 Roman Gilg <subdiff@gmail.com>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 ****************************************************************************/
20 #include "xdg_shell_surface.h"
21 #include "xdg_shell_surface_p.h"
22
23 #include "surface_p.h"
24 #include "xdg_shell.h"
25 #include "xdg_shell_p.h"
26 #include "xdg_shell_popup.h"
27 #include "xdg_shell_popup_p.h"
28 #include "xdg_shell_positioner_p.h"
29 #include "xdg_shell_toplevel.h"
30 #include "xdg_shell_toplevel_p.h"
31
32 #include "wayland/resource.h"
33
34 namespace Wrapland::Server
35 {
36
37 const struct xdg_surface_interface XdgShellSurface::Private::s_interface = {
38 destroyCallback,
39 getTopLevelCallback,
40 getPopupCallback,
41 setWindowGeometryCallback,
42 ackConfigureCallback,
43 };
44
45
2/4
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
162 XdgShellSurface::Private::Private(Client* client,
46 uint32_t version,
47 uint32_t id,
48 XdgShell* shell,
49 Surface* surface,
50 XdgShellSurface* q_ptr)
51 162 : Wayland::Resource<XdgShellSurface>(client,
52 81 version,
53 81 id,
54 &xdg_surface_interface,
55 &s_interface,
56 81 q_ptr)
57 81 , m_shell(shell)
58 81 , m_surface(surface)
59 162 {
60 81 }
61
62 71 void XdgShellSurface::Private::getTopLevelCallback([[maybe_unused]] wl_client* wlClient,
63 wl_resource* wlResource,
64 uint32_t id)
65 {
66 71 auto priv = get_handle(wlResource)->d_ptr;
67
68
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 69 times.
71 if (!priv->check_creation_error()) {
69 2 return;
70 }
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
69 auto topLevel = new XdgShellToplevel(priv->version, id, priv->handle);
72 69 priv->toplevel = topLevel;
73
74 69 priv->m_surface->d_ptr->shellSurface = priv->handle;
75 138 QObject::connect(topLevel,
76 &XdgShellToplevel::resourceDestroyed,
77 69 priv->m_surface,
78 71 [surface = priv->m_surface] { surface->d_ptr->shellSurface = nullptr; });
79
80 69 Q_EMIT priv->m_shell->toplevelCreated(topLevel);
81 71 }
82
83 12 void XdgShellSurface::Private::getPopupCallback([[maybe_unused]] wl_client* wlClient,
84 wl_resource* wlResource,
85 uint32_t id,
86 wl_resource* wlParent,
87 wl_resource* wlPositioner)
88 {
89 12 auto priv = get_handle(wlResource)->d_ptr;
90
91
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (!priv->check_creation_error()) {
92 1 return;
93 }
94
95 11 auto positioner = priv->m_shell->d_ptr->getPositioner(wlPositioner);
96
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (!positioner) {
97 priv->postError(XDG_WM_BASE_ERROR_INVALID_POSITIONER, "Invalid positioner");
98 return;
99 }
100
101 // TODO(romangg): Allow to set parent surface via side-channel (see protocol description).
102
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
11 auto parent = wlParent ? priv->m_shell->d_ptr->getSurface(wlParent) : nullptr;
103
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
11 if (wlParent && !parent) {
104 priv->postError(XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT, "Invalid popup parent");
105 return;
106 }
107
108
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 auto popup = new XdgShellPopup(priv->version, id, priv->handle, parent);
109
110 11 popup->d_ptr->parent = parent;
111 11 popup->d_ptr->positioner = positioner->get_data();
112
113 11 priv->popup = popup;
114
115 11 priv->m_surface->d_ptr->shellSurface = priv->handle;
116 22 QObject::connect(popup,
117 &XdgShellPopup::resourceDestroyed,
118 11 priv->m_surface,
119 11 [surface = priv->m_surface] { surface->d_ptr->shellSurface = nullptr; });
120
121 11 Q_EMIT priv->m_shell->popupCreated(popup);
122 12 }
123
124 2 void XdgShellSurface::Private::setWindowGeometryCallback([[maybe_unused]] wl_client* wlClient,
125 wl_resource* wlResource,
126 int32_t pos_x,
127 int32_t pos_y,
128 int32_t width,
129 int32_t height)
130 {
131 2 auto priv = get_handle(wlResource)->d_ptr;
132
133
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 if (!priv->toplevel && !priv->popup) {
134 priv->postError(XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "No role object constructed.");
135 return;
136 }
137
138
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (width < 0 || height < 0) {
139 priv->postError(XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
140 "Tried to set invalid xdg-surface geometry");
141 return;
142 }
143
144 2 priv->pending_state.window_geometry = QRect(pos_x, pos_y, width, height);
145 2 priv->pending_state.window_geometry_set = true;
146 2 }
147
148 30 void XdgShellSurface::Private::ackConfigureCallback([[maybe_unused]] wl_client* wlClient,
149 wl_resource* wlResource,
150 uint32_t serial)
151 {
152 30 auto priv = get_handle(wlResource)->d_ptr;
153
154
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
30 if (!priv->toplevel && !priv->popup) {
155 priv->postError(XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "No role object constructed.");
156 return;
157 }
158
159
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (priv->toplevel) {
160 30 priv->toplevel->d_ptr->ackConfigure(serial);
161
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
30 } else if (priv->popup) {
162 priv->popup->d_ptr->ackConfigure(serial);
163 }
164 30 }
165
166 83 bool XdgShellSurface::Private::check_creation_error()
167 {
168
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 81 times.
83 if (m_surface->d_ptr->has_role()) {
169 2 postError(XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "Surface already has a role.");
170 2 return false;
171 }
172
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 80 times.
81 if (m_surface->d_ptr->had_buffer_attached) {
173 1 postError(XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED,
174 "Creation after a buffer was already attached.");
175 1 return false;
176 }
177 80 return true;
178 83 }
179
180 81 XdgShellSurface::XdgShellSurface(Client* client,
181 uint32_t version,
182 uint32_t id,
183 XdgShell* shell,
184 Surface* surface)
185 81 : QObject(nullptr)
186
2/4
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 81 times.
81 , d_ptr(new Private(client, version, id, shell, surface, this))
187 81 {
188 81 }
189
190 1 bool XdgShellSurface::configurePending() const
191 {
192 1 return !d_ptr->configureSerials.empty();
193 }
194
195 23 Surface* XdgShellSurface::surface() const
196 {
197 23 return d_ptr->m_surface;
198 }
199
200 9 void XdgShellSurface::commit()
201 {
202 9 auto const geo_set = d_ptr->pending_state.window_geometry_set;
203
204
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (geo_set) {
205 2 d_ptr->current_state.window_geometry = d_ptr->pending_state.window_geometry;
206 2 d_ptr->current_state.window_geometry_set = true;
207 2 }
208
209 9 d_ptr->pending_state = Private::state{};
210
211
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 if (d_ptr->toplevel) {
212 7 d_ptr->toplevel->d_ptr->commit();
213 7 }
214
215
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (geo_set) {
216 2 Q_EMIT window_geometry_changed(d_ptr->current_state.window_geometry);
217 2 }
218 9 }
219
220 5 QRect XdgShellSurface::window_geometry() const
221 {
222 5 auto const bounds_geo = surface()->expanse();
223
224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!d_ptr->current_state.window_geometry_set) {
225 return bounds_geo;
226 }
227
228 5 return d_ptr->current_state.window_geometry.intersected(bounds_geo);
229 5 }
230
231 QMargins XdgShellSurface::window_margins() const
232 {
233 auto const window_geo = window_geometry();
234
235 QMargins margins;
236
237 margins.setLeft(window_geo.left());
238 margins.setTop(window_geo.top());
239
240 auto const surface_size = surface()->size();
241
242 margins.setRight(surface_size.width() - window_geo.right() - 1);
243 margins.setBottom(surface_size.height() - window_geo.bottom() - 1);
244
245 return margins;
246 }
247
248 }
249