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
qwaylandqtshell.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
7
8#include <QtWaylandCompositor/QWaylandCompositor>
9#include <QtWaylandCompositor/QWaylandSurface>
11#include <QtWaylandCompositor/QWaylandResource>
12
13#if QT_CONFIG(wayland_compositor_quick)
14# include "qwaylandqtshellintegration_p.h"
15#endif
16
17#include <QtWaylandCompositor/QWaylandResource>
18#include <QDebug>
19#include "compositor_api/qwaylandseat.h"
20
21#include <QtWaylandCompositor/private/qwaylandutils_p.h>
22
23QT_BEGIN_NAMESPACE
24
25/*!
26 * \qmltype QtShell
27 * \nativetype QWaylandQtShell
28 * \inqmlmodule QtWayland.Compositor.QtShell
29 * \since 6.3
30 * \brief Provides a shell extension for Qt applications running on a Qt Wayland Compositor.
31 *
32 * The QtShell extension provides a way to associate an QtShellSurface with a regular Wayland
33 * surface. The QtShell extension is written to support the window management features which are
34 * supported by Qt. It may be suitable on a platform where both the compositor and client
35 * applications are written with Qt, and where applications are trusted not to abuse features such
36 * as manual window positioning and "bring-to-front".
37 *
38 * For other use cases, consider using IviApplication or XdgShell instead.
39 *
40 * \code
41 * import QtWayland.Compositor.QtShell
42 *
43 * WaylandCompositor {
44 * property ListModel shellSurfaces: ListModel {}
45 * QtShell {
46 * onQtShellSurfaceCreated: {
47 * shellSurfaces.append({shellSurface: qtShellSurface})
48 * }
49 * }
50 * }
51 * \endcode
52 */
53QWaylandQtShell::QWaylandQtShell()
54 : QWaylandCompositorExtensionTemplate<QWaylandQtShell>(*new QWaylandQtShellPrivate())
55{
56}
57
58QWaylandQtShell::QWaylandQtShell(QWaylandCompositor *compositor)
59 : QWaylandCompositorExtensionTemplate<QWaylandQtShell>(compositor, *new QWaylandQtShellPrivate())
60{
61}
62
63bool QWaylandQtShell::moveChromeToFront(QWaylandQtShellChrome *chrome)
64{
65 Q_D(QWaylandQtShell);
66 for (int i = 0; i < d->m_chromes.size(); ++i) {
67 if (d->m_chromes.at(i) == chrome) {
68 if (i > 0) {
69 QWaylandQtShellChrome *currentActive = d->m_chromes.first();
70 d->m_chromes.move(i, 0);
71 chrome->activate();
72 currentActive->deactivate();
73 }
74 return true;
75 }
76 }
77
78 return false;
79}
80
81void QWaylandQtShell::registerChrome(QWaylandQtShellChrome *chrome)
82{
83 Q_D(QWaylandQtShell);
84 if (moveChromeToFront(chrome))
85 return;
86
87 QWaylandQtShellChrome *currentActive = d->m_chromes.isEmpty() ? nullptr : d->m_chromes.first();
88
89 d->m_chromes.prepend(chrome);
90 chrome->activate();
91
92 if (currentActive != nullptr)
93 currentActive->deactivate();
94
95 connect(chrome, &QWaylandQtShellChrome::activated, this, &QWaylandQtShell::chromeActivated);
96 connect(chrome, &QWaylandQtShellChrome::deactivated, this, &QWaylandQtShell::chromeDeactivated);
97}
98
99void QWaylandQtShell::unregisterChrome(QWaylandQtShellChrome *chrome)
100{
101 Q_D(QWaylandQtShell);
102
103 chrome->disconnect(this);
104 int index = d->m_chromes.indexOf(chrome);
105 if (index >= 0) {
106 d->m_chromes.removeAt(index);
107 if (index == 0 && d->m_chromes.size() > 0)
108 d->m_chromes.at(0)->activate();
109 }
110}
111
112void QWaylandQtShell::chromeActivated()
113{
114 QWaylandQtShellChrome *c = qobject_cast<QWaylandQtShellChrome *>(sender());
115 if (c != nullptr) {
116 moveChromeToFront(c);
117 }
118}
119
120void QWaylandQtShell::chromeDeactivated()
121{
122 Q_D(QWaylandQtShell);
123 QWaylandQtShellChrome *c = qobject_cast<QWaylandQtShellChrome *>(sender());
124 if (d->m_chromes.size() > 1 && d->m_chromes.at(0) == c) {
125 d->m_chromes.move(0, 1);
126 d->m_chromes.at(0)->activate();
127 } else if (d->m_chromes.size() == 1) { // One window must be active
128 d->m_chromes.at(0)->activate();
129 }
130}
131
132void QWaylandQtShell::initialize()
133{
134 Q_D(QWaylandQtShell);
135 QWaylandCompositorExtensionTemplate::initialize();
136
137 QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
138 if (!compositor) {
139 qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandQtShell";
140 return;
141 }
142
143 d->init(compositor->display(), 1);
144}
145
146const struct wl_interface *QWaylandQtShell::interface()
147{
148 return QWaylandQtShellPrivate::interface();
149}
150
151/*!
152 * \internal
153 */
154QByteArray QWaylandQtShell::interfaceName()
155{
156 return QWaylandQtShellPrivate::interfaceName();
157}
158
159/*!
160 * \qmlsignal void QtShell::qtShellSurfaceRequested(WaylandSurface surface, WaylandResource resource)
161 *
162 * This signal is emitted when the client has requested a QtShellSurface to be associated
163 * with \a surface. The handler for this signal is expected to create the QtShellSurface for
164 * \a resource and initialize it within the scope of the signal emission. If no QtShellSurface is
165 * created, a default one will be created instead.
166 */
167
168/*!
169 * \qmlsignal void QtShell::qtShellSurfaceCreated(QtShellSurface *qtShellSurface)
170 *
171 * This signal is emitted when an QtShellSurface has been created. The supplied \a qtShellSurface is
172 * most commonly used to instantiate a ShellSurfaceItem.
173 */
174
175QWaylandQtShellPrivate::QWaylandQtShellPrivate()
176{
177}
178
179void QWaylandQtShellPrivate::unregisterQtShellSurface(QWaylandQtShellSurface *qtShellSurface)
180{
181 Q_UNUSED(qtShellSurface)
182}
183
184void QWaylandQtShellPrivate::zqt_shell_v1_surface_create(QtWaylandServer::zqt_shell_v1::Resource *resource, wl_resource *surfaceResource, uint32_t id)
185{
186 Q_Q(QWaylandQtShell);
187 QWaylandSurface *surface = QWaylandSurface::fromResource(surfaceResource);
188
189 if (!surface->setRole(QWaylandQtShellSurface::role(), resource->handle, ZQT_SHELL_V1_ERROR_ROLE))
190 return;
191
192 QWaylandResource qtShellSurfaceResource(wl_resource_create(resource->client(), &zqt_shell_surface_v1_interface,
193 wl_resource_get_version(resource->handle), id));
194
195 emit q->qtShellSurfaceRequested(surface, qtShellSurfaceResource);
196
197 QWaylandQtShellSurface *qtShellSurface = QWaylandQtShellSurface::fromResource(qtShellSurfaceResource.resource());
198
199 if (!qtShellSurface)
200 qtShellSurface = new QWaylandQtShellSurface(q, surface, qtShellSurfaceResource);
201
202 emit q->qtShellSurfaceCreated(qtShellSurface);
203}
204
205QWaylandSurfaceRole QWaylandQtShellSurfacePrivate::s_role("qt_shell_surface");
206
207/*!
208 * \qmltype QtShellSurface
209 * \nativetype QWaylandQtShellSurface
210 * \inqmlmodule QtWayland.Compositor.QtShell
211 * \since 6.3
212 * \brief Provides a simple way to identify and resize a surface.
213 *
214 * This type is part of the \l{QtShell} extension and provides a way to extend
215 * the functionality of an existing WaylandSurface with window management functionality.
216 *
217 * The QtShellSurface type holds the core functionality needed to create a compositor that supports
218 * the QtShell extension. It can be used directly, or via the QtShellChrome type, depending on what
219 * the needs of the compositor are. The QtShellChrome type has default behaviors and convenience
220 * APIs for working with QtShellSurface objects.
221 */
222
223/*!
224 \qmlsignal void QtShellSurface::startMove()
225
226 The client has requested an interactive move operation in the compositor by calling
227 \l{QWindow::startSystemMove()}.
228
229 \sa capabilities
230*/
231
232/*!
233 \qmlsignal void QtShellSurface::startResize(enum edges)
234
235 The client has requested an interactive resize operation in the compositor by calling
236 \l{QWindow::startSystemResize()}.
237
238 The \a edges provides information about which edge of the window should be moved during the
239 resize. It is a mask of the following values:
240 \list
241 \li Qt.TopEdge
242 \li Qt.LeftEdge
243 \li Qt.RightEdge
244 \li Qt.BottomEdge
245 \endlist
246
247 \sa capabilities
248*/
249
250QWaylandQtShellSurface::QWaylandQtShellSurface()
251 : QWaylandShellSurfaceTemplate<QWaylandQtShellSurface>(*new QWaylandQtShellSurfacePrivate())
252{
253}
254
255QWaylandQtShellSurface::QWaylandQtShellSurface(QWaylandQtShell *application, QWaylandSurface *surface, const QWaylandResource &resource)
256 : QWaylandShellSurfaceTemplate<QWaylandQtShellSurface>(*new QWaylandQtShellSurfacePrivate())
257{
258 initialize(application, surface, resource);
259}
260
261/*!
262 * \qmlmethod void QtShellSurface::initialize(QtShell qtShell, WaylandSurface surface, WaylandResource resource)
263 *
264 * Initializes the QtShellSurface, associating it with the given \a qtShell, \a surface, and
265 * \a resource.
266 */
267void QWaylandQtShellSurface::initialize(QWaylandQtShell *qtShell, QWaylandSurface *surface, const QWaylandResource &resource)
268{
269 Q_D(QWaylandQtShellSurface);
270
271 d->m_qtShell = qtShell;
272 d->m_surface = surface;
273
274 connect(d->m_surface, &QWaylandSurface::damaged, this, &QWaylandQtShellSurface::surfaceCommitted);
275
276 d->init(resource.resource());
277 setExtensionContainer(surface);
278
279 emit surfaceChanged();
280
281 QWaylandCompositorExtension::initialize();
282}
283
284/*!
285 * \qmlproperty WaylandSurface QtShellSurface::surface
286 *
287 * This property holds the surface associated with this QtShellSurface.
288 */
289
290/*!
291 * \property QWaylandQtShellSurface::surface
292 *
293 * This property holds the surface associated with this QWaylandQtShellSurface.
294 */
295QWaylandSurface *QWaylandQtShellSurface::surface() const
296{
297 Q_D(const QWaylandQtShellSurface);
298 return d->m_surface;
299}
300
301QWaylandQtShell *QWaylandQtShellSurface::shell() const
302{
303 Q_D(const QWaylandQtShellSurface);
304 return d->m_qtShell;
305}
306
307/*!
308 * \qmlproperty point QtShellSurface::windowPosition
309 *
310 * This property holds the position of the shell surface relative to its output.
311 */
312
313/*!
314 * \property QWaylandQtShellSurface::windowPosition
315 *
316 * This property holds the position of the shell surface relative to its output.
317 */
318QPoint QWaylandQtShellSurface::windowPosition() const
319{
320 Q_D(const QWaylandQtShellSurface);
321 return d->m_windowGeometry.topLeft();
322}
323
324void QWaylandQtShellSurface::setWindowPosition(const QPoint &position)
325{
326 Q_D(QWaylandQtShellSurface);
327
328 // We don't care about the ack in this case, so use UINT_MAX as serial
329 d->send_set_position(UINT32_MAX, position.x(), position.y());
330 d->send_configure(UINT32_MAX);
331
332 d->m_windowGeometry.moveTopLeft(position);
333 d->m_positionSet = true;
334 emit positionAutomaticChanged();
335 emit windowGeometryChanged();
336}
337
338/*!
339 * \qmlproperty rect QtShellSurface::windowGeometry
340 *
341 * This property holds the window geometry of the shell surface.
342 */
343
344/*!
345 * \property QWaylandQtShellSurface::windowGeometry
346 *
347 * This property holds the window geometry of the shell surface.
348 */
349QRect QWaylandQtShellSurface::windowGeometry() const
350{
351 Q_D(const QWaylandQtShellSurface);
352 return d->m_windowGeometry;
353}
354
355/*!
356 * \qmlproperty size QtShellSurface::minimumSize
357 *
358 * The minimum size of the window if the client has specified one. Otherwise an invalid size.
359 */
360
361/*!
362 * \property QWaylandQtShellSurface::minimumSize
363 *
364 * The minimum size of the window if the client has specified one. Otherwise an
365 * invalid size.
366 */
367QSize QWaylandQtShellSurface::minimumSize() const
368{
369 Q_D(const QWaylandQtShellSurface);
370 return d->m_minimumSize;
371}
372
373/*!
374 * \qmlproperty size QtShellSurface::maximumSize
375 *
376 * The maximum size of the window if the client has specified one. Otherwise an invalid size.
377 */
378
379/*!
380 * \property QWaylandQtShellSurface::maximumSize
381 *
382 * The maximum size of the window if the client has specified one. Otherwise an
383 * invalid size.
384 */
385QSize QWaylandQtShellSurface::maximumSize() const
386{
387 Q_D(const QWaylandQtShellSurface);
388 return d->m_maximumSize;
389}
390
391/*!
392 * \qmlmethod void QtShellSurface::requestWindowGeometry(int windowState, rect windowGeometry)
393 *
394 * Requests a new \a windowState and \a windowGeometry for the QtShellSurface. The state and
395 * geometry is updated when the client has acknowledged the request (at which point it is safe to
396 * assume that the surface's buffer has been resized if necessary).
397 */
398void QWaylandQtShellSurface::requestWindowGeometry(uint windowState, const QRect &windowGeometry)
399{
400 Q_D(QWaylandQtShellSurface);
401 if (!windowGeometry.isValid())
402 return;
403
404 d->configure(windowState, windowGeometry);
405}
406
407void QWaylandQtShellSurfacePrivate::configure(uint windowState, const QRect &newGeometry)
408{
409 QWaylandCompositor *compositor = m_surface != nullptr ? m_surface->compositor() : nullptr;
410 if (!compositor) {
411 qWarning() << "Failed to find QWaylandCompositor when configuring QWaylandQtShell";
412 return;
413 }
414
415 uint32_t serial = compositor->nextSerial();
416 m_pendingConfigures[serial] = qMakePair(windowState, newGeometry);
417
418 send_set_position(serial, newGeometry.x(), newGeometry.y());
419 send_resize(serial, newGeometry.width(), newGeometry.height());
420 send_set_window_state(serial, windowState & ~Qt::WindowActive);
421 send_configure(serial);
422}
423
424void QWaylandQtShellSurface::setFrameMargins(const QMargins &margins)
425{
426 Q_D(QWaylandQtShellSurface);
427 if (d->m_frameMargins == margins)
428 return;
429
430 d->m_frameMargins = margins;
431 d->updateFrameMargins();
432
433 emit frameMarginChanged();
434}
435
436/*!
437 * \qmlproperty int QtShellSurface::frameMarginLeft
438 *
439 * This holds the window frame margin to the left of the surface.
440 */
441
442/*!
443 * \property QWaylandQtShellSurface::frameMarginLeft
444 *
445 * This property holds the window frame margin to the left of the surface.
446 */
447void QWaylandQtShellSurface::setFrameMarginLeft(int left)
448{
449 Q_D(QWaylandQtShellSurface);
450 if (d->m_frameMargins.left() == left)
451 return;
452
453 d->m_frameMargins.setLeft(left);
454 d->updateFrameMargins();
455
456 emit frameMarginChanged();
457}
458
459int QWaylandQtShellSurface::frameMarginLeft() const
460{
461 Q_D(const QWaylandQtShellSurface);
462 return d->m_frameMargins.left();
463}
464
465/*!
466 * \qmlproperty int QtShellSurface::frameMarginRight
467 *
468 * This holds the window frame margin to the right of the surface.
469 */
470
471/*!
472 * \property QWaylandQtShellSurface::frameMarginRight
473 *
474 * This property holds the window frame margin to the right of the surface.
475 */
476void QWaylandQtShellSurface::setFrameMarginRight(int right)
477{
478 Q_D(QWaylandQtShellSurface);
479 if (d->m_frameMargins.right() == right)
480 return;
481
482 d->m_frameMargins.setRight(right);
483 d->updateFrameMargins();
484
485 emit frameMarginChanged();
486}
487
488int QWaylandQtShellSurface::frameMarginRight() const
489{
490 Q_D(const QWaylandQtShellSurface);
491 return d->m_frameMargins.right();
492}
493
494/*!
495 * \qmlproperty int QtShellSurface::frameMarginTop
496 *
497 * This holds the window frame margin above the surface.
498 */
499
500/*!
501 * \property QWaylandQtShellSurface::frameMarginTop
502 *
503 * This property holds the window frame margin above the surface.
504 */
505void QWaylandQtShellSurface::setFrameMarginTop(int top)
506{
507 Q_D(QWaylandQtShellSurface);
508 if (d->m_frameMargins.top() == top)
509 return;
510 d->m_frameMargins.setTop(top);
511 d->updateFrameMargins();
512
513 emit frameMarginChanged();
514}
515
516int QWaylandQtShellSurface::frameMarginTop() const
517{
518 Q_D(const QWaylandQtShellSurface);
519 return d->m_frameMargins.top();
520}
521
522/*!
523 * \qmlproperty int QtShellSurface::frameMarginBottom
524 *
525 * This holds the window frame margin below the surface.
526 */
527
528/*!
529 * \property QWaylandQtShellSurface::frameMarginBottom
530 *
531 * This property holds the window frame margin below the surface.
532 */
533void QWaylandQtShellSurface::setFrameMarginBottom(int bottom)
534{
535 Q_D(QWaylandQtShellSurface);
536 if (d->m_frameMargins.bottom() == bottom)
537 return;
538 d->m_frameMargins.setBottom(bottom);
539 d->updateFrameMargins();
540
541 emit frameMarginChanged();
542}
543
544/*!
545 * \property QWaylandQtShellSurface::positionAutomatic
546 *
547 * This property holds whether the window position is automatically determined
548 * by the compositor.
549 *
550 * The value is \c true if the position has not been explicitly set; otherwise
551 * \c false.
552 */
553bool QWaylandQtShellSurface::positionAutomatic() const
554{
555 Q_D(const QWaylandQtShellSurface);
556 return !d->m_positionSet;
557}
558
559int QWaylandQtShellSurface::frameMarginBottom() const
560{
561 Q_D(const QWaylandQtShellSurface);
562 return d->m_frameMargins.bottom();
563}
564
565/*!
566 * \qmlproperty int QtShellSurface::windowFlags
567 *
568 * This property holds the window flags of the QtShellSurface.
569 */
570
571/*!
572 * \property QWaylandQtShellSurface::windowFlags
573 *
574 * This property holds the window flags of the QWaylandQtShellSurface.
575 */
576uint QWaylandQtShellSurface::windowFlags() const
577{
578 Q_D(const QWaylandQtShellSurface);
579 return d->m_windowFlags;
580}
581
582/*!
583 * \qmlmethod void QtShellSurface::sendClose()
584 *
585 * Requests that the client application closes itself.
586 */
587void QWaylandQtShellSurface::sendClose()
588{
589 Q_D(QWaylandQtShellSurface);
590 d->send_close();
591}
592
593/*!
594 * \qmlproperty string QtShellSurface::windowTitle
595 *
596 * This property holds the window title of the QtShellSurface.
597 */
598
599/*!
600 * \property QWaylandQtShellSurface::windowTitle
601 *
602 * This property holds the window title of the QWaylandQtShellSurface.
603 */
604QString QWaylandQtShellSurface::windowTitle() const
605{
606 Q_D(const QWaylandQtShellSurface);
607 return d->m_windowTitle;
608}
609
610/*!
611 * \qmlproperty bool QtShellSurface::active
612 *
613 * This property holds whether the surface is currently considered active.
614 *
615 * \note There are no restrictions in QtShellSurface that prevents multiple surfaces from being
616 * active simultaneously. Such logic must either be implemented by the compositor itself, or by
617 * using the QtShellChrome type, which will automatically manage the activation state of surfaces.
618 */
619
620/*!
621 * \property QWaylandQtShellSurface::active
622 *
623 * This property holds whether the surface is currently considered active.
624 *
625 * \note There are no restrictions in QWaylandQtShellSurface that prevent
626 * multiple surfaces from being active simultaneously. Such logic must
627 * either be implemented by the compositor itself, or by using the
628 * QWaylandQtShellChrome type, which will automatically manage the
629 * activation state of surfaces.
630 */
631void QWaylandQtShellSurface::setActive(bool active)
632{
633 Q_D(QWaylandQtShellSurface);
634 if (d->m_active == active)
635 return;
636
637 d->m_active = active;
638 QWaylandCompositor *compositor = d->m_surface ? d->m_surface->compositor() : nullptr;
639 QWaylandSeat *seat = compositor ? compositor->defaultSeat() : nullptr;
640 if (seat && active)
641 seat->setKeyboardFocus(surface());
642 emit activeChanged();
643}
644
645bool QWaylandQtShellSurface::active() const
646{
647 Q_D(const QWaylandQtShellSurface);
648 return d->m_active;
649}
650
651/*!
652 * \qmlproperty enum QtShellSurface::capabilities
653 *
654 * This property holds the capabilities of the compositor. By default, no special capabilities are
655 * enabled.
656 *
657 * \list
658 * \li QtShellSurface.InteractiveMove The client can trigger a server-side interactive move
659 * operation using \l{QWindow::startSystemMove()}. The compositor will be notified of this
660 * through the \l{startMove()} signal.
661 * \li QtShellSurface.InteractiveResize The client can trigger a server-side interactive resize
662 * operation using \l{QWindow::startSystemResize()}. The compositor will be notified of this
663 * through the \l{startResize()} signal.
664 * \endlist
665 */
666
667/*!
668 * \property QWaylandQtShellSurface::capabilities
669 *
670 * This property holds the capabilities of the compositor. By default, no
671 * special capabilities are enabled.
672 *
673 * \list
674 * \li QWaylandQtShellSurface::InteractiveMove The client can trigger a
675 * server-side interactive move operation using
676 * QWindow::startSystemMove(). The compositor will be notified of this
677 * through the startMove() signal.
678 * \li QWaylandQtShellSurface::InteractiveResize The client can trigger a
679 * server-side interactive resize operation using
680 * QWindow::startSystemResize(). The compositor will be notified of this
681 * through the startResize() signal.
682 * \endlist
683 */
684void QWaylandQtShellSurface::setCapabilities(CapabilityFlags capabilities)
685{
686 Q_D(QWaylandQtShellSurface);
687 if (d->m_capabilities == capabilities)
688 return;
689
690 d->m_capabilities = capabilities;
691 d->send_set_capabilities(capabilities);
692
693 emit capabilitiesChanged();
694}
695
696QWaylandQtShellSurface::CapabilityFlags QWaylandQtShellSurface::capabilities() const
697{
698 Q_D(const QWaylandQtShellSurface);
699 return d->m_capabilities;
700}
701
702/*!
703 * \qmlproperty int QtShellSurface::windowState
704 *
705 * This property holds the window state of the QtShellSurface.
706 *
707 * \note When \l{requestWindowGeometry()} is called to update state of the surface, the
708 * \c windowState property will not be updated until the client has acknowledged the state change.
709 */
710
711/*!
712 * \property QWaylandQtShellSurface::windowState
713 *
714 * This property holds the window state of the QWaylandQtShellSurface.
715 *
716 * \note When requestWindowGeometry() is called to update state of the surface,
717 * the windowState property will not be updated until the client has
718 * acknowledged the state change.
719 */
720uint QWaylandQtShellSurface::windowState() const
721{
722 Q_D(const QWaylandQtShellSurface);
723 return d->m_windowState;
724}
725
726void QWaylandQtShellSurface::surfaceCommitted()
727{
728 Q_D(QWaylandQtShellSurface);
729 if (d->m_lastAckedConfigure < UINT32_MAX) {
730 QRect targetRect = d->m_windowGeometry;
731 uint windowState = d->m_windowState;
732 for (auto it = d->m_pendingConfigures.begin(); it != d->m_pendingConfigures.end(); ) {
733 if (it.key() == d->m_lastAckedConfigure) {
734 targetRect = it.value().second;
735 windowState = it.value().first;
736 }
737
738 if (it.key() <= d->m_lastAckedConfigure)
739 it = d->m_pendingConfigures.erase(it);
740 else
741 break;
742 }
743
744 if (d->m_windowState != windowState) {
745 d->m_windowState = windowState;
746 emit windowStateChanged();
747 }
748
749 if (d->m_windowGeometry != targetRect) {
750 d->m_windowGeometry = targetRect;
751 d->m_positionSet = true;
752 emit positionAutomaticChanged();
753 emit windowGeometryChanged();
754 }
755
756 d->m_lastAckedConfigure = UINT32_MAX;
757 d->m_pendingPosition = QPoint{};
758 d->m_pendingPositionValid = false;
759 d->m_pendingSize = QSize{};
760 } else {
761 QRect oldRect = d->m_windowGeometry;
762 if (d->m_pendingPositionValid) {
763 d->m_windowGeometry.moveTopLeft(d->m_pendingPosition);
764 d->m_pendingPosition = QPoint{};
765 d->m_pendingPositionValid = false;
766 d->m_positionSet = true;
767 emit positionAutomaticChanged();
768 }
769
770 if (d->m_pendingSize.isValid()) {
771 d->m_windowGeometry.setSize(d->m_pendingSize);
772 d->m_pendingSize = QSize{};
773 }
774
775 if (d->m_windowGeometry != oldRect)
776 emit windowGeometryChanged();
777 }
778}
779
780/*!
781 * \internal
782 * Returns the Wayland interface for the QWaylandQtShellSurface.
783 */
784const wl_interface *QWaylandQtShellSurface::interface()
785{
786 return QWaylandQtShellSurfacePrivate::interface();
787}
788
789QByteArray QWaylandQtShellSurface::interfaceName()
790{
791 return QWaylandQtShellSurfacePrivate::interfaceName();
792}
793
794/*!
795 * \internal
796 * Returns the surface role for the QWaylandQtShellSurface.
797 */
798QWaylandSurfaceRole *QWaylandQtShellSurface::role()
799{
800 return &QWaylandQtShellSurfacePrivate::s_role;
801}
802
803/*!
804 * \internal
805 * Returns the QWaylandQtShellSurface corresponding to the \a resource.
806 */
807QWaylandQtShellSurface *QWaylandQtShellSurface::fromResource(wl_resource *resource)
808{
809 if (auto p = QtWayland::fromResource<QWaylandQtShellSurfacePrivate *>(resource))
810 return p->q_func();
811 return nullptr;
812}
813
814#if QT_CONFIG(wayland_compositor_quick)
815QWaylandQuickShellIntegration *QWaylandQtShellSurface::createIntegration(QWaylandQuickShellSurfaceItem *item)
816{
817 return new QtWayland::QtShellIntegration(item);
818}
819#endif
820
821/*!
822 * \internal
823 */
824void QWaylandQtShellSurface::initialize()
825{
826 QWaylandShellSurfaceTemplate::initialize();
827}
828
829QWaylandQtShellSurfacePrivate::QWaylandQtShellSurfacePrivate()
830{
831}
832
833void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_ack_configure(Resource *resource, uint32_t serial)
834{
835 Q_UNUSED(resource);
836 Q_Q(QWaylandQtShellSurface);
837 if (serial < UINT32_MAX)
838 m_lastAckedConfigure = serial;
839
840 // Fake a surface commit because we won't get one as long as the window is unexposed
841 if (m_windowState & Qt::WindowMinimized)
842 q->surfaceCommitted();
843}
844
845void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_reposition(Resource *resource, int32_t x, int32_t y)
846{
847 Q_UNUSED(resource);
848
849 m_pendingPosition = QPoint(x, y);
850 m_pendingPositionValid = true;
851 m_lastAckedConfigure = UINT32_MAX;
852}
853
854void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_size(Resource *resource, int32_t width, int32_t height)
855{
856 Q_UNUSED(resource);
857
858 m_pendingSize = QSize(width, height);
859 m_lastAckedConfigure = UINT32_MAX;
860}
861
862void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_minimum_size(Resource *resource, int32_t width, int32_t height)
863{
864 Q_UNUSED(resource);
865 Q_Q(QWaylandQtShellSurface);
866 m_minimumSize = QSize{width, height};
867 emit q->minimumSizeChanged();
868}
869
870void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_maximum_size(Resource *resource, int32_t width, int32_t height)
871{
872 Q_UNUSED(resource);
873 Q_Q(QWaylandQtShellSurface);
874 m_maximumSize = QSize{width, height};
875 emit q->maximumSizeChanged();
876}
877
878void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_destroy_resource(QtWaylandServer::zqt_shell_surface_v1::Resource *resource)
879{
880 Q_UNUSED(resource);
881 Q_Q(QWaylandQtShellSurface);
882 QWaylandQtShellPrivate::get(m_qtShell)->unregisterQtShellSurface(q);
883 delete q;
884}
885
886void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_destroy(QtWaylandServer::zqt_shell_surface_v1::Resource *resource)
887{
888 wl_resource_destroy(resource->handle);
889}
890
891void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_window_flags(Resource *resource, uint32_t flags)
892{
893 Q_UNUSED(resource);
894 Q_Q(QWaylandQtShellSurface);
895 m_windowFlags = flags;
896 emit q->windowFlagsChanged();
897}
898
899void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_change_window_state(Resource *resource, uint32_t state)
900{
901 Q_UNUSED(resource);
902 Q_Q(QWaylandQtShellSurface);
903 uint oldWindowState = m_windowState;
904 m_windowState = state & ~Qt::WindowActive;
905
906 if (oldWindowState != m_windowState)
907 emit q->windowStateChanged();
908}
909
910void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_start_system_resize(Resource *resource, uint32_t serial, uint32_t edge)
911{
912 Q_UNUSED(resource);
913 Q_UNUSED(serial);
914 Q_Q(QWaylandQtShellSurface);
915 emit q->startResize(Qt::Edges(edge));
916}
917
918void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_start_system_move(Resource *resource, uint32_t serial)
919{
920 Q_UNUSED(resource);
921 Q_UNUSED(serial);
922 Q_Q(QWaylandQtShellSurface);
923 emit q->startMove();
924}
925
926void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_set_window_title(Resource *resource,
927 const QString &title)
928{
929 Q_UNUSED(resource);
930 Q_Q(QWaylandQtShellSurface);
931 m_windowTitle = title;
932 emit q->windowTitleChanged();
933}
934
935void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_request_activate(Resource *resource)
936
937{
938 Q_UNUSED(resource);
939 Q_Q(QWaylandQtShellSurface);
940 q->setActive(true);
941
942 if (m_surface) {
943 auto view = m_surface->primaryView();
944 auto item = view ? qobject_cast<QWaylandQuickItem *>(view->renderObject()) : nullptr;
945 if (item)
946 item->forceActiveFocus();
947 }
948}
949
950void QWaylandQtShellSurfacePrivate::updateFrameMargins()
951{
952 send_set_frame_margins(m_frameMargins.left(), m_frameMargins.right(),
953 m_frameMargins.top(), m_frameMargins.bottom());
954}
955
956
957void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_raise(Resource *resource)
958{
959 Q_UNUSED(resource);
960 Q_Q(QWaylandQtShellSurface);
961 emit q->raiseRequested();
962}
963
964void QWaylandQtShellSurfacePrivate::zqt_shell_surface_v1_lower(Resource *resource)
965{
966 Q_UNUSED(resource);
967 Q_Q(QWaylandQtShellSurface);
968 emit q->lowerRequested();
969}
970
971QT_END_NAMESPACE
972
973#include "moc_qwaylandqtshell_p.cpp"