Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwaylandwlshell.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4// Qt-Security score:critical reason:network-protocol
5
8
9#if QT_CONFIG(wayland_compositor_quick)
10#include "qwaylandwlshellintegration_p.h"
11#endif
12#include <QtWaylandCompositor/private/qwaylandutils_p.h>
13
14#include <QtWaylandCompositor/QWaylandCompositor>
15#include <QtWaylandCompositor/QWaylandView>
16#include <QtWaylandCompositor/QWaylandOutput>
17#include <QtWaylandCompositor/QWaylandClient>
18
19#include <QtCore/QObject>
20#include <QtCore/QDebug>
21
23
24QWaylandSurfaceRole QWaylandWlShellSurfacePrivate::s_role("wl_shell_surface");
25
26QWaylandWlShellPrivate::QWaylandWlShellPrivate()
27{
28}
29
30void QWaylandWlShellPrivate::shell_get_shell_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface_res)
31{
32 Q_Q(QWaylandWlShell);
33 QWaylandSurface *surface = QWaylandSurface::fromResource(surface_res);
34
35 QWaylandResource shellSurfaceResource(wl_resource_create(resource->client(), &wl_shell_surface_interface,
36 wl_resource_get_version(resource->handle), id));
37
38 // XXX FIXME
39 // The role concept was formalized in wayland 1.7, so that release adds one error
40 // code for each interface that implements a role, and we are supposed to pass here
41 // the newly constructed resource and the correct error code so that if setting the
42 // role fails, a proper error can be sent to the client.
43 // However we're still using wayland 1.4, which doesn't have interface specific role
44 // errors, so the best we can do is to use wl_display's object_id error.
45 wl_resource *displayRes = wl_client_get_object(resource->client(), 1);
46 if (!surface->setRole(QWaylandWlShellSurface::role(), displayRes, WL_DISPLAY_ERROR_INVALID_OBJECT))
47 return;
48
49 emit q->wlShellSurfaceRequested(surface, shellSurfaceResource);
50
51 QWaylandWlShellSurface *shellSurface = QWaylandWlShellSurface::fromResource(shellSurfaceResource.resource());
52 if (!shellSurface) {
53 // A QWaylandWlShellSurface was not created in response to the wlShellSurfaceRequested
54 // signal, so we create one as fallback here instead.
55 shellSurface = new QWaylandWlShellSurface(q, surface, shellSurfaceResource);
56 }
57
58 m_shellSurfaces.append(shellSurface);
59 emit q->wlShellSurfaceCreated(shellSurface);
60}
61
62void QWaylandWlShellPrivate::unregisterShellSurface(QWaylandWlShellSurface *shellSurface)
63{
64 if (!m_shellSurfaces.removeOne(shellSurface))
65 qWarning("Unexpected state. Can't find registered shell surface.");
66}
67
68QWaylandWlShellSurfacePrivate::QWaylandWlShellSurfacePrivate()
69{
70}
71
72QWaylandWlShellSurfacePrivate::~QWaylandWlShellSurfacePrivate()
73{
74}
75
76void QWaylandWlShellSurfacePrivate::ping(uint32_t serial)
77{
78 m_pings.insert(serial);
79 send_ping(serial);
80}
81
82void QWaylandWlShellSurfacePrivate::setWindowType(Qt::WindowType windowType)
83{
84 if (m_windowType == windowType)
85 return;
86 m_windowType = windowType;
87
88 Q_Q(QWaylandWlShellSurface);
89 emit q->windowTypeChanged();
90}
91
92void QWaylandWlShellSurfacePrivate::shell_surface_destroy_resource(Resource *)
93{
94 Q_Q(QWaylandWlShellSurface);
95
96 delete q;
97}
98
99void QWaylandWlShellSurfacePrivate::shell_surface_move(Resource *resource,
100 struct wl_resource *input_device_super,
101 uint32_t serial)
102{
103 Q_UNUSED(resource);
104 Q_UNUSED(serial);
105
106 Q_Q(QWaylandWlShellSurface);
107 QWaylandSeat *input_device = QWaylandSeat::fromSeatResource(input_device_super);
108 emit q->startMove(input_device);
109}
110
111void QWaylandWlShellSurfacePrivate::shell_surface_resize(Resource *resource,
112 struct wl_resource *input_device_super,
113 uint32_t serial,
114 uint32_t edges)
115{
116 Q_UNUSED(resource);
117 Q_UNUSED(serial);
118 Q_Q(QWaylandWlShellSurface);
119
120 QWaylandSeat *input_device = QWaylandSeat::fromSeatResource(input_device_super);
121 emit q->startResize(input_device, QWaylandWlShellSurface::ResizeEdge(edges));
122}
123
124void QWaylandWlShellSurfacePrivate::shell_surface_set_toplevel(Resource *resource)
125{
126 Q_UNUSED(resource);
127 Q_Q(QWaylandWlShellSurface);
128 setWindowType(Qt::WindowType::Window);
129 emit q->setDefaultToplevel();
130}
131
132void QWaylandWlShellSurfacePrivate::shell_surface_set_transient(Resource *resource,
133 struct wl_resource *parent_surface_resource,
134 int x,
135 int y,
136 uint32_t flags)
137{
138
139 Q_UNUSED(resource);
140 Q_Q(QWaylandWlShellSurface);
141 QWaylandSurface *parent_surface = QWaylandSurface::fromResource(parent_surface_resource);
142 setWindowType(Qt::WindowType::SubWindow);
143 emit q->setTransient(parent_surface, QPoint(x,y), flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
144}
145
146void QWaylandWlShellSurfacePrivate::shell_surface_set_fullscreen(Resource *resource,
147 uint32_t method,
148 uint32_t framerate,
149 struct wl_resource *output_resource)
150{
151 Q_UNUSED(resource);
152 Q_UNUSED(method);
153 Q_UNUSED(framerate);
154 Q_Q(QWaylandWlShellSurface);
155 QWaylandOutput *output = output_resource
156 ? QWaylandOutput::fromResource(output_resource)
157 : nullptr;
158 setWindowType(Qt::WindowType::Window);
159 emit q->setFullScreen(QWaylandWlShellSurface::FullScreenMethod(method), framerate, output);
160}
161
162void QWaylandWlShellSurfacePrivate::shell_surface_set_popup(Resource *resource, wl_resource *input_device, uint32_t serial, wl_resource *parent, int32_t x, int32_t y, uint32_t flags)
163{
164 Q_UNUSED(resource);
165 Q_UNUSED(serial);
166 Q_UNUSED(flags);
167 Q_Q(QWaylandWlShellSurface);
168 QWaylandSeat *input = QWaylandSeat::fromSeatResource(input_device);
169 QWaylandSurface *parentSurface = QWaylandSurface::fromResource(parent);
170 setWindowType(Qt::WindowType::Popup);
171 emit q->setPopup(input, parentSurface, QPoint(x,y));
172
173}
174
175void QWaylandWlShellSurfacePrivate::shell_surface_set_maximized(Resource *resource,
176 struct wl_resource *output_resource)
177{
178 Q_UNUSED(resource);
179 Q_Q(QWaylandWlShellSurface);
180 QWaylandOutput *output = output_resource
181 ? QWaylandOutput::fromResource(output_resource)
182 : nullptr;
183 setWindowType(Qt::WindowType::Window);
184 emit q->setMaximized(output);
185}
186
187void QWaylandWlShellSurfacePrivate::shell_surface_pong(Resource *resource,
188 uint32_t serial)
189{
190 Q_UNUSED(resource);
191 Q_Q(QWaylandWlShellSurface);
192 if (m_pings.remove(serial))
193 emit q->pong();
194 else
195 qWarning("Received an unexpected pong!");
196}
197
198void QWaylandWlShellSurfacePrivate::shell_surface_set_title(Resource *resource,
199 const QString &title)
200{
201 Q_UNUSED(resource);
202 if (title == m_title)
203 return;
204 Q_Q(QWaylandWlShellSurface);
205 m_title = title;
206 emit q->titleChanged();
207}
208
209void QWaylandWlShellSurfacePrivate::shell_surface_set_class(Resource *resource,
210 const QString &className)
211{
212 Q_UNUSED(resource);
213 if (className == m_className)
214 return;
215 Q_Q(QWaylandWlShellSurface);
216 m_className = className;
217 emit q->classNameChanged();
218}
219
220/*!
221 * \qmltype WlShell
222 * \nativetype QWaylandWlShell
223 * \inqmlmodule QtWayland.Compositor.WlShell
224 * \since 5.8
225 * \brief Provides an extension for desktop-style user interfaces.
226 *
227 * The WlShell extension provides a way to associate a ShellSurface
228 * with a regular Wayland surface. Using the shell surface interface, the client
229 * can request that the surface is resized, moved, and so on.
230 *
231 * WlShell corresponds to the Wayland interface \c wl_shell.
232 *
233 * To provide the functionality of the shell extension in a compositor, create
234 * an instance of the WlShell component and add it to the list of extensions
235 * supported by the compositor:
236 *
237 * \qml
238 * import QtWayland.Compositor.WlShell
239 *
240 * WaylandCompositor {
241 * WlShell {
242 * // ...
243 * }
244 * }
245 * \endqml
246 */
247
248/*!
249 * \class QWaylandWlShell
250 * \inmodule QtWaylandCompositor
251 * \since 5.8
252 * \brief The QWaylandWlShell class is an extension for desktop-style user interfaces.
253 *
254 * The QWaylandWlShell extension provides a way to associate a QWaylandWlShellSurface with
255 * a regular Wayland surface. Using the shell surface interface, the client
256 * can request that the surface is resized, moved, and so on.
257 *
258 * WlShell corresponds to the Wayland interface \c wl_shell.
259 */
260
261/*!
262 * Constructs a QWaylandWlShell object.
263 */
264QWaylandWlShell::QWaylandWlShell()
265 : QWaylandShellTemplate<QWaylandWlShell>(*new QWaylandWlShellPrivate())
266{ }
267
268/*!
269 * Constructs a QWaylandWlShell object for the provided \a compositor.
270 */
271QWaylandWlShell::QWaylandWlShell(QWaylandCompositor *compositor)
272 : QWaylandShellTemplate<QWaylandWlShell>(compositor, *new QWaylandWlShellPrivate())
273{ }
274
275
276/*!
277 * Initializes the WlShell extension.
278 */
279void QWaylandWlShell::initialize()
280{
281 Q_D(QWaylandWlShell);
282 QWaylandShellTemplate::initialize();
283 QWaylandCompositor *compositor = qobject_cast<QWaylandCompositor *>(extensionContainer());
284 if (!compositor) {
285 qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandWlShell";
286 return;
287 }
288 d->init(compositor->display(), 1);
289}
290
291QList<QWaylandWlShellSurface *> QWaylandWlShell::shellSurfaces() const
292{
293 Q_D(const QWaylandWlShell);
294 return d->m_shellSurfaces;
295}
296
297QList<QWaylandWlShellSurface *> QWaylandWlShell::shellSurfacesForClient(QWaylandClient *client) const
298{
299 Q_D(const QWaylandWlShell);
300 QList<QWaylandWlShellSurface *> surfsForClient;
301 for (QWaylandWlShellSurface *shellSurface : d->m_shellSurfaces) {
302 if (shellSurface->surface() && shellSurface->surface()->client() == client)
303 surfsForClient.append(shellSurface);
304 }
305 return surfsForClient;
306}
307
308QList<QWaylandWlShellSurface *> QWaylandWlShell::mappedPopups() const
309{
310 Q_D(const QWaylandWlShell);
311 QList<QWaylandWlShellSurface *> popupSurfaces;
312 for (QWaylandWlShellSurface *shellSurface : d->m_shellSurfaces) {
313 if (shellSurface->windowType() == Qt::WindowType::Popup
314 && shellSurface->surface() && shellSurface->surface()->hasContent()) {
315 popupSurfaces.append(shellSurface);
316 }
317 }
318 return popupSurfaces;
319}
320
321QWaylandClient *QWaylandWlShell::popupClient() const
322{
323 Q_D(const QWaylandWlShell);
324 for (QWaylandWlShellSurface *shellSurface : d->m_shellSurfaces) {
325 if (shellSurface->windowType() == Qt::WindowType::Popup
326 && shellSurface->surface() && shellSurface->surface()->hasContent()) {
327 return shellSurface->surface()->client();
328 }
329 }
330 return nullptr;
331}
332
333void QWaylandWlShell::closeAllPopups()
334{
335 const auto mapped = mappedPopups();
336 for (QWaylandWlShellSurface *shellSurface : mapped)
337 shellSurface->sendPopupDone();
338}
339
340/*!
341 * Returns the Wayland interface for the QWaylandWlShell.
342 */
343const struct wl_interface *QWaylandWlShell::interface()
344{
345 return QWaylandWlShellPrivate::interface();
346}
347
348/*!
349 * \qmlsignal void WlShell::wlShellSurfaceRequested(WaylandSurface surface, WaylandResource resource)
350 *
351 * This signal is emitted when the client has requested a \c wl_shell_surface to be associated with
352 * \a surface. The handler for this signal may create a shell surface for \a resource and initialize
353 * it within the scope of the signal emission. Otherwise a WlShellSurface will be created
354 * automatically.
355 */
356
357/*!
358 * \fn void QWaylandWlShell::wlShellSurfaceRequested(QWaylandSurface *surface, const QWaylandResource &resource)
359 *
360 * This signal is emitted when the client has requested a \c wl_shell_surface to be associated with
361 * \a surface. The handler for this signal may create a shell surface for \a resource and initialize
362 * it within the scope of the signal emission. Otherwise a QWaylandWlShellSurface will be created
363 * automatically.
364 */
365
366/*!
367 * \qmlsignal void WlShell::wlShellSurfaceCreated(WlShellSurface shellSurface)
368 *
369 * This signal is emitted when the client has created a \c wl_shell_surface.
370 * A common use case is to let the handler of this signal instantiate a ShellSurfaceItem or
371 * WaylandQuickItem for displaying \a shellSurface in a QtQuick scene.
372 */
373
374/*!
375 * \fn void QWaylandWlShell::wlShellSurfaceCreated(QWaylandWlShellSurface *shellSurface)
376 *
377 * This signal is emitted when the client has created a \c wl_shell_surface.
378 * A common use case is to let the handler of this signal instantiate a QWaylandShellSurfaceItem or
379 * QWaylandQuickItem for displaying \a shellSurface in a QtQuick scene.
380 */
381
382/*!
383 * \internal
384 */
385QByteArray QWaylandWlShell::interfaceName()
386{
387 return QWaylandWlShellPrivate::interfaceName();
388}
389
390/*!
391 * \qmltype WlShellSurface
392 * \nativetype QWaylandWlShellSurface
393 * \inqmlmodule QtWayland.Compositor.WlShell
394 * \since 5.8
395 * \brief Provides a \c wl_shell_surface that offers desktop-style compositor-specific features to a surface.
396 *
397 * This type is part of the \l{WlShell} extension and provides a way to extend
398 * the functionality of an existing WaylandSurface with features specific to desktop-style
399 * compositors, such as resizing and moving the surface.
400 *
401 * It corresponds to the Wayland interface \c wl_shell_surface.
402 */
403
404/*!
405 * \class QWaylandWlShellSurface
406 * \inmodule QtWaylandCompositor
407 * \since 5.8
408 * \brief The QWaylandWlShellSurface class provides desktop-style compositor-specific features to a surface.
409 *
410 * This class is part of the QWaylandWlShell extension and provides a way to extend
411 * the functionality of an existing QWaylandSurface with features specific to desktop-style
412 * compositors, such as resizing and moving the surface.
413 *
414 * It corresponds to the Wayland interface \c wl_shell_surface.
415 */
416
417/*!
418 * Constructs a QWaylandWlShellSurface.
419 */
420QWaylandWlShellSurface::QWaylandWlShellSurface()
421 : QWaylandShellSurfaceTemplate<QWaylandWlShellSurface>(*new QWaylandWlShellSurfacePrivate)
422{
423}
424
425/*!
426 * Constructs a QWaylandWlShellSurface for \a surface and initializes it with the given \a shell and resource \a res.
427 */
428QWaylandWlShellSurface::QWaylandWlShellSurface(QWaylandWlShell *shell, QWaylandSurface *surface, const QWaylandResource &res)
429 : QWaylandShellSurfaceTemplate<QWaylandWlShellSurface>(*new QWaylandWlShellSurfacePrivate)
430{
431 initialize(shell, surface, res);
432}
433
434QWaylandWlShellSurface::~QWaylandWlShellSurface()
435{
436 Q_D(QWaylandWlShellSurface);
437 if (d->m_shell)
438 QWaylandWlShellPrivate::get(d->m_shell)->unregisterShellSurface(this);
439}
440
441/*!
442 * \qmlmethod void WlShellSurface::initialize(WlShell shell, WaylandSurface surface, WaylandResource resource)
443 *
444 * Initializes the WlShellSurface and associates it with the given \a shell, \a surface, and \a resource.
445 */
446
447/*!
448 * Initializes the QWaylandWlShellSurface and associates it with the given \a shell, \a surface, and \a resource.
449 */
450void QWaylandWlShellSurface::initialize(QWaylandWlShell *shell, QWaylandSurface *surface, const QWaylandResource &resource)
451{
452 Q_D(QWaylandWlShellSurface);
453 d->m_shell = shell;
454 d->m_surface = surface;
455 d->init(resource.resource());
456 setExtensionContainer(surface);
457 emit surfaceChanged();
458 emit shellChanged();
459 QWaylandCompositorExtension::initialize();
460}
461
462/*!
463 * \internal
464 */
465void QWaylandWlShellSurface::initialize()
466{
467 QWaylandCompositorExtension::initialize();
468}
469
470const struct wl_interface *QWaylandWlShellSurface::interface()
471{
472 return QWaylandWlShellSurfacePrivate::interface();
473}
474
475/*!
476 * \internal
477 */
478QByteArray QWaylandWlShellSurface::interfaceName()
479{
480 return QWaylandWlShellSurfacePrivate::interfaceName();
481}
482
483QSize QWaylandWlShellSurface::sizeForResize(const QSizeF &size, const QPointF &delta, QWaylandWlShellSurface::ResizeEdge edge)
484{
485 qreal width = size.width();
486 qreal height = size.height();
487 if (edge & LeftEdge)
488 width -= delta.x();
489 else if (edge & RightEdge)
490 width += delta.x();
491
492 if (edge & TopEdge)
493 height -= delta.y();
494 else if (edge & BottomEdge)
495 height += delta.y();
496
497 QSizeF newSize(qMax(width, 1.0), qMax(height, 1.0));
498 return newSize.toSize();
499}
500
501/*!
502 * \enum QWaylandWlShellSurface::ResizeEdge
503 *
504 * This enum type provides a way to specify an edge or corner of
505 * the surface.
506 *
507 * \value NoneEdge No edge.
508 * \value TopEdge The top edge.
509 * \value BottomEdge The bottom edge.
510 * \value LeftEdge The left edge.
511 * \value TopLeftEdge The top left corner.
512 * \value BottomLeftEdge The bottom left corner.
513 * \value RightEdge The right edge.
514 * \value TopRightEdge The top right corner.
515 * \value BottomRightEdge The bottom right corner.
516 */
517
518/*!
519 * \qmlmethod void WlShellSurface::sendConfigure(size s, enum edges)
520 *
521 * Sends a configure event to the client, suggesting that it resize its surface to
522 * the provided size \a s. The \a edges provide a hint about how the surface
523 * was resized.
524 */
525
526/*!
527 * Sends a configure event to the client, suggesting that it resize its surface to
528 * the provided \a size. The \a edges provide a hint about how the surface
529 * was resized.
530 */
531void QWaylandWlShellSurface::sendConfigure(const QSize &size, ResizeEdge edges)
532{
533 Q_D(QWaylandWlShellSurface);
534 if (!size.isValid()) {
535 qWarning() << "Can't configure wl_shell_surface with an invalid size" << size;
536 return;
537 }
538 d->send_configure(edges, size.width(), size.height());
539}
540
541/*!
542 * \qmlmethod void WlShellSurface::sendPopupDone()
543 *
544 * Sends a popup_done event to the client to indicate that the user has clicked
545 * somewhere outside the client's surfaces.
546 */
547
548/*!
549 * Sends a popup_done event to the client to indicate that the user has clicked
550 * somewhere outside the client's surfaces.
551 */
552void QWaylandWlShellSurface::sendPopupDone()
553{
554 Q_D(QWaylandWlShellSurface);
555 d->send_popup_done();
556}
557
558#if QT_CONFIG(wayland_compositor_quick)
559QWaylandQuickShellIntegration *QWaylandWlShellSurface::createIntegration(QWaylandQuickShellSurfaceItem *item)
560{
561 return new QtWayland::WlShellIntegration(item);
562}
563#endif
564
565/*!
566 * \qmlproperty WaylandSurface WlShellSurface::surface
567 *
568 * This property holds the \c wl_surface associated with this WlShellSurface.
569 */
570
571/*!
572 * \property QWaylandWlShellSurface::surface
573 *
574 * This property holds the surface associated with this QWaylandWlShellSurface.
575 */
576QWaylandSurface *QWaylandWlShellSurface::surface() const
577{
578 Q_D(const QWaylandWlShellSurface);
579 return d->m_surface;
580}
581
582/*!
583 * \qmlproperty WlShell WlShellSurface::shell
584 *
585 * This property holds the shell associated with this WlShellSurface.
586 */
587
588/*!
589 * \property QWaylandWlShellSurface::shell
590 *
591 * This property holds the shell associated with this QWaylandWlShellSurface.
592 */
593QWaylandWlShell *QWaylandWlShellSurface::shell() const
594{
595 Q_D(const QWaylandWlShellSurface);
596 return d->m_shell;
597}
598
599/*!
600 * \qmlproperty enum WlShellSurface::windowType
601 *
602 * This property holds the window type of the WlShellSurface.
603 */
604
605Qt::WindowType QWaylandWlShellSurface::windowType() const
606{
607 Q_D(const QWaylandWlShellSurface);
608 return d->m_windowType;
609}
610
611/*!
612 * \qmlproperty string WlShellSurface::title
613 *
614 * This property holds the title of the WlShellSurface.
615 */
616
617/*!
618 * \property QWaylandWlShellSurface::title
619 *
620 * This property holds the title of the QWaylandWlShellSurface.
621 */
622QString QWaylandWlShellSurface::title() const
623{
624 Q_D(const QWaylandWlShellSurface);
625 return d->m_title;
626}
627
628/*!
629 * \qmlproperty string WlShellSurface::className
630 *
631 * This property holds the class name of the WlShellSurface.
632 */
633
634/*!
635 * \property QWaylandWlShellSurface::className
636 *
637 * This property holds the class name of the QWaylandWlShellSurface.
638 */
639QString QWaylandWlShellSurface::className() const
640{
641 Q_D(const QWaylandWlShellSurface);
642 return d->m_className;
643}
644
645QWaylandSurfaceRole *QWaylandWlShellSurface::role()
646{
647 return &QWaylandWlShellSurfacePrivate::s_role;
648}
649
650/*!
651 * \qmlmethod void WlShellSurface::ping()
652 *
653 * Sends a ping event to the client. If the client replies to the event the pong
654 * signal will be emitted.
655 */
656
657/*!
658 * Sends a ping event to the client. If the client replies to the event the pong
659 * signal will be emitted.
660 */
661void QWaylandWlShellSurface::ping()
662{
663 Q_D(QWaylandWlShellSurface);
664 uint32_t serial = d->m_surface->compositor()->nextSerial();
665 d->ping(serial);
666}
667
668/*!
669 * Returns the QWaylandWlShellSurface object associated with the given \a resource, or null if no such object exists.
670 */
671QWaylandWlShellSurface *QWaylandWlShellSurface::fromResource(wl_resource *resource)
672{
673 if (auto p = QtWayland::fromResource<QWaylandWlShellSurfacePrivate *>(resource))
674 return p->q_func();
675 return nullptr;
676}
677
678QT_END_NAMESPACE
679
680#include "moc_qwaylandwlshell.cpp"
Combined button and popup list for selecting options.