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
14namespace KWayland
15{
16namespace Client
17{
18class XdgShellUnstableV5::Private : public XdgShell::Private
19{
20public:
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
45const struct zxdg_shell_v5_listener XdgShellUnstableV5::Private::s_shellListener = {
46 .ping: pingCallback,
47};
48
49void 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
55void 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
64void XdgShellUnstableV5::Private::release()
65{
66 xdgshellv5.release();
67}
68
69void XdgShellUnstableV5::Private::destroy()
70{
71 xdgshellv5.destroy();
72}
73
74bool XdgShellUnstableV5::Private::isValid() const
75{
76 return xdgshellv5.isValid();
77}
78
79XdgShellSurface *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
91XdgShellPopup *
92XdgShellUnstableV5::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
104XdgShellUnstableV5::XdgShellUnstableV5(QObject *parent)
105 : XdgShell(new Private, parent)
106{
107}
108
109XdgShellUnstableV5::~XdgShellUnstableV5() = default;
110
111class XdgShellSurfaceUnstableV5::Private : public XdgShellSurface::Private
112{
113public:
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
149private:
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
156const struct zxdg_surface_v5_listener XdgShellSurfaceUnstableV5::Private::s_listener = {.configure: configureCallback, .close: closeCallback};
157
158void 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
193void 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
200XdgShellSurfaceUnstableV5::Private::Private(XdgShellSurface *q)
201 : XdgShellSurface::Private(q)
202{
203}
204
205void 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
213void XdgShellSurfaceUnstableV5::Private::release()
214{
215 xdgsurfacev5.release();
216}
217
218void XdgShellSurfaceUnstableV5::Private::destroy()
219{
220 xdgsurfacev5.destroy();
221}
222
223bool XdgShellSurfaceUnstableV5::Private::isValid() const
224{
225 return xdgsurfacev5.isValid();
226}
227
228void 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
237void XdgShellSurfaceUnstableV5::Private::setTitle(const QString &title)
238{
239 zxdg_surface_v5_set_title(xdg_surface: xdgsurfacev5, title: title.toUtf8().constData());
240}
241
242void XdgShellSurfaceUnstableV5::Private::setAppId(const QByteArray &appId)
243{
244 zxdg_surface_v5_set_app_id(xdg_surface: xdgsurfacev5, app_id: appId.constData());
245}
246
247void 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
252void XdgShellSurfaceUnstableV5::Private::move(Seat *seat, quint32 serial)
253{
254 zxdg_surface_v5_move(xdg_surface: xdgsurfacev5, seat: *seat, serial);
255}
256
257void 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
284void XdgShellSurfaceUnstableV5::Private::ackConfigure(quint32 serial)
285{
286 zxdg_surface_v5_ack_configure(xdg_surface: xdgsurfacev5, serial);
287}
288
289void XdgShellSurfaceUnstableV5::Private::setMaximized()
290{
291 zxdg_surface_v5_set_maximized(xdg_surface: xdgsurfacev5);
292}
293
294void XdgShellSurfaceUnstableV5::Private::unsetMaximized()
295{
296 zxdg_surface_v5_unset_maximized(xdg_surface: xdgsurfacev5);
297}
298
299void 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
308void XdgShellSurfaceUnstableV5::Private::unsetFullscreen()
309{
310 zxdg_surface_v5_unset_fullscreen(xdg_surface: xdgsurfacev5);
311}
312
313void XdgShellSurfaceUnstableV5::Private::setMinimized()
314{
315 zxdg_surface_v5_set_minimized(xdg_surface: xdgsurfacev5);
316}
317
318void XdgShellSurfaceUnstableV5::Private::setMaxSize(const QSize &size)
319{
320 Q_UNUSED(size)
321 // TODO: notify an error?
322}
323
324void XdgShellSurfaceUnstableV5::Private::setMinSize(const QSize &size)
325{
326 Q_UNUSED(size)
327 // TODO: notify an error?
328}
329
330XdgShellSurfaceUnstableV5::XdgShellSurfaceUnstableV5(QObject *parent)
331 : XdgShellSurface(new Private(this), parent)
332{
333}
334
335XdgShellSurfaceUnstableV5::~XdgShellSurfaceUnstableV5() = default;
336
337class XdgShellPopupUnstableV5::Private : public XdgShellPopup::Private
338{
339public:
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
360private:
361 static void popupDoneCallback(void *data, xdg_popup *xdg_popup);
362 static const struct zxdg_popup_v5_listener s_listener;
363};
364
365const struct zxdg_popup_v5_listener XdgShellPopupUnstableV5::Private::s_listener = {.popup_done: popupDoneCallback};
366
367void XdgShellPopupUnstableV5::Private::popupDoneCallback(void *data, xdg_popup *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
374XdgShellPopupUnstableV5::Private::Private(XdgShellPopup *q)
375 : XdgShellPopup::Private(q)
376{
377}
378
379void 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
387void XdgShellPopupUnstableV5::Private::release()
388{
389 xdgpopupv5.release();
390}
391
392void XdgShellPopupUnstableV5::Private::destroy()
393{
394 xdgpopupv5.destroy();
395}
396
397bool XdgShellPopupUnstableV5::Private::isValid() const
398{
399 return xdgpopupv5.isValid();
400}
401
402XdgShellPopupUnstableV5::XdgShellPopupUnstableV5(QObject *parent)
403 : XdgShellPopup(new Private(this), parent)
404{
405}
406
407XdgShellPopupUnstableV5::~XdgShellPopupUnstableV5() = default;
408
409}
410}
411

source code of kwayland/src/client/xdgshell_v5.cpp