1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include "qwaylandxdgshellv5.h"
31#include "qwaylandxdgshellv5_p.h"
32
33#if QT_CONFIG(wayland_compositor_quick)
34#include "qwaylandxdgshellv5integration_p.h"
35#endif
36#include <QtWaylandCompositor/private/qwaylandutils_p.h>
37
38#include <QtWaylandCompositor/QWaylandCompositor>
39#include <QtWaylandCompositor/QWaylandSurface>
40#include <QtWaylandCompositor/QWaylandSurfaceRole>
41#include <QtWaylandCompositor/QWaylandResource>
42#include <QtWaylandCompositor/QWaylandSeat>
43
44#include <QtCore/QObject>
45
46#include <algorithm>
47
48QT_BEGIN_NAMESPACE
49
50#if QT_DEPRECATED_SINCE(5, 15)
51
52QWaylandSurfaceRole QWaylandXdgSurfaceV5Private::s_role("xdg_surface");
53QWaylandSurfaceRole QWaylandXdgPopupV5Private::s_role("xdg_popup");
54
55QWaylandXdgShellV5Private::QWaylandXdgShellV5Private()
56{
57}
58
59void QWaylandXdgShellV5Private::ping(Resource *resource, uint32_t serial)
60{
61 m_pings.insert(value: serial);
62 send_ping(resource: resource->handle, serial);
63}
64
65void QWaylandXdgShellV5Private::registerSurface(QWaylandXdgSurfaceV5 *xdgSurface)
66{
67 m_xdgSurfaces.insert(akey: xdgSurface->surface()->client()->client(), avalue: xdgSurface);
68}
69
70void QWaylandXdgShellV5Private::unregisterXdgSurface(QWaylandXdgSurfaceV5 *xdgSurface)
71{
72 auto xdgSurfacePrivate = QWaylandXdgSurfaceV5Private::get(xdgSurface);
73 if (!m_xdgSurfaces.remove(key: xdgSurfacePrivate->resource()->client(), value: xdgSurface))
74 qWarning(msg: "%s Unexpected state. Can't find registered xdg surface\n", Q_FUNC_INFO);
75}
76
77void QWaylandXdgShellV5Private::registerXdgPopup(QWaylandXdgPopupV5 *xdgPopup)
78{
79 m_xdgPopups.insert(akey: xdgPopup->surface()->client()->client(), avalue: xdgPopup);
80}
81
82void QWaylandXdgShellV5Private::unregisterXdgPopup(QWaylandXdgPopupV5 *xdgPopup)
83{
84 auto xdgPopupPrivate = QWaylandXdgPopupV5Private::get(xdgPopup);
85 if (!m_xdgPopups.remove(key: xdgPopupPrivate->resource()->client(), value: xdgPopup))
86 qWarning(msg: "%s Unexpected state. Can't find registered xdg popup\n", Q_FUNC_INFO);
87}
88
89bool QWaylandXdgShellV5Private::isValidPopupParent(QWaylandSurface *parentSurface) const
90{
91 QWaylandXdgPopupV5 *topmostPopup = topmostPopupForClient(client: parentSurface->client()->client());
92 if (topmostPopup && topmostPopup->surface() != parentSurface) {
93 return false;
94 }
95
96 QWaylandSurfaceRole *parentRole = parentSurface->role();
97 if (parentRole != QWaylandXdgSurfaceV5::role() && parentRole != QWaylandXdgPopupV5::role()) {
98 return false;
99 }
100
101 return true;
102}
103
104QWaylandXdgPopupV5 *QWaylandXdgShellV5Private::topmostPopupForClient(wl_client *client) const
105{
106 QList<QWaylandXdgPopupV5 *> clientPopups = m_xdgPopups.values(akey: client);
107 return clientPopups.empty() ? nullptr : clientPopups.last();
108}
109
110QWaylandXdgSurfaceV5 *QWaylandXdgShellV5Private::xdgSurfaceFromSurface(QWaylandSurface *surface) const
111{
112 for (QWaylandXdgSurfaceV5 *xdgSurface : m_xdgSurfaces) {
113 if (surface == xdgSurface->surface())
114 return xdgSurface;
115 }
116 return nullptr;
117}
118
119void QWaylandXdgShellV5Private::xdg_shell_destroy(Resource *resource)
120{
121 if (!m_xdgSurfaces.values(akey: resource->client()).empty())
122 wl_resource_post_error(resource: resource->handle, code: XDG_SHELL_ERROR_DEFUNCT_SURFACES,
123 msg: "xdg_shell was destroyed before children");
124
125 wl_resource_destroy(resource: resource->handle);
126}
127
128void QWaylandXdgShellV5Private::xdg_shell_get_xdg_surface(Resource *resource, uint32_t id,
129 wl_resource *surface_res)
130{
131 Q_Q(QWaylandXdgShellV5);
132 QWaylandSurface *surface = QWaylandSurface::fromResource(resource: surface_res);
133
134 if (xdgSurfaceFromSurface(surface)) {
135 wl_resource_post_error(resource: resource->handle, code: XDG_SHELL_ERROR_ROLE,
136 msg: "An active xdg_surface already exists for wl_surface@%d",
137 wl_resource_get_id(resource: surface->resource()));
138 return;
139 }
140
141 if (!surface->setRole(role: QWaylandXdgSurfaceV5::role(), errorResource: resource->handle, errorCode: XDG_SHELL_ERROR_ROLE))
142 return;
143
144 QWaylandResource xdgSurfaceResource(wl_resource_create(client: resource->client(), interface: &xdg_surface_v5_interface,
145 version: wl_resource_get_version(resource: resource->handle), id));
146
147 emit q->xdgSurfaceRequested(surface, resource: xdgSurfaceResource);
148
149 QWaylandXdgSurfaceV5 *xdgSurface = QWaylandXdgSurfaceV5::fromResource(resource: xdgSurfaceResource.resource());
150 if (!xdgSurface) {
151 // A QWaylandXdgSurfaceV5 was not created in response to the xdgSurfaceRequested signal, so we
152 // create one as fallback here instead.
153 xdgSurface = new QWaylandXdgSurfaceV5(q, surface, xdgSurfaceResource);
154 }
155
156 registerSurface(xdgSurface);
157 emit q->xdgSurfaceCreated(xdgSurface);
158}
159
160void QWaylandXdgShellV5Private::xdg_shell_use_unstable_version(Resource *resource, int32_t version)
161{
162 if (xdg_shell_v5::version_current != version) {
163 wl_resource_post_error(resource: resource->handle, code: WL_DISPLAY_ERROR_INVALID_OBJECT,
164 msg: "incompatible version, server is %d, but client wants %d",
165 xdg_shell_v5::version_current, version);
166 }
167}
168
169void QWaylandXdgShellV5Private::xdg_shell_get_xdg_popup(Resource *resource, uint32_t id,
170 wl_resource *surface_res, wl_resource *parent,
171 wl_resource *seatResource, uint32_t serial,
172 int32_t x, int32_t y)
173{
174 Q_UNUSED(serial);
175 Q_Q(QWaylandXdgShellV5);
176 QWaylandSurface *surface = QWaylandSurface::fromResource(resource: surface_res);
177 QWaylandSurface *parentSurface = QWaylandSurface::fromResource(resource: parent);
178
179 if (!isValidPopupParent(parentSurface)) {
180 wl_resource_post_error(resource: resource->handle, code: XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
181 msg: "the client specified an invalid popup parent surface");
182 return;
183 }
184
185 if (!surface->setRole(role: QWaylandXdgPopupV5::role(), errorResource: resource->handle, errorCode: XDG_SHELL_ERROR_ROLE)) {
186 return;
187 }
188
189 QWaylandResource xdgPopupResource (wl_resource_create(client: resource->client(), interface: &xdg_popup_v5_interface,
190 version: wl_resource_get_version(resource: resource->handle), id));
191 QWaylandSeat *seat = QWaylandSeat::fromSeatResource(resource: seatResource);
192 QPoint position(x, y);
193 emit q->xdgPopupRequested(surface, parent: parentSurface, seat, position, resource: xdgPopupResource);
194
195 QWaylandXdgPopupV5 *xdgPopup = QWaylandXdgPopupV5::fromResource(resource: xdgPopupResource.resource());
196 if (!xdgPopup) {
197 // A QWaylandXdgPopupV5 was not created in response to the xdgPopupRequested signal, so we
198 // create one as fallback here instead.
199 xdgPopup = new QWaylandXdgPopupV5(q, surface, parentSurface, position, xdgPopupResource);
200 }
201
202 registerXdgPopup(xdgPopup);
203 emit q->xdgPopupCreated(xdgPopup);
204}
205
206void QWaylandXdgShellV5Private::xdg_shell_pong(Resource *resource, uint32_t serial)
207{
208 Q_UNUSED(resource);
209 Q_Q(QWaylandXdgShellV5);
210 if (m_pings.remove(value: serial))
211 emit q->pong(serial);
212 else
213 qWarning(msg: "Received an unexpected pong!");
214}
215
216QWaylandXdgSurfaceV5Private::QWaylandXdgSurfaceV5Private()
217 : m_lastAckedConfigure({.states: {}, .size: QSize(0, 0), .serial: 0})
218{
219}
220
221void QWaylandXdgSurfaceV5Private::handleFocusLost()
222{
223 Q_Q(QWaylandXdgSurfaceV5);
224 QWaylandXdgSurfaceV5Private::ConfigureEvent current = lastSentConfigure();
225 current.states.removeOne(t: QWaylandXdgSurfaceV5::State::ActivatedState);
226 q->sendConfigure(size: current.size, states: current.states);
227}
228
229void QWaylandXdgSurfaceV5Private::handleFocusReceived()
230{
231 Q_Q(QWaylandXdgSurfaceV5);
232
233 QWaylandXdgSurfaceV5Private::ConfigureEvent current = lastSentConfigure();
234 if (!current.states.contains(t: QWaylandXdgSurfaceV5::State::ActivatedState)) {
235 current.states.push_back(t: QWaylandXdgSurfaceV5::State::ActivatedState);
236 }
237
238 q->sendConfigure(size: current.size, states: current.states);
239}
240
241QRect QWaylandXdgSurfaceV5Private::calculateFallbackWindowGeometry() const
242{
243 // TODO: The unset window geometry should include subsurfaces as well, so this solution
244 // won't work too well on those kinds of clients.
245 return QRect(QPoint(), m_surface->destinationSize());
246}
247
248void QWaylandXdgSurfaceV5Private::updateFallbackWindowGeometry()
249{
250 Q_Q(QWaylandXdgSurfaceV5);
251 if (!m_unsetWindowGeometry)
252 return;
253
254 const QRect unsetGeometry = calculateFallbackWindowGeometry();
255 if (unsetGeometry == m_windowGeometry)
256 return;
257
258 m_windowGeometry = unsetGeometry;
259 emit q->windowGeometryChanged();
260}
261
262void QWaylandXdgSurfaceV5Private::setWindowType(Qt::WindowType windowType)
263{
264 if (m_windowType == windowType)
265 return;
266
267 m_windowType = windowType;
268
269 Q_Q(QWaylandXdgSurfaceV5);
270 emit q->windowTypeChanged();
271}
272
273void QWaylandXdgSurfaceV5Private::xdg_surface_destroy_resource(Resource *resource)
274{
275 Q_UNUSED(resource);
276 Q_Q(QWaylandXdgSurfaceV5);
277 QWaylandXdgShellV5Private::get(xdgShell: m_xdgShell)->unregisterXdgSurface(xdgSurface: q);
278 delete q;
279}
280
281void QWaylandXdgSurfaceV5Private::xdg_surface_destroy(Resource *resource)
282{
283 wl_resource_destroy(resource: resource->handle);
284}
285
286void QWaylandXdgSurfaceV5Private::xdg_surface_move(Resource *resource, wl_resource *seat, uint32_t serial)
287{
288 Q_UNUSED(resource);
289 Q_UNUSED(serial);
290
291 Q_Q(QWaylandXdgSurfaceV5);
292 QWaylandSeat *input_device = QWaylandSeat::fromSeatResource(resource: seat);
293 emit q->startMove(seat: input_device);
294}
295
296void QWaylandXdgSurfaceV5Private::xdg_surface_resize(Resource *resource, wl_resource *seat,
297 uint32_t serial, uint32_t edges)
298{
299 Q_UNUSED(resource);
300 Q_UNUSED(serial);
301
302 Q_Q(QWaylandXdgSurfaceV5);
303 QWaylandSeat *input_device = QWaylandSeat::fromSeatResource(resource: seat);
304 emit q->startResize(seat: input_device, edges: QWaylandXdgSurfaceV5::ResizeEdge(edges));
305}
306
307void QWaylandXdgSurfaceV5Private::xdg_surface_set_maximized(Resource *resource)
308{
309 Q_UNUSED(resource);
310 Q_Q(QWaylandXdgSurfaceV5);
311 emit q->setMaximized();
312}
313
314void QWaylandXdgSurfaceV5Private::xdg_surface_unset_maximized(Resource *resource)
315{
316 Q_UNUSED(resource);
317 Q_Q(QWaylandXdgSurfaceV5);
318 emit q->unsetMaximized();
319}
320
321void QWaylandXdgSurfaceV5Private::xdg_surface_set_fullscreen(Resource *resource, wl_resource *output_res)
322{
323 Q_UNUSED(resource);
324 Q_Q(QWaylandXdgSurfaceV5);
325 QWaylandOutput *output = output_res ? QWaylandOutput::fromResource(resource: output_res) : nullptr;
326 emit q->setFullscreen(output);
327}
328
329void QWaylandXdgSurfaceV5Private::xdg_surface_unset_fullscreen(Resource *resource)
330{
331 Q_UNUSED(resource);
332 Q_Q(QWaylandXdgSurfaceV5);
333 emit q->unsetFullscreen();
334}
335
336void QWaylandXdgSurfaceV5Private::xdg_surface_set_minimized(Resource *resource)
337{
338 Q_UNUSED(resource);
339 Q_Q(QWaylandXdgSurfaceV5);
340 emit q->setMinimized();
341}
342
343void QWaylandXdgSurfaceV5Private::xdg_surface_set_parent(Resource *resource, wl_resource *parent)
344{
345 Q_UNUSED(resource);
346 QWaylandXdgSurfaceV5 *parentSurface = nullptr;
347 if (parent) {
348 parentSurface = static_cast<QWaylandXdgSurfaceV5Private *>(
349 QWaylandXdgSurfaceV5Private::Resource::fromResource(resource: parent)->xdg_surface_object)->q_func();
350 }
351
352 Q_Q(QWaylandXdgSurfaceV5);
353
354 if (m_parentSurface != parentSurface) {
355 m_parentSurface = parentSurface;
356 emit q->parentSurfaceChanged();
357 }
358
359 if (m_parentSurface && m_windowType != Qt::WindowType::SubWindow) {
360 // There's a parent now, which means the surface is transient
361 setWindowType(Qt::WindowType::SubWindow);
362 emit q->setTransient();
363 } else if (!m_parentSurface && m_windowType != Qt::WindowType::Window) {
364 // When the surface has no parent it is toplevel
365 setWindowType(Qt::WindowType::Window);
366 emit q->setTopLevel();
367 }
368}
369
370void QWaylandXdgSurfaceV5Private::xdg_surface_set_app_id(Resource *resource, const QString &app_id)
371{
372 Q_UNUSED(resource);
373 if (app_id == m_appId)
374 return;
375 Q_Q(QWaylandXdgSurfaceV5);
376 m_appId = app_id;
377 emit q->appIdChanged();
378}
379
380void QWaylandXdgSurfaceV5Private::xdg_surface_show_window_menu(Resource *resource, wl_resource *seatResource,
381 uint32_t serial, int32_t x, int32_t y)
382{
383 Q_UNUSED(resource);
384 Q_UNUSED(serial);
385 QPoint position(x, y);
386 auto seat = QWaylandSeat::fromSeatResource(resource: seatResource);
387 Q_Q(QWaylandXdgSurfaceV5);
388 emit q->showWindowMenu(seat, localSurfacePosition: position);
389}
390
391void QWaylandXdgSurfaceV5Private::xdg_surface_ack_configure(Resource *resource, uint32_t serial)
392{
393 Q_UNUSED(resource);
394 Q_Q(QWaylandXdgSurfaceV5);
395
396 ConfigureEvent config;
397 Q_FOREVER {
398 if (m_pendingConfigures.empty()) {
399 qWarning(msg: "Received an unexpected ack_configure!");
400 return;
401 }
402
403 config = m_pendingConfigures.takeFirst();
404
405 if (config.serial == serial)
406 break;
407 }
408
409 std::vector<uint> changedStates;
410 std::set_symmetric_difference(
411 first1: m_lastAckedConfigure.states.begin(), last1: m_lastAckedConfigure.states.end(),
412 first2: config.states.begin(), last2: config.states.end(),
413 result: std::back_inserter(x&: changedStates));
414
415 m_lastAckedConfigure = config;
416
417 if (!changedStates.empty()) {
418 for (uint state : changedStates) {
419 switch (state) {
420 case QWaylandXdgSurfaceV5::State::MaximizedState:
421 emit q->maximizedChanged();
422 break;
423 case QWaylandXdgSurfaceV5::State::FullscreenState:
424 emit q->fullscreenChanged();
425 break;
426 case QWaylandXdgSurfaceV5::State::ResizingState:
427 emit q->resizingChanged();
428 break;
429 case QWaylandXdgSurfaceV5::State::ActivatedState:
430 emit q->activatedChanged();
431 break;
432 }
433 }
434 emit q->statesChanged();
435 }
436
437 emit q->ackConfigure(serial);
438}
439
440void QWaylandXdgSurfaceV5Private::xdg_surface_set_title(Resource *resource, const QString &title)
441{
442 Q_UNUSED(resource);
443 if (title == m_title)
444 return;
445 Q_Q(QWaylandXdgSurfaceV5);
446 m_title = title;
447 emit q->titleChanged();
448}
449
450void QWaylandXdgSurfaceV5Private::xdg_surface_set_window_geometry(Resource *resource,
451 int32_t x, int32_t y,
452 int32_t width, int32_t height)
453{
454 Q_UNUSED(resource);
455
456 if (width <= 0 || height <= 0) {
457 qWarning() << "Invalid (non-positive) dimensions received in set_window_geometry";
458 return;
459 }
460
461 m_unsetWindowGeometry = false;
462
463 QRect geometry(x, y, width, height);
464
465 Q_Q(QWaylandXdgSurfaceV5);
466 if ((q->maximized() || q->fullscreen()) && m_lastAckedConfigure.size != geometry.size())
467 qWarning() << "Client window geometry did not obey last acked configure";
468
469 if (geometry == m_windowGeometry)
470 return;
471
472 m_windowGeometry = geometry;
473 emit q->windowGeometryChanged();
474}
475
476QWaylandXdgPopupV5Private::QWaylandXdgPopupV5Private()
477{
478}
479
480void QWaylandXdgPopupV5Private::xdg_popup_destroy_resource(Resource *resource)
481{
482 Q_UNUSED(resource);
483 Q_Q(QWaylandXdgPopupV5);
484 QWaylandXdgShellV5Private::get(xdgShell: m_xdgShell)->unregisterXdgPopup(xdgPopup: q);
485 delete q;
486}
487
488void QWaylandXdgPopupV5Private::xdg_popup_destroy(Resource *resource)
489{
490 //TODO: post error if not topmost popup
491 wl_resource_destroy(resource: resource->handle);
492}
493
494/*!
495 * \qmltype XdgShellV5
496 * \inqmlmodule QtWayland.Compositor
497 * \since 5.8
498 * \obsolete
499 * \brief Provides an extension for desktop-style user interfaces.
500 *
501 * The XdgShellV5 extension provides a way to associate an XdgSurfaceV5
502 * with a regular Wayland surface. Using the xdg_surface interface, the client
503 * can request that the surface is resized, moved, and so on.
504 *
505 * XdgShellV5 corresponds to the Wayland interface \c xdg_shell.
506 *
507 * To provide the functionality of the shell extension in a compositor, create
508 * an instance of the XdgShellV5 component and add it as a child of the
509 * compositor:
510 *
511 * \qml \QtMinorVersion
512 * import QtWayland.Compositor 1.\1
513 *
514 * WaylandCompositor {
515 * XdgShellV5 {
516 * // ...
517 * }
518 * }
519 * \endqml
520 *
521 * \deprecated
522 */
523
524/*!
525 * \class QWaylandXdgShellV5
526 * \inmodule QtWaylandCompositor
527 * \since 5.8
528 * \obsolete
529 * \brief The QWaylandXdgShellV5 class is an extension for desktop-style user interfaces.
530 *
531 * The QWaylandXdgShellV5 extension provides a way to associate a QWaylandXdgSurfaceV5 with
532 * a regular Wayland surface. Using the xdg_surface interface, the client
533 * can request that the surface is resized, moved, and so on.
534 *
535 * QWaylandXdgShellV5 corresponds to the Wayland interface \c xdg_shell.
536 *
537 * \deprecated
538 */
539
540/*!
541 * Constructs a QWaylandXdgShellV5 object.
542 */
543QWaylandXdgShellV5::QWaylandXdgShellV5()
544 : QWaylandShellTemplate<QWaylandXdgShellV5>(*new QWaylandXdgShellV5Private())
545{ }
546
547/*!
548 * Constructs a QWaylandXdgShellV5 object for the provided \a compositor.
549 */
550QWaylandXdgShellV5::QWaylandXdgShellV5(QWaylandCompositor *compositor)
551 : QWaylandShellTemplate<QWaylandXdgShellV5>(compositor, *new QWaylandXdgShellV5Private())
552{ }
553
554/*!
555 * Initializes the shell extension.
556 */
557void QWaylandXdgShellV5::initialize()
558{
559 Q_D(QWaylandXdgShellV5);
560 QWaylandShellTemplate::initialize();
561 QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
562 if (!compositor) {
563 qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandXdgShellV5";
564 return;
565 }
566 d->init(display: compositor->display(), version: 1);
567
568 handleSeatChanged(newSeat: compositor->defaultSeat(), oldSeat: nullptr);
569
570 connect(sender: compositor, signal: &QWaylandCompositor::defaultSeatChanged,
571 receiver: this, slot: &QWaylandXdgShellV5::handleSeatChanged);
572}
573
574QWaylandClient *QWaylandXdgShellV5::popupClient() const
575{
576 Q_D(const QWaylandXdgShellV5);
577 for (QWaylandXdgPopupV5 *popup : d->m_xdgPopups) {
578 if (popup->surface()->hasContent())
579 return popup->surface()->client();
580 }
581 return nullptr;
582}
583
584/*!
585 * Returns the Wayland interface for the QWaylandXdgShellV5.
586 */
587const struct wl_interface *QWaylandXdgShellV5::interface()
588{
589 return QWaylandXdgShellV5Private::interface();
590}
591
592QByteArray QWaylandXdgShellV5::interfaceName()
593{
594 return QWaylandXdgShellV5Private::interfaceName();
595}
596
597/*!
598 * \qmlmethod void QtWaylandCompositor::XdgShellV5::ping(WaylandClient client)
599 *
600 * Sends a ping event to the \a client. If the client replies to the event, the
601 * pong signal will be emitted.
602 */
603
604/*!
605 * Sends a ping event to the \a client. If the client replies to the event, the
606 * pong signal will be emitted.
607 */
608uint QWaylandXdgShellV5::ping(QWaylandClient *client)
609{
610 Q_D(QWaylandXdgShellV5);
611
612 QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
613 Q_ASSERT(compositor);
614
615 uint32_t serial = compositor->nextSerial();
616
617 QWaylandXdgShellV5Private::Resource *clientResource = d->resourceMap().value(akey: client->client(), adefaultValue: nullptr);
618 Q_ASSERT(clientResource);
619
620 d->ping(resource: clientResource, serial);
621 return serial;
622}
623
624// ### remove once QMap has rbegin()/rend()
625template <typename Iterator>
626std::reverse_iterator<Iterator> make_reverse(Iterator it)
627{
628 return std::reverse_iterator<Iterator>(std::move(it));
629}
630
631void QWaylandXdgShellV5::closeAllPopups()
632{
633 Q_D(QWaylandXdgShellV5);
634 // Close pop-ups from top-most to bottom-most, lest we get protocol errors:
635 for (auto rit = make_reverse(it: d->m_xdgPopups.end()), rend = make_reverse(it: d->m_xdgPopups.begin()); rit != rend; ++rit) {
636 (*rit)->sendPopupDone();
637 }
638}
639
640/*!
641 * \qmlsignal void QtWaylandCompositor::XdgShellV5::xdgSurfaceRequested(WaylandSurface surface, WaylandResource resource)
642 *
643 * This signal is emitted when the client has requested an \c xdg_surface to be associated
644 * with \a surface. The handler for this signal may create the shell surface for \a resource
645 * and initialize it within the scope of the signal emission. Otherwise an XdgSurfaceV5 will
646 * be created automatically.
647 */
648
649/*!
650 * \fn void QWaylandXdgShellV5::xdgSurfaceRequested(QWaylandSurface *surface, const QWaylandResource &resource)
651 *
652 * This signal is emitted when the client has requested an \c xdg_surface to be associated
653 * with \a surface. The handler for this signal may create the shell surface for \a resource
654 * and initialize it within the scope of the signal emission. Otherwise a QWaylandXdgSurfaceV5
655 * will be created automatically.
656 */
657
658/*!
659 * \qmlsignal void QtWaylandCompositor::XdgShellV5::xdgSurfaceCreated(XdgSurfaceV5 xdgSurface)
660 *
661 * This signal is emitted when the client has created an \c xdg_surface.
662 * A common use case is to let the handler of this signal instantiate a ShellSurfaceItem or
663 * WaylandQuickItem for displaying \a xdgSurface in a QtQuick scene.
664 */
665
666/*!
667 * \fn void QWaylandXdgShellV5::xdgSurfaceCreated(QWaylandXdgSurfaceV5 *xdgSurface)
668 *
669 * This signal is emitted when the client has created an \c xdg_surface.
670 * A common use case is to let the handler of this signal instantiate a QWaylandShellSurfaceItem or
671 * QWaylandQuickItem for displaying \a xdgSurface in a QtQuick scene.
672 */
673
674/*!
675 * \qmlsignal void QtWaylandCompositor::XdgShellV5::xdgPopupRequested(WaylandSurface surface, WaylandSurface parent, WaylandSeat seat, point position, WaylandResource resource)
676 *
677 * This signal is emitted when the client has requested an \c xdg_popup to be associated
678 * with \a surface. The handler for this signal may create the xdg popup for \a resource and
679 * initialize it within the scope of the signal emission. Otherwise an XdgPopupV5 will be
680 * created automatically.
681 *
682 * The \a seat is the \c wl_seat that caused the popup to be opened.
683 *
684 * \a position is the desired position of the popup, relative to the \a parent.
685 */
686
687/*!
688 * \fn void QWaylandXdgShellV5::xdgPopupRequested(QWaylandSurface *surface, QWaylandSurface *parent, QWaylandSeat *seat, const QPoint &position, const QWaylandResource &resource)
689 *
690 * This signal is emitted when the client has requested an \c xdg_surface to be associated
691 * with \a surface. The handler for this signal may create the xdg poup for \a resource and
692 * initialize it within the scope of the signal emission. Otherwise a QWaylandXdgPopupV5 will be
693 * created automatically.
694 *
695 * The \a seat is the \c wl_seat that caused the popup to be opened.
696 *
697 * \a position is the desired position of the popup, relative to the \a parent.
698 */
699
700/*!
701 * \qmlsignal void QtWaylandCompositor::XdgShellV5::xdgPopupCreated(XdgPopupV5 xdgPopup)
702 *
703 * This signal is emitted when the client has created an \c xdg_popup.
704 * A common use case is to let the handler of this signal instantiate a ShellSurfaceItem or
705 * WaylandQuickItem for displaying \a xdgPopup in a QtQuick scene.
706 */
707
708/*!
709 * \fn void QWaylandXdgShellV5::xdgPopupCreated(QWaylandXdgPopupV5 *xdgPopup)
710 *
711 * This signal is emitted when the client has created an \c xdg_popup.
712 * A common use case is to let the handler of this signal instantiate a QWaylandShellSurfaceItem or
713 * QWaylandQuickItem for displaying \a xdgPopup in a QtQuick scene.
714 */
715
716/*!
717 * \qmlsignal void QtWaylandCompositor::XdgShellV5::pong(int serial)
718 *
719 * This signal is emitted when the client has responded to a ping event with serial \a serial.
720 *
721 * \sa QtWaylandCompositor::XdgShellV5::ping()
722 */
723
724/*!
725 * \fn void QWaylandXdgShellV5::pong(uint serial)
726 *
727 * This signal is emitted when the client has responded to a ping event with serial \a serial.
728 *
729 * \sa QWaylandXdgShellV5::ping()
730 */
731
732void QWaylandXdgShellV5::handleSeatChanged(QWaylandSeat *newSeat, QWaylandSeat *oldSeat)
733{
734 if (oldSeat != nullptr) {
735 disconnect(sender: oldSeat, signal: &QWaylandSeat::keyboardFocusChanged,
736 receiver: this, slot: &QWaylandXdgShellV5::handleFocusChanged);
737 }
738
739 if (newSeat != nullptr) {
740 connect(sender: newSeat, signal: &QWaylandSeat::keyboardFocusChanged,
741 receiver: this, slot: &QWaylandXdgShellV5::handleFocusChanged);
742 }
743}
744
745void QWaylandXdgShellV5::handleFocusChanged(QWaylandSurface *newSurface, QWaylandSurface *oldSurface)
746{
747 Q_D(QWaylandXdgShellV5);
748
749 QWaylandXdgSurfaceV5 *newXdgSurface = d->xdgSurfaceFromSurface(surface: newSurface);
750 QWaylandXdgSurfaceV5 *oldXdgSurface = d->xdgSurfaceFromSurface(surface: oldSurface);
751
752 if (newXdgSurface)
753 QWaylandXdgSurfaceV5Private::get(xdgSurface: newXdgSurface)->handleFocusReceived();
754
755 if (oldXdgSurface)
756 QWaylandXdgSurfaceV5Private::get(xdgSurface: oldXdgSurface)->handleFocusLost();
757}
758
759/*!
760 * \qmltype XdgSurfaceV5
761 * \inqmlmodule QtWayland.Compositor
762 * \since 5.8
763 * \obsolete
764 * \brief Provides a \c xdg_surface that offers desktop-style compositor-specific features to a surface.
765 *
766 * This type is part of the \l{XdgShellV5} extension and provides a way to extend
767 * the functionality of an existing WaylandSurface with features specific to desktop-style
768 * compositors, such as resizing and moving the surface.
769 *
770 * It corresponds to the Wayland interface \c xdg_surface for the unstable xdg-shell protocol v5.
771 *
772 * \deprecated
773 */
774
775/*!
776 * \class QWaylandXdgSurfaceV5
777 * \inmodule QtWaylandCompositor
778 * \since 5.8
779 * \obsolete
780 * \brief The QWaylandXdgSurfaceV5 class provides desktop-style compositor-specific features to an xdg surface.
781 *
782 * This class is part of the QWaylandXdgShellV5 extension and provides a way to
783 * extend the functionality of an existing QWaylandSurface with features
784 * specific to desktop-style compositors, such as resizing and moving the
785 * surface.
786 *
787 * It corresponds to the Wayland interface xdg_surface.
788 *
789 * \deprecated
790 */
791
792/*!
793 \enum QWaylandXdgSurfaceV5::ResizeEdge
794
795 \value NoneEdge
796 No edge defined.
797 \value TopEdge
798 Top egde.
799 \value BottomEdge
800 Bottom edge.
801 \value LeftEdge
802 Left edge.
803 \value TopLeftEdge
804 Top-left edge.
805 \value BottomLeftEdge
806 Bottom-left edge.
807 \value RightEdge
808 Right edge.
809 \value TopRightEdge
810 Top-right edge.
811 \value BottomRightEdge
812 Bottom-right edge.
813 */
814
815/*!
816 * \fn QWaylandXdgSurfaceV5::setTopLevel()
817 *
818 * This signal is emitted when the parent surface is unset, effectively
819 * making the window top level.
820 */
821
822/*!
823 * \qmlsignal QtWaylandCompositor::XdgSurfaceV5::setTopLevel()
824 *
825 * This signal is emitted when the parent surface is unset, effectively
826 * making the window top level.
827 */
828
829/*!
830 * \fn QWaylandXdgSurfaceV5::setTransient()
831 *
832 * This signal is emitted when the parent surface is set, effectively
833 * making the window transient.
834 */
835
836/*!
837 * \qmlsignal QtWaylandCompositor::XdgSurfaceV5::setTransient()
838 *
839 * This signal is emitted when the parent surface is set, effectively
840 * making the window transient.
841 */
842
843/*!
844 * Constructs a QWaylandXdgSurfaceV5.
845 */
846QWaylandXdgSurfaceV5::QWaylandXdgSurfaceV5()
847 : QWaylandShellSurfaceTemplate<QWaylandXdgSurfaceV5>(*new QWaylandXdgSurfaceV5Private)
848{
849}
850
851/*!
852 * Constructs a QWaylandXdgSurfaceV5 for \a surface and initializes it with the
853 * given \a xdgShell, \a surface, and resource \a res.
854 */
855QWaylandXdgSurfaceV5::QWaylandXdgSurfaceV5(QWaylandXdgShellV5 *xdgShell, QWaylandSurface *surface, const QWaylandResource &res)
856 : QWaylandShellSurfaceTemplate<QWaylandXdgSurfaceV5>(*new QWaylandXdgSurfaceV5Private)
857{
858 initialize(xdgShell, surface, resource: res);
859}
860
861/*!
862 * \qmlmethod void QtWaylandCompositor::XdgSurfaceV5::initialize(XdgShellV5 xdgShell, WaylandSurface surface, WaylandResource resource)
863 *
864 * Initializes the XdgSurfaceV5, associating it with the given \a xdgShell, \a surface,
865 * and \a resource.
866 */
867
868/*!
869 * Initializes the QWaylandXdgSurfaceV5, associating it with the given \a xdgShell, \a surface
870 * and \a resource.
871 */
872void QWaylandXdgSurfaceV5::initialize(QWaylandXdgShellV5 *xdgShell, QWaylandSurface *surface, const QWaylandResource &resource)
873{
874 Q_D(QWaylandXdgSurfaceV5);
875 d->m_xdgShell = xdgShell;
876 d->m_surface = surface;
877 d->init(resource: resource.resource());
878 setExtensionContainer(surface);
879 d->m_windowGeometry = d->calculateFallbackWindowGeometry();
880 connect(sender: surface, signal: &QWaylandSurface::destinationSizeChanged, receiver: this, slot: &QWaylandXdgSurfaceV5::handleSurfaceSizeChanged);
881 connect(sender: surface, signal: &QWaylandSurface::bufferScaleChanged, receiver: this, slot: &QWaylandXdgSurfaceV5::handleBufferScaleChanged);
882 emit shellChanged();
883 emit surfaceChanged();
884 emit windowGeometryChanged();
885 QWaylandCompositorExtension::initialize();
886}
887
888/*!
889 * \qmlsignal void QtWaylandCompositor::XdgSurfaceV5::showWindowMenu(WaylandSeat seat, point localSurfacePosition)
890 *
891 * This signal is emitted when the client wants to show a context menu at \a localSurfacePosition,
892 * using the Wayland seat \a seat. It's typically emitted in response to the user right-clicking
893 * the window decorations.
894 */
895
896/*!
897 * \fn void QWaylandXdgSurfaceV5::showWindowMenu(QWaylandSeat *seat, const QPoint &localSurfacePosition)
898 *
899 * This signal is emitted when the client wants to show a context menu at \a localSurfacePosition,
900 * using the Wayland seat \a seat. It's typically emitted in response to the user right-clicking
901 * the window decorations.
902 */
903
904/*!
905 * \qmlsignal void QtWaylandCompositor::XdgSurfaceV5::startMove(WaylandSeat seat)
906 *
907 * This signal is emitted when the client wants to start an interactive move of the XdgSurfaceV5,
908 * typically in response to the window decorations being dragged by \a seat.
909 */
910
911/*!
912 * \fn void QWaylandXdgSurfaceV5::startMove(QWaylandSeat *seat)
913 *
914 * This signal is emitted when the client wants to start an interactive move of the
915 * QWaylandXdgSurfaceV5, typically in response to the window decorations being dragged by \a seat.
916 */
917
918/*!
919 * \qmlsignal void QtWaylandCompositor::XdgSurfaceV5::startResize(WaylandSeat seat, enumeration edges)
920 *
921 * This signal is emitted when the client wants to start an interactive resize of the XdgSurfaceV5,
922 * typically in response to the window decorations being dragged by \a seat on the window borders
923 * given by \a edges.
924 *
925 * \sa QWaylandXdgSurfaceV5::ResizeEdge
926 */
927
928/*!
929 * \fn void QWaylandXdgSurfaceV5::startResize(QWaylandSeat *seat, ResizeEdge edges)
930 *
931 * This signal is emitted when the client wants to start an interactive resize of the
932 * QWaylandXdgSurfaceV5, typically in response to the window decorations being dragged by
933 * \a seat on the window borders given by \a edges.
934 */
935
936/*!
937 * \qmlsignal void QtWaylandCompositor::XdgSurfaceV5::setMaximized()
938 *
939 * This signal is emitted when the client wants the \c xdg_surface to be maximized.
940 */
941
942/*!
943 * \fn void QWaylandXdgSurfaceV5::setMaximized()
944 *
945 * This signal is emitted when the client wants the \c xdg_surface to be maximized.
946 */
947
948/*!
949 * \qmlsignal void QtWaylandCompositor::XdgSurfaceV5::unsetMaximized()
950 *
951 * This signal is emitted when the client doesn't want the \c xdg_surface to be maximized anymore.
952 */
953
954/*!
955 * \fn void QWaylandXdgSurfaceV5::unsetMaximized()
956 *
957 * This signal is emitted when the client doesn't want the \c xdg_surface to be maximized anymore.
958 */
959
960/*!
961 * \qmlsignal void QtWaylandCompositor::XdgSurfaceV5::setFullscreen(WaylandOutput output)
962 *
963 * This signal is emitted when the client wants the \c xdg_surface to be in full screen mode.
964 * The client may specify an \a output it wishes the \c xdg_surface to be shown on.
965 */
966
967/*!
968 * \fn void QWaylandXdgSurfaceV5::setFullscreen(QWaylandOutput *output)
969 *
970 * This signal is emitted when the client wants the \c xdg_surface to be in full screen mode.
971 * The client may specify an \a output it wishes the \c xdg_surface to be shown on.
972 */
973
974/*!
975 * \qmlsignal void QtWaylandCompositor::XdgSurfaceV5::unsetFullscreen()
976 *
977 * This signal is emitted when the client doesn't want the \c xdg_surface to be in full screen mode
978 * anymore.
979 */
980
981/*!
982 * \fn void QWaylandXdgSurfaceV5::unsetFullscreen()
983 *
984 * This signal is emitted when the client doesn't want the \c xdg_surface to be in full screen mode
985 * anymore.
986 */
987
988/*!
989 * \qmlsignal void QtWaylandCompositor::XdgSurfaceV5::setMinimized()
990 *
991 * This signal is emitted when the client wants the \c xdg_surface to be minimized.
992 */
993
994/*!
995 * \fn void QWaylandXdgSurfaceV5::setMinimized()
996 *
997 * This signal is emitted when the client wants the \c xdg_surface to be minimized.
998 */
999
1000/*!
1001 * \qmlsignal void QtWaylandCompositor::XdgSurfaceV5::ackConfigure(int serial)
1002 *
1003 * This signal is emitted when the client has received configure events up to and including the
1004 * configure event with serial \a serial and will draw its surface accordingly in the next committed
1005 * buffer.
1006 */
1007
1008/*!
1009 * \fn void QWaylandXdgSurfaceV5::ackConfigure(uint serial)
1010 *
1011 * This signal is emitted when the client has received configure events up to and including the
1012 * configure event with serial \a serial and will draw its surface accordingly in the next committed
1013 * buffer.
1014 */
1015
1016/*!
1017 * \internal
1018 */
1019void QWaylandXdgSurfaceV5::initialize()
1020{
1021 QWaylandCompositorExtension::initialize();
1022}
1023
1024QList<int> QWaylandXdgSurfaceV5::statesAsInts() const
1025{
1026 QList<int> list;
1027 const auto s = states();
1028 list.reserve(alloc: s.size());
1029 for (auto state : s) {
1030 list << static_cast<int>(state);
1031 }
1032 return list;
1033}
1034
1035void QWaylandXdgSurfaceV5::handleSurfaceSizeChanged()
1036{
1037 Q_D(QWaylandXdgSurfaceV5);
1038 d->updateFallbackWindowGeometry();
1039}
1040
1041void QWaylandXdgSurfaceV5::handleBufferScaleChanged()
1042{
1043 Q_D(QWaylandXdgSurfaceV5);
1044 d->updateFallbackWindowGeometry();
1045}
1046
1047/*!
1048 * \qmlproperty XdgShellV5 QtWaylandCompositor::XdgSurfaceV5::shell
1049 *
1050 * This property holds the shell associated with this XdgSurfaceV5.
1051 */
1052
1053/*!
1054 * \property QWaylandXdgSurfaceV5::shell
1055 *
1056 * This property holds the shell associated with this QWaylandXdgSurfaceV5.
1057 */
1058QWaylandXdgShellV5 *QWaylandXdgSurfaceV5::shell() const
1059{
1060 Q_D(const QWaylandXdgSurfaceV5);
1061 return d->m_xdgShell;
1062}
1063
1064/*!
1065 * \qmlproperty WaylandSurface QtWaylandCompositor::XdgSurfaceV5::surface
1066 *
1067 * This property holds the surface associated with this XdgSurfaceV5.
1068 */
1069
1070/*!
1071 * \property QWaylandXdgSurfaceV5::surface
1072 *
1073 * This property holds the surface associated with this QWaylandXdgSurfaceV5.
1074 */
1075QWaylandSurface *QWaylandXdgSurfaceV5::surface() const
1076{
1077 Q_D(const QWaylandXdgSurfaceV5);
1078 return d->m_surface;
1079}
1080
1081/*!
1082 * \qmlproperty enumeration QtWaylandCompositor::XdgSurfaceV5::windowType
1083 *
1084 * This property holds the window type of the XdgSurfaceV5.
1085 */
1086
1087Qt::WindowType QWaylandXdgSurfaceV5::windowType() const
1088{
1089 Q_D(const QWaylandXdgSurfaceV5);
1090 return d->m_windowType;
1091}
1092
1093/*!
1094 * \qmlproperty XdgSurfaceV5 QtWaylandCompositor::XdgSurfaceV5::parentSurface
1095 *
1096 * This property holds the XdgSurfaceV5 parent of this XdgSurfaceV5.
1097 * When a parent surface is set, the parentSurfaceChanged() signal
1098 * is guaranteed to be emitted before setTopLevel() and setTransient().
1099 *
1100 * \sa QtWaylandCompositor::XdgSurfaceV5::setTopLevel()
1101 * \sa QtWaylandCompositor::XdgSurfaceV5::setTransient()
1102 */
1103
1104/*!
1105 * \property QWaylandXdgSurfaceV5::parentSurface
1106 *
1107 * This property holds the XdgSurfaceV5 parent of this XdgSurfaceV5.
1108 * When a parent surface is set, the parentSurfaceChanged() signal
1109 * is guaranteed to be emitted before setTopLevel() and setTransient().
1110 *
1111 * \sa QWaylandXdgSurfaceV5::setTopLevel()
1112 * \sa QWaylandXdgSurfaceV5::setTransient()
1113 */
1114QWaylandXdgSurfaceV5 *QWaylandXdgSurfaceV5::parentSurface() const
1115{
1116 Q_D(const QWaylandXdgSurfaceV5);
1117 return d->m_parentSurface;
1118}
1119
1120/*!
1121 * \qmlproperty string QtWaylandCompositor::XdgSurfaceV5::title
1122 *
1123 * This property holds the title of the XdgSurfaceV5.
1124 */
1125
1126/*!
1127 * \property QWaylandXdgSurfaceV5::title
1128 *
1129 * This property holds the title of the QWaylandXdgSurfaceV5.
1130 */
1131QString QWaylandXdgSurfaceV5::title() const
1132{
1133 Q_D(const QWaylandXdgSurfaceV5);
1134 return d->m_title;
1135}
1136
1137/*!
1138 * \property QWaylandXdgSurfaceV5::appId
1139 *
1140 * This property holds the app id of the QWaylandXdgSurfaceV5.
1141 */
1142QString QWaylandXdgSurfaceV5::appId() const
1143{
1144 Q_D(const QWaylandXdgSurfaceV5);
1145 return d->m_appId;
1146}
1147
1148/*!
1149 * \property QWaylandXdgSurfaceV5::windowGeometry
1150 *
1151 * This property holds the window geometry of the QWaylandXdgSurfaceV5. The window
1152 * geometry describes the window's visible bounds from the user's perspective.
1153 * The geometry includes title bars and borders if drawn by the client, but
1154 * excludes drop shadows. It is meant to be used for aligning and tiling
1155 * windows.
1156 */
1157QRect QWaylandXdgSurfaceV5::windowGeometry() const
1158{
1159 Q_D(const QWaylandXdgSurfaceV5);
1160 return d->m_windowGeometry;
1161}
1162
1163/*!
1164 * \property QWaylandXdgSurfaceV5::states
1165 *
1166 * This property holds the last states the client acknowledged for this QWaylandXdgSurfaceV5.
1167 */
1168QVector<uint> QWaylandXdgSurfaceV5::states() const
1169{
1170 Q_D(const QWaylandXdgSurfaceV5);
1171 return d->m_lastAckedConfigure.states;
1172}
1173
1174bool QWaylandXdgSurfaceV5::maximized() const
1175{
1176 Q_D(const QWaylandXdgSurfaceV5);
1177 return d->m_lastAckedConfigure.states.contains(t: QWaylandXdgSurfaceV5::State::MaximizedState);
1178}
1179
1180bool QWaylandXdgSurfaceV5::fullscreen() const
1181{
1182 Q_D(const QWaylandXdgSurfaceV5);
1183 return d->m_lastAckedConfigure.states.contains(t: QWaylandXdgSurfaceV5::State::FullscreenState);
1184}
1185
1186bool QWaylandXdgSurfaceV5::resizing() const
1187{
1188 Q_D(const QWaylandXdgSurfaceV5);
1189 return d->m_lastAckedConfigure.states.contains(t: QWaylandXdgSurfaceV5::State::ResizingState);
1190}
1191
1192bool QWaylandXdgSurfaceV5::activated() const
1193{
1194 Q_D(const QWaylandXdgSurfaceV5);
1195 return d->m_lastAckedConfigure.states.contains(t: QWaylandXdgSurfaceV5::State::ActivatedState);
1196}
1197
1198/*!
1199 * Returns the Wayland interface for the QWaylandXdgSurfaceV5.
1200 */
1201const wl_interface *QWaylandXdgSurfaceV5::interface()
1202{
1203 return QWaylandXdgSurfaceV5Private::interface();
1204}
1205
1206QByteArray QWaylandXdgSurfaceV5::interfaceName()
1207{
1208 return QWaylandXdgSurfaceV5Private::interfaceName();
1209}
1210
1211/*!
1212 * Returns the surface role for the QWaylandXdgSurfaceV5.
1213 */
1214QWaylandSurfaceRole *QWaylandXdgSurfaceV5::role()
1215{
1216 return &QWaylandXdgSurfaceV5Private::s_role;
1217}
1218
1219/*!
1220 * Returns the QWaylandXdgSurfaceV5 corresponding to the \a resource.
1221 */
1222QWaylandXdgSurfaceV5 *QWaylandXdgSurfaceV5::fromResource(wl_resource *resource)
1223{
1224 if (auto p = QtWayland::fromResource<QWaylandXdgSurfaceV5Private *>(resource))
1225 return p->q_func();
1226 return nullptr;
1227}
1228
1229QSize QWaylandXdgSurfaceV5::sizeForResize(const QSizeF &size, const QPointF &delta,
1230 QWaylandXdgSurfaceV5::ResizeEdge edge)
1231{
1232 qreal width = size.width();
1233 qreal height = size.height();
1234 if (edge & LeftEdge)
1235 width -= delta.x();
1236 else if (edge & RightEdge)
1237 width += delta.x();
1238
1239 if (edge & TopEdge)
1240 height -= delta.y();
1241 else if (edge & BottomEdge)
1242 height += delta.y();
1243
1244 QSizeF newSize(qMax(a: width, b: 1.0), qMax(a: height, b: 1.0));
1245 return newSize.toSize();
1246}
1247
1248/*!
1249 * \qmlmethod int QtWaylandCompositor::XdgSurfaceV5::sendConfigure(size size, list<uint> states)
1250 *
1251 * Sends a configure event to the client. \a size contains the pixel size of the surface.
1252 * Known \a states are enumerated in XdgSurfaceV5::State.
1253 */
1254
1255/*!
1256 * Sends a configure event to the client. Parameter \a size contains the pixel size
1257 * of the surface. Known \a states are enumerated in QWaylandXdgSurfaceV5::State.
1258 */
1259uint QWaylandXdgSurfaceV5::sendConfigure(const QSize &size, const QVector<uint> &states)
1260{
1261 if (!size.isValid()) {
1262 qWarning() << "Can't configure xdg surface (v5) with an invalid size" << size;
1263 return 0;
1264 }
1265 Q_D(QWaylandXdgSurfaceV5);
1266 auto statesBytes = QByteArray::fromRawData((char *)states.data(), size: states.size() * sizeof(State));
1267 QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(object: extensionContainer());
1268 Q_ASSERT(surface);
1269 QWaylandCompositor *compositor = surface->compositor();
1270 Q_ASSERT(compositor);
1271 uint32_t serial = compositor->nextSerial();
1272 d->m_pendingConfigures.append(t: QWaylandXdgSurfaceV5Private::ConfigureEvent{.states: states, .size: size, .serial: serial});
1273 d->send_configure(width: size.width(), height: size.height(), states: statesBytes, serial);
1274 return serial;
1275}
1276
1277uint QWaylandXdgSurfaceV5::sendConfigure(const QSize &size, const QVector<QWaylandXdgSurfaceV5::State> &states)
1278{
1279 QVector<uint> asUints;
1280 asUints.reserve(asize: states.size());
1281 for (QWaylandXdgSurfaceV5::State state : states) {
1282 asUints << state;
1283 }
1284 return sendConfigure(size, states: asUints);
1285}
1286
1287/*!
1288 * \qmlmethod void QtWaylandCompositor::XdgSurfaceV5::sendClose()
1289 *
1290 * Sends a close event to the client.
1291 */
1292
1293/*!
1294 * Sends a close event to the client.
1295 */
1296void QWaylandXdgSurfaceV5::sendClose()
1297{
1298 Q_D(QWaylandXdgSurfaceV5);
1299 d->send_close();
1300}
1301
1302uint QWaylandXdgSurfaceV5::sendMaximized(const QSize &size)
1303{
1304 Q_D(QWaylandXdgSurfaceV5);
1305 QWaylandXdgSurfaceV5Private::ConfigureEvent conf = d->lastSentConfigure();
1306
1307 if (!conf.states.contains(t: QWaylandXdgSurfaceV5::State::MaximizedState))
1308 conf.states.append(t: QWaylandXdgSurfaceV5::State::MaximizedState);
1309 conf.states.removeOne(t: QWaylandXdgSurfaceV5::State::FullscreenState);
1310 conf.states.removeOne(t: QWaylandXdgSurfaceV5::State::ResizingState);
1311
1312 return sendConfigure(size, states: conf.states);
1313}
1314
1315uint QWaylandXdgSurfaceV5::sendUnmaximized(const QSize &size)
1316{
1317 Q_D(QWaylandXdgSurfaceV5);
1318 QWaylandXdgSurfaceV5Private::ConfigureEvent conf = d->lastSentConfigure();
1319
1320 conf.states.removeOne(t: QWaylandXdgSurfaceV5::State::MaximizedState);
1321 conf.states.removeOne(t: QWaylandXdgSurfaceV5::State::FullscreenState);
1322 conf.states.removeOne(t: QWaylandXdgSurfaceV5::State::ResizingState);
1323
1324 return sendConfigure(size, states: conf.states);
1325}
1326
1327uint QWaylandXdgSurfaceV5::sendFullscreen(const QSize &size)
1328{
1329 Q_D(QWaylandXdgSurfaceV5);
1330 QWaylandXdgSurfaceV5Private::ConfigureEvent conf = d->lastSentConfigure();
1331
1332 if (!conf.states.contains(t: QWaylandXdgSurfaceV5::State::FullscreenState))
1333 conf.states.append(t: QWaylandXdgSurfaceV5::State::FullscreenState);
1334 conf.states.removeOne(t: QWaylandXdgSurfaceV5::State::MaximizedState);
1335 conf.states.removeOne(t: QWaylandXdgSurfaceV5::State::ResizingState);
1336
1337 return sendConfigure(size, states: conf.states);
1338}
1339
1340uint QWaylandXdgSurfaceV5::sendResizing(const QSize &maxSize)
1341{
1342 Q_D(QWaylandXdgSurfaceV5);
1343 QWaylandXdgSurfaceV5Private::ConfigureEvent conf = d->lastSentConfigure();
1344
1345 if (!conf.states.contains(t: QWaylandXdgSurfaceV5::State::ResizingState))
1346 conf.states.append(t: QWaylandXdgSurfaceV5::State::ResizingState);
1347 conf.states.removeOne(t: QWaylandXdgSurfaceV5::State::MaximizedState);
1348 conf.states.removeOne(t: QWaylandXdgSurfaceV5::State::FullscreenState);
1349
1350 return sendConfigure(size: maxSize, states: conf.states);
1351}
1352
1353#if QT_CONFIG(wayland_compositor_quick)
1354QWaylandQuickShellIntegration *QWaylandXdgSurfaceV5::createIntegration(QWaylandQuickShellSurfaceItem *item)
1355{
1356 return new QtWayland::XdgShellV5Integration(item);
1357}
1358#endif
1359
1360/*!
1361 * \qmltype XdgPopupV5
1362 * \inqmlmodule QtWayland.Compositor
1363 * \since 5.8
1364 * \obsolete
1365 * \brief Provides a \c xdg_popup interface that implements popup features for the xdg-shell protocol.
1366 *
1367 * This type is part of the \l{XdgShellV5} extension and provides a way to extend
1368 * the functionality of an existing WaylandSurface for handling popup surfaces created by clients
1369 * using xdg-shell.
1370 *
1371 * It corresponds to the Wayland interface \c xdg_popup for the unstable xdg-shell protocol v5.
1372 *
1373 * \deprecated
1374 */
1375
1376/*!
1377 * \class QWaylandXdgPopupV5
1378 * \inmodule QtWaylandCompositor
1379 * \since 5.8
1380 * \obsolete
1381 * \brief The QWaylandXdgPopupV5 class provides menus for an xdg surface.
1382 *
1383 * This class is part of the QWaylandXdgShellV5 extension and provides a way to
1384 * extend the functionality of an existing QWaylandSurface with features
1385 * specific to desktop-style menus for an xdg surface.
1386 *
1387 * It corresponds to the Wayland interface xdg_popup.
1388 *
1389 * \deprecated
1390 */
1391
1392/*!
1393 * Constructs a QWaylandXdgPopupV5.
1394 */
1395QWaylandXdgPopupV5::QWaylandXdgPopupV5()
1396 : QWaylandShellSurfaceTemplate<QWaylandXdgPopupV5>(*new QWaylandXdgPopupV5Private)
1397{
1398}
1399
1400/*!
1401 * Constructs a QWaylandXdgPopupV5, associating it with \a xdgShell at the specified \a position
1402 * for \a surface, and initializes it with the given \a parentSurface and \a resource.
1403 */
1404QWaylandXdgPopupV5::QWaylandXdgPopupV5(QWaylandXdgShellV5 *xdgShell, QWaylandSurface *surface,
1405 QWaylandSurface *parentSurface, const QPoint &position, const QWaylandResource &resource)
1406 : QWaylandShellSurfaceTemplate<QWaylandXdgPopupV5>(*new QWaylandXdgPopupV5Private)
1407{
1408 initialize(shell: xdgShell, surface, parentSurface, position, resource);
1409}
1410
1411/*!
1412 * \qmlmethod void QtWaylandCompositor::XdgPopupV5::initialize(XdgShellV5 shell, WaylandSurface surface, WaylandSurface parentSurface, point position, WaylandResource resource)
1413 *
1414 * Initializes the xdg popup, associating it with the given \a shell, \a surface,
1415 * \a parentSurface, \a position and \a resource.
1416 */
1417
1418/*!
1419 * Initializes the QWaylandXdgPopupV5, associating it with the given \a shell, \a surface,
1420 * \a parentSurface, \a position, and \a resource.
1421 */
1422void QWaylandXdgPopupV5::initialize(QWaylandXdgShellV5 *shell, QWaylandSurface *surface, QWaylandSurface *parentSurface,
1423 const QPoint& position, const QWaylandResource &resource)
1424{
1425 Q_D(QWaylandXdgPopupV5);
1426 d->m_surface = surface;
1427 d->m_parentSurface = parentSurface;
1428 d->m_xdgShell = shell;
1429 d->m_position = position;
1430 d->init(resource: resource.resource());
1431 setExtensionContainer(surface);
1432 emit shellChanged();
1433 emit surfaceChanged();
1434 emit parentSurfaceChanged();
1435 emit positionChanged();
1436 QWaylandCompositorExtension::initialize();
1437}
1438
1439/*!
1440 * \qmlproperty XdgShellV5 QtWaylandCompositor::XdgPopupV5::shell
1441 *
1442 * This property holds the shell associated with this XdgPopupV5.
1443 */
1444
1445/*!
1446 * \property QWaylandXdgPopupV5::shell
1447 *
1448 * This property holds the shell associated with this QWaylandXdgPopupV5.
1449 */
1450QWaylandXdgShellV5 *QWaylandXdgPopupV5::shell() const
1451{
1452 Q_D(const QWaylandXdgPopupV5);
1453 return d->m_xdgShell;
1454}
1455
1456/*!
1457 * \qmlproperty WaylandSurface QtWaylandCompositor::XdgPopupV5::surface
1458 *
1459 * This property holds the surface associated with this XdgPopupV5.
1460 */
1461
1462/*!
1463 * \property QWaylandXdgPopupV5::surface
1464 *
1465 * This property holds the surface associated with this QWaylandXdgPopupV5.
1466 */
1467QWaylandSurface *QWaylandXdgPopupV5::surface() const
1468{
1469 Q_D(const QWaylandXdgPopupV5);
1470 return d->m_surface;
1471}
1472
1473/*!
1474 * \qmlproperty WaylandSurface QtWaylandCompositor::XdgPopupV5::parentSurface
1475 *
1476 * This property holds the surface associated with the parent of this XdgPopupV5.
1477 */
1478
1479/*!
1480 * \property QWaylandXdgPopupV5::parentSurface
1481 *
1482 * This property holds the surface associated with the parent of this
1483 * QWaylandXdgPopupV5.
1484 */
1485QWaylandSurface *QWaylandXdgPopupV5::parentSurface() const
1486{
1487 Q_D(const QWaylandXdgPopupV5);
1488 return d->m_parentSurface;
1489}
1490
1491
1492/*!
1493 * \qmlproperty point QtWaylandCompositor::XdgPopupV5::position
1494 *
1495 * This property holds the location of the upper left corner of the surface
1496 * relative to the upper left corner of the parent surface, in surface local
1497 * coordinates.
1498 */
1499
1500/*!
1501 * \property QWaylandXdgPopupV5::position
1502 *
1503 * This property holds the location of the upper left corner of the surface
1504 * relative to the upper left corner of the parent surface, in surface local
1505 * coordinates.
1506 */
1507QPoint QWaylandXdgPopupV5::position() const
1508{
1509 Q_D(const QWaylandXdgPopupV5);
1510 return d->m_position;
1511}
1512
1513/*!
1514 * \internal
1515 */
1516void QWaylandXdgPopupV5::initialize()
1517{
1518 QWaylandCompositorExtension::initialize();
1519}
1520
1521/*!
1522 * Returns the Wayland interface for the QWaylandXdgPopupV5.
1523 */
1524const wl_interface *QWaylandXdgPopupV5::interface()
1525{
1526 return QWaylandXdgPopupV5Private::interface();
1527}
1528
1529QByteArray QWaylandXdgPopupV5::interfaceName()
1530{
1531 return QWaylandXdgPopupV5Private::interfaceName();
1532}
1533
1534/*!
1535 * Returns the surface role for the QWaylandXdgPopupV5.
1536 */
1537QWaylandSurfaceRole *QWaylandXdgPopupV5::role()
1538{
1539 return &QWaylandXdgPopupV5Private::s_role;
1540}
1541
1542QWaylandXdgPopupV5 *QWaylandXdgPopupV5::fromResource(wl_resource *resource)
1543{
1544 if (auto p = QtWayland::fromResource<QWaylandXdgPopupV5Private *>(resource))
1545 return p->q_func();
1546 return nullptr;
1547}
1548
1549void QWaylandXdgPopupV5::sendPopupDone()
1550{
1551 Q_D(QWaylandXdgPopupV5);
1552 d->send_popup_done();
1553}
1554
1555#if QT_CONFIG(wayland_compositor_quick)
1556QWaylandQuickShellIntegration *QWaylandXdgPopupV5::createIntegration(QWaylandQuickShellSurfaceItem *item)
1557{
1558 return new QtWayland::XdgPopupV5Integration(item);
1559}
1560#endif
1561
1562#endif // QT_DEPRECATED_SINCE(5, 15)
1563
1564QT_END_NAMESPACE
1565

source code of qtwayland/src/compositor/extensions/qwaylandxdgshellv5.cpp