1 | /* |
2 | SPDX-FileCopyrightText: 2016 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 "../compat/wayland-xdg-shell-v5-client-protocol.h" |
7 | #include "event_queue.h" |
8 | #include "output.h" |
9 | #include "seat.h" |
10 | #include "surface.h" |
11 | #include "wayland_pointer_p.h" |
12 | #include "xdgshell_p.h" |
13 | |
14 | namespace KWayland |
15 | { |
16 | namespace Client |
17 | { |
18 | class XdgShellUnstableV5::Private : public XdgShell::Private |
19 | { |
20 | public: |
21 | void setupV5(xdg_shell *shell) override; |
22 | void release() override; |
23 | void destroy() override; |
24 | bool isValid() const override; |
25 | XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) override; |
26 | XdgShellPopup *getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) override; |
27 | |
28 | using XdgShell::Private::operator xdg_wm_base *; |
29 | using XdgShell::Private::operator zxdg_shell_v6 *; |
30 | operator xdg_shell *() override |
31 | { |
32 | return xdgshellv5; |
33 | } |
34 | operator xdg_shell *() const override |
35 | { |
36 | return xdgshellv5; |
37 | } |
38 | |
39 | static void pingCallback(void *data, struct xdg_shell *shell, uint32_t serial); |
40 | |
41 | WaylandPointer<xdg_shell, zxdg_shell_v5_destroy> xdgshellv5; |
42 | static const struct zxdg_shell_v5_listener s_shellListener; |
43 | }; |
44 | |
45 | const struct zxdg_shell_v5_listener XdgShellUnstableV5::Private::s_shellListener = { |
46 | .ping: pingCallback, |
47 | }; |
48 | |
49 | void XdgShellUnstableV5::Private::pingCallback(void *data, struct xdg_shell *shell, uint32_t serial) |
50 | { |
51 | Q_UNUSED(data); |
52 | zxdg_shell_v5_pong(xdg_shell: shell, serial); |
53 | } |
54 | |
55 | void XdgShellUnstableV5::Private::setupV5(xdg_shell *shell) |
56 | { |
57 | Q_ASSERT(shell); |
58 | Q_ASSERT(!xdgshellv5); |
59 | xdgshellv5.setup(pointer: shell); |
60 | zxdg_shell_v5_use_unstable_version(xdg_shell: xdgshellv5, version: 5); |
61 | zxdg_shell_v5_add_listener(xdg_shell: shell, listener: &s_shellListener, data: this); |
62 | } |
63 | |
64 | void XdgShellUnstableV5::Private::release() |
65 | { |
66 | xdgshellv5.release(); |
67 | } |
68 | |
69 | void XdgShellUnstableV5::Private::destroy() |
70 | { |
71 | xdgshellv5.destroy(); |
72 | } |
73 | |
74 | bool XdgShellUnstableV5::Private::isValid() const |
75 | { |
76 | return xdgshellv5.isValid(); |
77 | } |
78 | |
79 | XdgShellSurface *XdgShellUnstableV5::Private::getXdgSurface(Surface *surface, QObject *parent) |
80 | { |
81 | Q_ASSERT(isValid()); |
82 | XdgShellSurface *s = new XdgShellSurfaceUnstableV5(parent); |
83 | auto w = zxdg_shell_v5_get_xdg_surface(xdg_shell: xdgshellv5, surface: *surface); |
84 | if (queue) { |
85 | queue->addProxy(proxy: w); |
86 | } |
87 | s->setup(w); |
88 | return s; |
89 | } |
90 | |
91 | XdgShellPopup * |
92 | XdgShellUnstableV5::Private::getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) |
93 | { |
94 | Q_ASSERT(isValid()); |
95 | XdgShellPopup *s = new XdgShellPopupUnstableV5(parent); |
96 | auto w = zxdg_shell_v5_get_xdg_popup(xdg_shell: xdgshellv5, surface: *surface, parent: *parentSurface, seat: *seat, serial, x: parentPos.x(), y: parentPos.y()); |
97 | if (queue) { |
98 | queue->addProxy(proxy: w); |
99 | } |
100 | s->setup(w); |
101 | return s; |
102 | } |
103 | |
104 | XdgShellUnstableV5::XdgShellUnstableV5(QObject *parent) |
105 | : XdgShell(new Private, parent) |
106 | { |
107 | } |
108 | |
109 | XdgShellUnstableV5::~XdgShellUnstableV5() = default; |
110 | |
111 | class XdgShellSurfaceUnstableV5::Private : public XdgShellSurface::Private |
112 | { |
113 | public: |
114 | Private(XdgShellSurface *q); |
115 | WaylandPointer<xdg_surface, zxdg_surface_v5_destroy> xdgsurfacev5; |
116 | |
117 | void setupV5(xdg_surface *surface) override; |
118 | void release() override; |
119 | void destroy() override; |
120 | bool isValid() const override; |
121 | |
122 | using XdgShellSurface::Private::operator zxdg_surface_v6 *; |
123 | using XdgShellSurface::Private::operator zxdg_toplevel_v6 *; |
124 | using XdgShellSurface::Private::operator xdg_toplevel *; |
125 | operator xdg_surface *() override |
126 | { |
127 | return xdgsurfacev5; |
128 | } |
129 | operator xdg_surface *() const override |
130 | { |
131 | return xdgsurfacev5; |
132 | } |
133 | |
134 | void setTransientFor(XdgShellSurface *parent) override; |
135 | void setTitle(const QString &title) override; |
136 | void setAppId(const QByteArray &appId) override; |
137 | void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) override; |
138 | void move(Seat *seat, quint32 serial) override; |
139 | void resize(Seat *seat, quint32 serial, Qt::Edges edges) override; |
140 | void ackConfigure(quint32 serial) override; |
141 | void setMaximized() override; |
142 | void unsetMaximized() override; |
143 | void setFullscreen(Output *output) override; |
144 | void unsetFullscreen() override; |
145 | void setMinimized() override; |
146 | void setMaxSize(const QSize &size) override; |
147 | void setMinSize(const QSize &size) override; |
148 | |
149 | private: |
150 | static void configureCallback(void *data, xdg_surface *xdg_surface, int32_t width, int32_t height, wl_array *states, uint32_t serial); |
151 | static void closeCallback(void *data, xdg_surface *xdg_surface); |
152 | |
153 | static const struct zxdg_surface_v5_listener s_listener; |
154 | }; |
155 | |
156 | const struct zxdg_surface_v5_listener XdgShellSurfaceUnstableV5::Private::s_listener = {.configure: configureCallback, .close: closeCallback}; |
157 | |
158 | void XdgShellSurfaceUnstableV5::Private::configureCallback(void *data, |
159 | xdg_surface *xdg_surface, |
160 | int32_t width, |
161 | int32_t height, |
162 | wl_array *wlStates, |
163 | uint32_t serial) |
164 | { |
165 | auto s = reinterpret_cast<XdgShellSurfaceUnstableV5::Private *>(data); |
166 | Q_ASSERT(s->xdgsurfacev5 == xdg_surface); |
167 | uint32_t *state = reinterpret_cast<uint32_t *>(wlStates->data); |
168 | size_t numStates = wlStates->size / sizeof(uint32_t); |
169 | States states; |
170 | for (size_t i = 0; i < numStates; i++) { |
171 | switch (state[i]) { |
172 | case ZXDG_SURFACE_V5_STATE_MAXIMIZED: |
173 | states = states | XdgShellSurface::State::Maximized; |
174 | break; |
175 | case ZXDG_SURFACE_V5_STATE_FULLSCREEN: |
176 | states = states | XdgShellSurface::State::Fullscreen; |
177 | break; |
178 | case ZXDG_SURFACE_V5_STATE_RESIZING: |
179 | states = states | XdgShellSurface::State::Resizing; |
180 | break; |
181 | case ZXDG_SURFACE_V5_STATE_ACTIVATED: |
182 | states = states | XdgShellSurface::State::Activated; |
183 | break; |
184 | } |
185 | } |
186 | const QSize size = QSize(width, height); |
187 | Q_EMIT s->q->configureRequested(size, states, serial); |
188 | if (!size.isNull()) { |
189 | s->q->setSize(size); |
190 | } |
191 | } |
192 | |
193 | void XdgShellSurfaceUnstableV5::Private::closeCallback(void *data, xdg_surface *xdg_surface) |
194 | { |
195 | auto s = reinterpret_cast<XdgShellSurfaceUnstableV5::Private *>(data); |
196 | Q_ASSERT(s->xdgsurfacev5 == xdg_surface); |
197 | Q_EMIT s->q->closeRequested(); |
198 | } |
199 | |
200 | XdgShellSurfaceUnstableV5::Private::Private(XdgShellSurface *q) |
201 | : XdgShellSurface::Private(q) |
202 | { |
203 | } |
204 | |
205 | void XdgShellSurfaceUnstableV5::Private::setupV5(xdg_surface *surface) |
206 | { |
207 | Q_ASSERT(surface); |
208 | Q_ASSERT(!xdgsurfacev5); |
209 | xdgsurfacev5.setup(pointer: surface); |
210 | zxdg_surface_v5_add_listener(xdg_surface: xdgsurfacev5, listener: &s_listener, data: this); |
211 | } |
212 | |
213 | void XdgShellSurfaceUnstableV5::Private::release() |
214 | { |
215 | xdgsurfacev5.release(); |
216 | } |
217 | |
218 | void XdgShellSurfaceUnstableV5::Private::destroy() |
219 | { |
220 | xdgsurfacev5.destroy(); |
221 | } |
222 | |
223 | bool XdgShellSurfaceUnstableV5::Private::isValid() const |
224 | { |
225 | return xdgsurfacev5.isValid(); |
226 | } |
227 | |
228 | void XdgShellSurfaceUnstableV5::Private::setTransientFor(XdgShellSurface *parent) |
229 | { |
230 | xdg_surface *parentSurface = nullptr; |
231 | if (parent) { |
232 | parentSurface = *parent; |
233 | } |
234 | zxdg_surface_v5_set_parent(xdg_surface: xdgsurfacev5, parent: parentSurface); |
235 | } |
236 | |
237 | void XdgShellSurfaceUnstableV5::Private::setTitle(const QString &title) |
238 | { |
239 | zxdg_surface_v5_set_title(xdg_surface: xdgsurfacev5, title: title.toUtf8().constData()); |
240 | } |
241 | |
242 | void XdgShellSurfaceUnstableV5::Private::setAppId(const QByteArray &appId) |
243 | { |
244 | zxdg_surface_v5_set_app_id(xdg_surface: xdgsurfacev5, app_id: appId.constData()); |
245 | } |
246 | |
247 | void XdgShellSurfaceUnstableV5::Private::showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) |
248 | { |
249 | zxdg_surface_v5_show_window_menu(xdg_surface: xdgsurfacev5, seat: *seat, serial, x, y); |
250 | } |
251 | |
252 | void XdgShellSurfaceUnstableV5::Private::move(Seat *seat, quint32 serial) |
253 | { |
254 | zxdg_surface_v5_move(xdg_surface: xdgsurfacev5, seat: *seat, serial); |
255 | } |
256 | |
257 | void XdgShellSurfaceUnstableV5::Private::resize(Seat *seat, quint32 serial, Qt::Edges edges) |
258 | { |
259 | uint wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_NONE; |
260 | if (edges.testFlag(flag: Qt::TopEdge)) { |
261 | if (edges.testFlag(flag: Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) { |
262 | wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_TOP_LEFT; |
263 | } else if (edges.testFlag(flag: Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) { |
264 | wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_TOP_RIGHT; |
265 | } else if ((edges & ~Qt::TopEdge) == Qt::Edges()) { |
266 | wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_TOP; |
267 | } |
268 | } else if (edges.testFlag(flag: Qt::BottomEdge)) { |
269 | if (edges.testFlag(flag: Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) { |
270 | wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_BOTTOM_LEFT; |
271 | } else if (edges.testFlag(flag: Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) { |
272 | wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_BOTTOM_RIGHT; |
273 | } else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) { |
274 | wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_BOTTOM; |
275 | } |
276 | } else if (edges.testFlag(flag: Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) { |
277 | wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_RIGHT; |
278 | } else if (edges.testFlag(flag: Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) { |
279 | wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_LEFT; |
280 | } |
281 | zxdg_surface_v5_resize(xdg_surface: xdgsurfacev5, seat: *seat, serial, edges: wlEdge); |
282 | } |
283 | |
284 | void XdgShellSurfaceUnstableV5::Private::ackConfigure(quint32 serial) |
285 | { |
286 | zxdg_surface_v5_ack_configure(xdg_surface: xdgsurfacev5, serial); |
287 | } |
288 | |
289 | void XdgShellSurfaceUnstableV5::Private::setMaximized() |
290 | { |
291 | zxdg_surface_v5_set_maximized(xdg_surface: xdgsurfacev5); |
292 | } |
293 | |
294 | void XdgShellSurfaceUnstableV5::Private::unsetMaximized() |
295 | { |
296 | zxdg_surface_v5_unset_maximized(xdg_surface: xdgsurfacev5); |
297 | } |
298 | |
299 | void XdgShellSurfaceUnstableV5::Private::setFullscreen(Output *output) |
300 | { |
301 | wl_output *o = nullptr; |
302 | if (output) { |
303 | o = *output; |
304 | } |
305 | zxdg_surface_v5_set_fullscreen(xdg_surface: xdgsurfacev5, output: o); |
306 | } |
307 | |
308 | void XdgShellSurfaceUnstableV5::Private::unsetFullscreen() |
309 | { |
310 | zxdg_surface_v5_unset_fullscreen(xdg_surface: xdgsurfacev5); |
311 | } |
312 | |
313 | void XdgShellSurfaceUnstableV5::Private::setMinimized() |
314 | { |
315 | zxdg_surface_v5_set_minimized(xdg_surface: xdgsurfacev5); |
316 | } |
317 | |
318 | void XdgShellSurfaceUnstableV5::Private::setMaxSize(const QSize &size) |
319 | { |
320 | Q_UNUSED(size) |
321 | // TODO: notify an error? |
322 | } |
323 | |
324 | void XdgShellSurfaceUnstableV5::Private::setMinSize(const QSize &size) |
325 | { |
326 | Q_UNUSED(size) |
327 | // TODO: notify an error? |
328 | } |
329 | |
330 | XdgShellSurfaceUnstableV5::XdgShellSurfaceUnstableV5(QObject *parent) |
331 | : XdgShellSurface(new Private(this), parent) |
332 | { |
333 | } |
334 | |
335 | XdgShellSurfaceUnstableV5::~XdgShellSurfaceUnstableV5() = default; |
336 | |
337 | class XdgShellPopupUnstableV5::Private : public XdgShellPopup::Private |
338 | { |
339 | public: |
340 | Private(XdgShellPopup *q); |
341 | |
342 | void setupV5(xdg_popup *p) override; |
343 | void release() override; |
344 | void destroy() override; |
345 | bool isValid() const override; |
346 | |
347 | using XdgShellPopup::Private::operator xdg_surface *; |
348 | using XdgShellPopup::Private::operator zxdg_popup_v6 *; |
349 | using XdgShellPopup::Private::operator zxdg_surface_v6 *; |
350 | operator xdg_popup *() override |
351 | { |
352 | return xdgpopupv5; |
353 | } |
354 | operator xdg_popup *() const override |
355 | { |
356 | return xdgpopupv5; |
357 | } |
358 | WaylandPointer<xdg_popup, zxdg_popup_v5_destroy> xdgpopupv5; |
359 | |
360 | private: |
361 | static void popupDoneCallback(void *data, xdg_popup *); |
362 | static const struct zxdg_popup_v5_listener s_listener; |
363 | }; |
364 | |
365 | const struct zxdg_popup_v5_listener XdgShellPopupUnstableV5::Private::s_listener = {.popup_done: popupDoneCallback}; |
366 | |
367 | void XdgShellPopupUnstableV5::Private::popupDoneCallback(void *data, xdg_popup *) |
368 | { |
369 | auto s = reinterpret_cast<XdgShellPopupUnstableV5::Private *>(data); |
370 | Q_ASSERT(s->xdgpopupv5 == xdg_popup); |
371 | Q_EMIT s->q->popupDone(); |
372 | } |
373 | |
374 | XdgShellPopupUnstableV5::Private::Private(XdgShellPopup *q) |
375 | : XdgShellPopup::Private(q) |
376 | { |
377 | } |
378 | |
379 | void XdgShellPopupUnstableV5::Private::setupV5(xdg_popup *p) |
380 | { |
381 | Q_ASSERT(p); |
382 | Q_ASSERT(!xdgpopupv5); |
383 | xdgpopupv5.setup(pointer: p); |
384 | zxdg_popup_v5_add_listener(xdg_popup: xdgpopupv5, listener: &s_listener, data: this); |
385 | } |
386 | |
387 | void XdgShellPopupUnstableV5::Private::release() |
388 | { |
389 | xdgpopupv5.release(); |
390 | } |
391 | |
392 | void XdgShellPopupUnstableV5::Private::destroy() |
393 | { |
394 | xdgpopupv5.destroy(); |
395 | } |
396 | |
397 | bool XdgShellPopupUnstableV5::Private::isValid() const |
398 | { |
399 | return xdgpopupv5.isValid(); |
400 | } |
401 | |
402 | XdgShellPopupUnstableV5::XdgShellPopupUnstableV5(QObject *parent) |
403 | : XdgShellPopup(new Private(this), parent) |
404 | { |
405 | } |
406 | |
407 | XdgShellPopupUnstableV5::~XdgShellPopupUnstableV5() = default; |
408 | |
409 | } |
410 | } |
411 | |