1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qwaylandqtshellchrome.h"
5#include "qwaylandqtshellchrome_p.h"
6#include "qwaylandqtshell.h"
7
8#include <QtWaylandCompositor/qwaylandquickshellsurfaceitem.h>
9
10QT_BEGIN_NAMESPACE
11
12QPointF QWaylandQtShellChromePrivate::constrainPoint(const QPointF &point) const
13{
14 float x0 = maximizedRect.left();
15 float y0 = maximizedRect.top();
16 float x1 = maximizedRect.right();
17 float y1 = maximizedRect.bottom();
18 return QPoint(qBound(min: x0, val: point.x(), max: x1),
19 qBound(min: y0, val: point.y(), max: y1));
20}
21
22void QWaylandQtShellChromePrivate::updateDecorationInteraction(quint8 flags,
23 const QQuickHandlerPoint &centroid)
24{
25 if (shellSurface == nullptr)
26 return;
27
28 if (decorationInteraction == quint8(DecorationInteraction::None)) {
29 decorationInteraction = flags;
30 decorationInteractionPosition = centroid.scenePressPosition();
31 decorationInteractionGeometry = shellSurface->windowGeometry();
32 }
33
34 if (decorationInteraction != flags)
35 return;
36
37 QPointF position = constrainPoint(point: centroid.scenePosition());
38 float dx = position.x() - decorationInteractionPosition.x();
39 float dy = position.y() - decorationInteractionPosition.y();
40
41 float minWidth = qMax(a: 0, b: shellSurface->minimumSize().width());
42 float minHeight = qMax(a: 0, b: shellSurface->minimumSize().height());
43
44 float maxWidth = shellSurface->maximumSize().width();
45 float maxHeight = shellSurface->maximumSize().height();
46
47 float minX = maxWidth >= 0.0f
48 ? decorationInteractionGeometry.right() - maxWidth
49 : -FLT_MAX;
50 float minY = maxHeight >= 0.0f
51 ? decorationInteractionGeometry.bottom() - maxHeight
52 : -FLT_MAX;
53 float maxX = maxWidth >= 0
54 ? decorationInteractionGeometry.left() + maxWidth
55 : FLT_MAX;
56 float maxY = maxHeight >= 0.0f
57 ? decorationInteractionGeometry.top() + maxHeight
58 : FLT_MAX;
59
60 float newLeft = decorationInteractionGeometry.left();
61 if (flags & quint8(DecorationInteraction::WestBound)) {
62 newLeft = qBound(min: minX,
63 val: newLeft + dx,
64 max: float(decorationInteractionGeometry.right() - minWidth));
65 }
66
67 float newTop = decorationInteractionGeometry.top();
68 if (flags & quint8(DecorationInteraction::NorthBound)) {
69 newTop = qBound(min: minY,
70 val: newTop + dy,
71 max: decorationInteractionGeometry.bottom() + minHeight);
72 }
73
74 float newRight = decorationInteractionGeometry.right();
75 if (flags & quint8(DecorationInteraction::EastBound)) {
76 newRight = qBound(min: decorationInteractionGeometry.left() + minWidth,
77 val: newRight + dx,
78 max: maxX);
79 }
80
81 float newBottom = decorationInteractionGeometry.bottom();
82 if (flags & quint8(DecorationInteraction::SouthBound)) {
83 newBottom = qBound(min: decorationInteractionGeometry.top() + minHeight,
84 val: newBottom + dy,
85 max: maxY);
86 }
87
88 shellSurface->requestWindowGeometry(windowState: shellSurface->windowState(),
89 windowGeometry: QRect(int(newLeft), int(newTop),
90 int(newRight - newLeft), int(newBottom - newTop)));
91}
92
93/*!
94 * \qmltype QtShellChrome
95 * \instantiates QWaylandQtShellChrome
96 * \inqmlmodule QtWayland.Compositor.QtShell
97 * \since 6.3
98 * \brief Provides default window manager functionality for use with the \c qt-shell extension.
99 *
100 * The QtShellChrome is a convenience type that can be used to provide window manager functionality
101 * to the interaction with clients over the \c qt-shell
102 * \l{Shell Extensions - Qt Wayland Compositor}{shell extension protocol}.
103 *
104 * Given a ShellSurfaceItem with an associated QtShellSurface, the item will automatically adapt
105 * its size to match the surface. It will also provide automatic handling of:
106 * \list
107 * \li Window states, such as maximized, minimized and fullscreen.
108 * \li Window activation.
109 * \li Window resizing using with resize handles (if the appropriate properties are set.)
110 * \li Window repositioning using title bar interaction (if the \l titleBar property is set.)
111 * \endlist
112 *
113 * The QtShellChrome is intended to be used together with QtShell and QtShellSurface.
114 *
115 * \sa {QtShell Compositor}
116 */
117QWaylandQtShellChrome::QWaylandQtShellChrome(QQuickItem *parent)
118 : QQuickItem(*new QWaylandQtShellChromePrivate{}, parent)
119{
120 init();
121}
122
123QWaylandQtShellChrome::QWaylandQtShellChrome(QWaylandQtShellChromePrivate &dd,
124 QQuickItem *parent)
125 : QQuickItem(dd, parent)
126{
127 init();
128}
129
130QWaylandQtShellChrome::~QWaylandQtShellChrome()
131{
132 Q_D(QWaylandQtShellChrome);
133 if (d->shell != nullptr)
134 d->shell->unregisterChrome(chrome: this);
135}
136
137void QWaylandQtShellChrome::init()
138{
139 connect(sender: this, signal: &QWaylandQtShellChrome::currentWindowStateChanged,
140 context: this, slot: &QWaylandQtShellChrome::windowMetaInfoChanged);
141
142 connect(sender: this, signal: &QWaylandQtShellChrome::currentWindowFlagsChanged,
143 context: this, slot: &QWaylandQtShellChrome::windowMetaInfoChanged);
144
145 connect(sender: this, signal: &QWaylandQtShellChrome::windowMetaInfoChanged,
146 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
147
148 connect(sender: this, signal: &QWaylandQtShellChrome::leftResizeHandleChanged,
149 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
150
151 connect(sender: this, signal: &QWaylandQtShellChrome::rightResizeHandleChanged,
152 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
153
154 connect(sender: this, signal: &QWaylandQtShellChrome::topResizeHandleChanged,
155 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
156
157 connect(sender: this, signal: &QWaylandQtShellChrome::bottomResizeHandleChanged,
158 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
159
160 connect(sender: this, signal: &QWaylandQtShellChrome::topLeftResizeHandleChanged,
161 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
162
163 connect(sender: this, signal: &QWaylandQtShellChrome::bottomLeftResizeHandleChanged,
164 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
165
166 connect(sender: this, signal: &QWaylandQtShellChrome::topRightResizeHandleChanged,
167 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
168
169 connect(sender: this, signal: &QWaylandQtShellChrome::bottomRightResizeHandleChanged,
170 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
171}
172
173/*!
174 * \qmlmethod void QtShellChrome::toggleFullScreen()
175 *
176 * Toggles between fullscreen and normal window states. This method also clears the minimized
177 * or maximized window states if either is set.
178 */
179void QWaylandQtShellChrome::toggleFullScreen()
180{
181 Q_D(QWaylandQtShellChrome);
182 if (d->shellSurface == nullptr)
183 return;
184
185 uint newState;
186 if ((d->shellSurface->windowState() & Qt::WindowFullScreen) == Qt::WindowFullScreen)
187 newState = d->currentState & ~Qt::WindowFullScreen;
188 else
189 newState = d->currentState | Qt::WindowFullScreen;
190
191 if ((newState & (Qt::WindowMinimized | Qt::WindowMaximized)) != 0)
192 newState &= ~(Qt::WindowMinimized | Qt::WindowMaximized);
193
194 setWindowState(newState);
195}
196
197/*!
198 * \qmlmethod void QtShellChrome::toggleMaximized()
199 *
200 * Toggles between maximized and normal states. This method also clears the minimized
201 * window state if it is set.
202 */
203void QWaylandQtShellChrome::toggleMaximized()
204{
205 Q_D(QWaylandQtShellChrome);
206 if (d->shellSurface == nullptr)
207 return;
208
209 uint newState;
210 if ((d->shellSurface->windowState() & Qt::WindowMaximized) == Qt::WindowMaximized)
211 newState = d->currentState & ~Qt::WindowMaximized;
212 else
213 newState = d->currentState | Qt::WindowMaximized;
214
215 if ((newState & Qt::WindowMinimized) == Qt::WindowMinimized)
216 newState &= ~Qt::WindowMinimized;
217
218 setWindowState(newState);
219}
220
221/*!
222 * \qmlmethod void QtShellChrome::toggleMinimized()
223 *
224 * Toggles between minimized and normal states. This method also clears the maximized
225 * window state if it is set.
226 */
227void QWaylandQtShellChrome::toggleMinimized()
228{
229 Q_D(QWaylandQtShellChrome);
230 if (d->shellSurface == nullptr)
231 return;
232
233 uint newState;
234 if ((d->shellSurface->windowState() & Qt::WindowMinimized) == Qt::WindowMinimized)
235 newState = d->currentState & ~Qt::WindowMinimized;
236 else
237 newState = d->currentState | Qt::WindowMinimized;
238
239 if ((newState & Qt::WindowMaximized) == Qt::WindowMaximized)
240 newState &= ~Qt::WindowMaximized;
241
242 setWindowState(newState);
243}
244
245/*!
246 * \qmlproperty ShellSurfaceItem QtShellChrome::shellSurfaceItem
247 *
248 * This property holds the shell surface item associated with this QtShellChrome. It will
249 * in turn manage the \c shellSurface of this item. The \c shellSurface of the item is expected to
250 * be of the type QtShellSurface.
251 *
252 * \qml
253 * QtShellChrome {
254 * id: chrome
255 * ShellSurfaceItem {
256 * id: sfi
257 * anchors.fill: parent
258 * moveItem: chrome
259 * }
260 * shellSurfaceItem: sfi
261 * }
262 * \endqml
263 */
264void QWaylandQtShellChrome::setShellSurfaceItem(QWaylandQuickShellSurfaceItem *shellSurfaceItem)
265{
266 Q_D(QWaylandQtShellChrome);
267 if (d->shellSurfaceItem == shellSurfaceItem)
268 return;
269
270 if (d->shellSurfaceItem != nullptr)
271 d->shellSurfaceItem->disconnect(receiver: this);
272
273 d->shellSurfaceItem = shellSurfaceItem;
274
275 if (d->shellSurfaceItem != nullptr) {
276 connect(sender: d->shellSurfaceItem, signal: &QWaylandQuickShellSurfaceItem::shellSurfaceChanged,
277 context: this, slot: &QWaylandQtShellChrome::updateShellSurface);
278 connect(sender: d->shellSurfaceItem, signal: &QWaylandQuickShellSurfaceItem::surfaceDestroyed,
279 context: this, slot: &QWaylandQtShellChrome::clientDestroyed);
280 }
281
282 updateShellSurface();
283 emit shellSurfaceItemChanged();
284}
285
286QWaylandQuickShellSurfaceItem *QWaylandQtShellChrome::shellSurfaceItem() const
287{
288 Q_D(const QWaylandQtShellChrome);
289 return d->shellSurfaceItem;
290}
291
292void QWaylandQtShellChrome::stopGrab()
293{
294 Q_D(QWaylandQtShellChrome);
295 d->decorationInteraction = quint8(QWaylandQtShellChromePrivate::DecorationInteraction::None);
296}
297
298void QWaylandQtShellChrome::leftResize()
299{
300 Q_D(QWaylandQtShellChrome);
301 if (!d->leftResizeHandleHandler->active())
302 return;
303
304 d->updateDecorationInteraction(flags: quint8(QWaylandQtShellChromePrivate::DecorationInteraction::WestBound),
305 centroid: d->leftResizeHandleHandler->centroid());
306}
307
308void QWaylandQtShellChrome::rightResize()
309{
310 Q_D(QWaylandQtShellChrome);
311 if (!d->rightResizeHandleHandler->active())
312 return;
313
314 d->updateDecorationInteraction(flags: quint8(QWaylandQtShellChromePrivate::DecorationInteraction::EastBound),
315 centroid: d->rightResizeHandleHandler->centroid());
316}
317
318void QWaylandQtShellChrome::topResize()
319{
320 Q_D(QWaylandQtShellChrome);
321 if (!d->topResizeHandleHandler->active())
322 return;
323
324 d->updateDecorationInteraction(flags: quint8(QWaylandQtShellChromePrivate::DecorationInteraction::NorthBound),
325 centroid: d->topResizeHandleHandler->centroid());
326}
327
328void QWaylandQtShellChrome::bottomResize()
329{
330 Q_D(QWaylandQtShellChrome);
331 if (!d->bottomResizeHandleHandler->active())
332 return;
333
334 d->updateDecorationInteraction(flags: quint8(QWaylandQtShellChromePrivate::DecorationInteraction::SouthBound),
335 centroid: d->bottomResizeHandleHandler->centroid());
336}
337
338void QWaylandQtShellChrome::topLeftResize()
339{
340 Q_D(QWaylandQtShellChrome);
341 if (!d->topLeftResizeHandleHandler->active())
342 return;
343
344 d->updateDecorationInteraction(flags: quint8(QWaylandQtShellChromePrivate::DecorationInteraction::WestBound)
345 | quint8(QWaylandQtShellChromePrivate::DecorationInteraction::NorthBound),
346 centroid: d->topLeftResizeHandleHandler->centroid());
347}
348
349void QWaylandQtShellChrome::topRightResize()
350{
351 Q_D(QWaylandQtShellChrome);
352 if (!d->topRightResizeHandleHandler->active())
353 return;
354
355 d->updateDecorationInteraction(flags: quint8(QWaylandQtShellChromePrivate::DecorationInteraction::EastBound)
356 | quint8(QWaylandQtShellChromePrivate::DecorationInteraction::NorthBound),
357 centroid: d->topRightResizeHandleHandler->centroid());
358}
359
360void QWaylandQtShellChrome::bottomLeftResize()
361{
362 Q_D(QWaylandQtShellChrome);
363 if (!d->bottomLeftResizeHandleHandler->active())
364 return;
365
366 d->updateDecorationInteraction(flags: quint8(QWaylandQtShellChromePrivate::DecorationInteraction::WestBound)
367 | quint8(QWaylandQtShellChromePrivate::DecorationInteraction::SouthBound),
368 centroid: d->bottomLeftResizeHandleHandler->centroid());
369}
370
371void QWaylandQtShellChrome::bottomRightResize()
372{
373 Q_D(QWaylandQtShellChrome);
374 if (!d->bottomRightResizeHandleHandler->active())
375 return;
376
377 d->updateDecorationInteraction(flags: quint8(QWaylandQtShellChromePrivate::DecorationInteraction::EastBound)
378 | quint8(QWaylandQtShellChromePrivate::DecorationInteraction::SouthBound),
379 centroid: d->bottomRightResizeHandleHandler->centroid());
380}
381
382void QWaylandQtShellChrome::titleBarMove()
383{
384 Q_D(QWaylandQtShellChrome);
385 if (!d->titleBarHandler->active())
386 return;
387
388 quint8 flags = quint8(QWaylandQtShellChromePrivate::DecorationInteraction::TitleBar);
389 QQuickHandlerPoint centroid = d->titleBarHandler->centroid();
390 if (d->decorationInteraction == quint8(QWaylandQtShellChromePrivate::DecorationInteraction::None)) {
391 d->decorationInteraction = flags;
392 d->decorationInteractionPosition = d->shellSurface->windowPosition() - centroid.scenePressPosition();
393
394 activate();
395 }
396
397 if (d->decorationInteraction != flags)
398 return;
399
400 QPointF position = d->constrainPoint(point: centroid.scenePosition());
401 d->shellSurface->setWindowPosition((position + d->decorationInteractionPosition).toPoint());
402}
403
404/*!
405 * \qmlproperty Item QtShellChrome::titleBar
406 *
407 * This property holds the default title bar item of the QtShellChrome. If set, a \l DragHandler
408 * will be installed on the title bar which moves the window around on user interaction. In
409 * addition, the window will automatically be activated if the title bar is clicked.
410 *
411 * The title bar will automatically hide and show, depending on the window flags and the
412 * window's full screen state.
413 *
414 * \qml
415 * QtShellChrome {
416 * Rectangle {
417 * id: tb
418 * anchors.top: parent.top
419 * anchors.right: parent.right
420 * anchors.left: parent.left
421 * height: 50
422 * color: "black"
423 *
424 * Text {
425 * color: "white"
426 * anchors.centerIn: parent
427 * text: shellSurfaceItem.shellSurface.windowTitle
428 * font.pixelSize: 25
429 * }
430 * }
431 * titleBar: tb
432 * }
433 * \endqml
434 *
435 * \note Unless explicit frame margins are set, the title bar's height will be included in the
436 * window's top frame margin.
437 */
438QQuickItem *QWaylandQtShellChrome::titleBar() const
439{
440 Q_D(const QWaylandQtShellChrome);
441 return d->titleBar;
442}
443
444void QWaylandQtShellChrome::setTitleBar(QQuickItem *item)
445{
446 Q_D(QWaylandQtShellChrome);
447 if (d->titleBar == item)
448 return;
449
450 if (d->titleBar != nullptr) {
451 d->titleBar->disconnect(receiver: this);
452
453 delete d->titleBarHandler;
454 d->titleBarHandler = nullptr;
455 }
456
457 d->titleBar = item;
458
459 if (d->titleBar != nullptr) {
460 connect(sender: d->titleBar, signal: &QQuickItem::heightChanged,
461 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
462
463 d->titleBarHandler = new QQuickDragHandler(d->titleBar);
464 d->titleBarHandler->setTarget(nullptr);
465
466 connect(sender: d->titleBarHandler, signal: &QQuickPointerHandler::grabChanged,
467 context: this, slot: &QWaylandQtShellChrome::stopGrab);
468 connect(sender: d->titleBarHandler, signal: &QQuickPointerHandler::grabChanged,
469 context: this, slot: &QWaylandQtShellChrome::activateOnGrab);
470 connect(sender: d->titleBarHandler, signal: &QQuickMultiPointHandler::centroidChanged,
471 context: this, slot: &QWaylandQtShellChrome::titleBarMove);
472 }
473
474 emit titleBarChanged();
475}
476
477/*!
478 * \qmlproperty Item QtShellChrome::leftResizeHandle
479 *
480 * This property holds the default left resize handle of the QtShellChrome. If set, a \l DragHandler
481 * will be installed on the resize handle which resizes the window by moving its left edge.
482 *
483 * The handle will automatically hide and show, depending on the window flags and the window's full
484 * screen state.
485 *
486 * \qml
487 * QtShellChrome {
488 * Rectangle {
489 * id: lrh
490 * anchors.left: parent.left
491 * anchors.top: parent.top
492 * anchors.bottom: parent.bottom
493 * width: 5
494 * color: "white"
495 * }
496 * leftResizeHandle: lrh
497 * }
498 * \endqml
499 *
500 * \note Unless explicit frame margins are set, the handle's width will be included in the
501 * window's left frame margin.
502 */
503QQuickItem *QWaylandQtShellChrome::leftResizeHandle() const
504{
505 Q_D(const QWaylandQtShellChrome);
506 return d->leftResizeHandle;
507}
508
509void QWaylandQtShellChrome::setLeftResizeHandle(QQuickItem *item)
510{
511 Q_D(QWaylandQtShellChrome);
512 if (d->leftResizeHandle == item)
513 return;
514
515 if (d->leftResizeHandle != nullptr) {
516 d->leftResizeHandle->disconnect(receiver: this);
517
518 delete d->leftResizeHandleHandler;
519 d->leftResizeHandleHandler = nullptr;
520 }
521
522 d->leftResizeHandle = item;
523
524 if (d->leftResizeHandle != nullptr) {
525 connect(sender: d->leftResizeHandle, signal: &QQuickItem::widthChanged,
526 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
527
528 d->leftResizeHandleHandler = new QQuickDragHandler(d->leftResizeHandle);
529 d->leftResizeHandleHandler->setCursorShape(Qt::SizeHorCursor);
530 d->leftResizeHandleHandler->setTarget(nullptr);
531
532 connect(sender: d->leftResizeHandleHandler, signal: &QQuickPointerHandler::grabChanged,
533 context: this, slot: &QWaylandQtShellChrome::stopGrab);
534 connect(sender: d->leftResizeHandleHandler, signal: &QQuickMultiPointHandler::centroidChanged,
535 context: this, slot: &QWaylandQtShellChrome::leftResize);
536 }
537
538 emit leftResizeHandleChanged();
539}
540
541/*!
542 * \qmlproperty Item QtShellChrome::rightResizeHandle
543 *
544 * This property holds the default right resize handle of the QtShellChrome. If set, a \l DragHandler
545 * will be installed on the resize handle which resizes the window by moving its right edge.
546 *
547 * The handle will automatically hide and show, depending on the window flags and the window's full
548 * screen state.
549 *
550 * \qml
551 * QtShellChrome {
552 * Rectangle {
553 * id: rrh
554 * anchors.right: parent.right
555 * anchors.top: parent.top
556 * anchors.bottom: parent.bottom
557 * width: 5
558 * color: "white"
559 * }
560 * rightResizeHandle: rrh
561 * }
562 * \endqml
563 *
564 * \note Unless explicit frame margins are set, the handle's width will be included in the
565 * window's right frame margin.
566 */
567QQuickItem *QWaylandQtShellChrome::rightResizeHandle() const
568{
569 Q_D(const QWaylandQtShellChrome);
570 return d->rightResizeHandle;
571}
572
573void QWaylandQtShellChrome::setRightResizeHandle(QQuickItem *item)
574{
575 Q_D(QWaylandQtShellChrome);
576 if (d->rightResizeHandle == item)
577 return;
578
579 if (d->rightResizeHandle != nullptr) {
580 d->rightResizeHandle->disconnect(receiver: this);
581
582 delete d->rightResizeHandleHandler;
583 d->rightResizeHandleHandler = nullptr;
584 }
585
586 d->rightResizeHandle = item;
587
588 if (d->rightResizeHandle != nullptr) {
589 connect(sender: d->rightResizeHandle, signal: &QQuickItem::widthChanged,
590 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
591
592 d->rightResizeHandleHandler = new QQuickDragHandler(d->rightResizeHandle);
593 d->rightResizeHandleHandler->setCursorShape(Qt::SizeHorCursor);
594 d->rightResizeHandleHandler->setTarget(nullptr);
595
596 connect(sender: d->rightResizeHandleHandler, signal: &QQuickPointerHandler::grabChanged,
597 context: this, slot: &QWaylandQtShellChrome::stopGrab);
598 connect(sender: d->rightResizeHandleHandler, signal: &QQuickMultiPointHandler::centroidChanged,
599 context: this, slot: &QWaylandQtShellChrome::rightResize);
600 }
601
602 emit rightResizeHandleChanged();
603}
604
605/*!
606 * \qmlproperty Item QtShellChrome::topResizeHandle
607 *
608 * This property holds the default top resize handle of the QtShellChrome. If set, a \l DragHandler
609 * will be installed on the resize handle which resizes the window by moving its top edge.
610 *
611 * The handle will automatically hide and show, depending on the window flags and the window's full
612 * screen state.
613 *
614 * \qml
615 * QtShellChrome {
616 * Rectangle {
617 * id: trh
618 * anchors.top: parent.top
619 * anchors.left: parent.left
620 * anchors.right: parent.right
621 * height: 5
622 * color: "white"
623 * }
624 * topResizeHandle: trh
625 * }
626 * \endqml
627 *
628 * \note Unless explicit frame margins are set, the handle's height will be included in the
629 * window's top frame margin.
630 */
631QQuickItem *QWaylandQtShellChrome::topResizeHandle() const
632{
633 Q_D(const QWaylandQtShellChrome);
634 return d->topResizeHandle;
635}
636
637void QWaylandQtShellChrome::setTopResizeHandle(QQuickItem *item)
638{
639 Q_D(QWaylandQtShellChrome);
640 if (d->topResizeHandle == item)
641 return;
642
643 if (d->topResizeHandle != nullptr) {
644 d->topResizeHandle->disconnect(receiver: this);
645
646 delete d->topResizeHandleHandler;
647 d->topResizeHandleHandler = nullptr;
648 }
649
650 d->topResizeHandle = item;
651
652 if (d->topResizeHandle != nullptr) {
653 connect(sender: d->topResizeHandle, signal: &QQuickItem::heightChanged,
654 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
655
656 d->topResizeHandleHandler = new QQuickDragHandler(d->topResizeHandle);
657 d->topResizeHandleHandler->setCursorShape(Qt::SizeVerCursor);
658 d->topResizeHandleHandler->setTarget(nullptr);
659
660 connect(sender: d->topResizeHandleHandler, signal: &QQuickPointerHandler::grabChanged,
661 context: this, slot: &QWaylandQtShellChrome::stopGrab);
662 connect(sender: d->topResizeHandleHandler, signal: &QQuickMultiPointHandler::centroidChanged,
663 context: this, slot: &QWaylandQtShellChrome::topResize);
664 }
665
666 emit topResizeHandleChanged();
667}
668
669/*!
670 * \qmlproperty Item QtShellChrome::bottomResizeHandle
671 *
672 * This property holds the default bottom resize handle of the QtShellChrome. If set, a \l DragHandler
673 * will be installed on the resize handle which resizes the window by moving its bottom edge.
674 *
675 * The handle will automatically hide and show, depending on the window flags and the window's full
676 * screen state.
677 *
678 * \qml
679 * QtShellChrome {
680 * Rectangle {
681 * id: brh
682 * anchors.bottom: parent.bottom
683 * anchors.left: parent.left
684 * anchors.right: parent.right
685 * height: 5
686 * color: "white"
687 * }
688 * bottomResizeHandle: brh
689 * }
690 * \endqml
691 *
692 * \note Unless explicit frame margins are set, the handle's height will be included in the
693 * window's bottom frame margin.
694 */
695QQuickItem *QWaylandQtShellChrome::bottomResizeHandle() const
696{
697 Q_D(const QWaylandQtShellChrome);
698 return d->bottomResizeHandle;
699}
700
701void QWaylandQtShellChrome::setBottomResizeHandle(QQuickItem *item)
702{
703 Q_D(QWaylandQtShellChrome);
704 if (d->bottomResizeHandle == item)
705 return;
706
707 if (d->bottomResizeHandle != nullptr) {
708 d->bottomResizeHandle->disconnect(receiver: this);
709
710 delete d->bottomResizeHandleHandler;
711 d->bottomResizeHandleHandler = nullptr;
712 }
713
714 d->bottomResizeHandle = item;
715
716 if (d->bottomResizeHandle != nullptr) {
717 connect(sender: d->bottomResizeHandle, signal: &QQuickItem::heightChanged,
718 context: this, slot: &QWaylandQtShellChrome::updateDecorations);
719
720 d->bottomResizeHandleHandler = new QQuickDragHandler(d->bottomResizeHandle);
721 d->bottomResizeHandleHandler->setCursorShape(Qt::SizeVerCursor);
722 d->bottomResizeHandleHandler->setTarget(nullptr);
723
724 connect(sender: d->bottomResizeHandleHandler, signal: &QQuickPointerHandler::grabChanged,
725 context: this, slot: &QWaylandQtShellChrome::stopGrab);
726 connect(sender: d->bottomResizeHandleHandler, signal: &QQuickMultiPointHandler::centroidChanged,
727 context: this, slot: &QWaylandQtShellChrome::bottomResize);
728
729 }
730
731 emit bottomResizeHandleChanged();
732}
733
734/*!
735 * \qmlproperty Item QtShellChrome::topLeftResizeHandle
736 *
737 * This property holds the default top-left resize handle of the QtShellChrome. If set, a \l DragHandler
738 * will be installed on the resize handle which resizes the window by moving its top and left edges
739 * in equal amounts.
740 *
741 * The handle will automatically hide and show, depending on the window flags and the window's full
742 * screen state.
743 *
744 * \qml
745 * QtShellChrome {
746 * Rectangle {
747 * id: tlrh
748 * anchors.top: parent.top
749 * anchors.left: parent.left
750 * height: 5
751 * width: 5
752 * color: "white"
753 * }
754 * topLeftResizeHandle: tlrh
755 * }
756 * \endqml
757 */
758QQuickItem *QWaylandQtShellChrome::topLeftResizeHandle() const
759{
760 Q_D(const QWaylandQtShellChrome);
761 return d->topLeftResizeHandle;
762}
763
764void QWaylandQtShellChrome::setTopLeftResizeHandle(QQuickItem *item)
765{
766 Q_D(QWaylandQtShellChrome);
767 if (d->topLeftResizeHandle == item)
768 return;
769
770 if (d->topLeftResizeHandle != nullptr) {
771 delete d->topLeftResizeHandleHandler;
772 d->topLeftResizeHandleHandler = nullptr;
773 }
774
775 d->topLeftResizeHandle = item;
776
777 if (d->topLeftResizeHandle != nullptr) {
778 d->topLeftResizeHandleHandler = new QQuickDragHandler(d->topLeftResizeHandle);
779 d->topLeftResizeHandleHandler->setCursorShape(Qt::SizeFDiagCursor);
780 d->topLeftResizeHandleHandler->setTarget(nullptr);
781
782 connect(sender: d->topLeftResizeHandleHandler, signal: &QQuickPointerHandler::grabChanged,
783 context: this, slot: &QWaylandQtShellChrome::stopGrab);
784 connect(sender: d->topLeftResizeHandleHandler, signal: &QQuickMultiPointHandler::centroidChanged,
785 context: this, slot: &QWaylandQtShellChrome::topLeftResize);
786 }
787
788 emit topLeftResizeHandleChanged();
789}
790
791/*!
792 * \qmlproperty Item QtShellChrome::bottomLeftResizeHandle
793 *
794 * This property holds the default bottom-left resize handle of the QtShellChrome. If set, a \l DragHandler
795 * will be installed on the resize handle which resizes the window by moving its bottom and left edges
796 * in equal amounts.
797 *
798 * The handle will automatically hide and show, depending on the window flags and the window's full
799 * screen state.
800 *
801 * \qml
802 * QtShellChrome {
803 * Rectangle {
804 * id: blrh
805 * anchors.bottom: parent.bottom
806 * anchors.left: parent.left
807 * height: 5
808 * width: 5
809 * color: "white"
810 * }
811 * bottomLeftResizeHandle: blrh
812 * }
813 * \endqml
814 */
815QQuickItem *QWaylandQtShellChrome::bottomLeftResizeHandle() const
816{
817 Q_D(const QWaylandQtShellChrome);
818 return d->bottomLeftResizeHandle;
819}
820
821void QWaylandQtShellChrome::setBottomLeftResizeHandle(QQuickItem *item)
822{
823 Q_D(QWaylandQtShellChrome);
824 if (d->bottomLeftResizeHandle == item)
825 return;
826
827 if (d->bottomLeftResizeHandle != nullptr) {
828 delete d->bottomLeftResizeHandleHandler;
829 d->bottomLeftResizeHandleHandler = nullptr;
830 }
831
832 d->bottomLeftResizeHandle = item;
833
834 if (d->bottomLeftResizeHandle != nullptr) {
835 d->bottomLeftResizeHandleHandler = new QQuickDragHandler(d->bottomLeftResizeHandle);
836 d->bottomLeftResizeHandleHandler->setCursorShape(Qt::SizeBDiagCursor);
837 d->bottomLeftResizeHandleHandler->setTarget(nullptr);
838
839 connect(sender: d->bottomLeftResizeHandleHandler, signal: &QQuickPointerHandler::grabChanged,
840 context: this, slot: &QWaylandQtShellChrome::stopGrab);
841 connect(sender: d->bottomLeftResizeHandleHandler, signal: &QQuickMultiPointHandler::centroidChanged,
842 context: this, slot: &QWaylandQtShellChrome::bottomLeftResize);
843 }
844
845 emit bottomLeftResizeHandleChanged();
846}
847
848/*!
849 * \qmlproperty Item QtShellChrome::topRightResizeHandle
850 *
851 * This property holds the default top-right resize handle of the QtShellChrome. If set, a \l DragHandler
852 * will be installed on the resize handle which resizes the window by moving its top and right edges
853 * in equal amounts.
854 *
855 * The handle will automatically hide and show, depending on the window flags and the window's full
856 * screen state.
857 *
858 * \qml
859 * QtShellChrome {
860 * Rectangle {
861 * id: trrh
862 * anchors.top: parent.top
863 * anchors.right: parent.right
864 * height: 5
865 * width: 5
866 * color: "white"
867 * }
868 * topRightResizeHandle: trrh
869 * }
870 * \endqml
871 */
872QQuickItem *QWaylandQtShellChrome::topRightResizeHandle() const
873{
874 Q_D(const QWaylandQtShellChrome);
875 return d->topRightResizeHandle;
876}
877
878void QWaylandQtShellChrome::setTopRightResizeHandle(QQuickItem *item)
879{
880 Q_D(QWaylandQtShellChrome);
881 if (d->topRightResizeHandle == item)
882 return;
883
884 if (d->topRightResizeHandle != nullptr) {
885 delete d->topRightResizeHandleHandler;
886 d->topRightResizeHandleHandler = nullptr;
887 }
888
889 d->topRightResizeHandle = item;
890
891 if (d->topRightResizeHandle != nullptr) {
892 d->topRightResizeHandleHandler = new QQuickDragHandler(d->topRightResizeHandle);
893 d->topRightResizeHandleHandler->setCursorShape(Qt::SizeBDiagCursor);
894 d->topRightResizeHandleHandler->setTarget(nullptr);
895
896 connect(sender: d->topRightResizeHandleHandler, signal: &QQuickPointerHandler::grabChanged,
897 context: this, slot: &QWaylandQtShellChrome::stopGrab);
898 connect(sender: d->topRightResizeHandleHandler, signal: &QQuickMultiPointHandler::centroidChanged,
899 context: this, slot: &QWaylandQtShellChrome::topRightResize);
900 }
901
902 emit topRightResizeHandleChanged();
903}
904
905/*!
906 * \qmlproperty Item QtShellChrome::bottomRightResizeHandle
907 *
908 * This property holds the default bottom-right resize handle of the QtShellChrome. If set, a \l DragHandler
909 * will be installed on the resize handle which resizes the window by moving its bottom and right edges
910 * in equal amounts.
911 *
912 * The handle will automatically hide and show, depending on the window flags and the window's full
913 * screen state.
914 *
915 * \qml
916 * QtShellChrome {
917 * Rectangle {
918 * id: brrh
919 * anchors.bottom: parent.bottom
920 * anchors.right: parent.right
921 * height: 5
922 * width: 5
923 * color: "white"
924 * }
925 * bottomRightResizeHandle: brrh
926 * }
927 * \endqml
928 */
929QQuickItem *QWaylandQtShellChrome::bottomRightResizeHandle() const
930{
931 Q_D(const QWaylandQtShellChrome);
932 return d->bottomRightResizeHandle;
933}
934
935void QWaylandQtShellChrome::setBottomRightResizeHandle(QQuickItem *item)
936{
937 Q_D(QWaylandQtShellChrome);
938 if (d->bottomRightResizeHandle == item)
939 return;
940
941 if (d->bottomRightResizeHandle != nullptr) {
942 delete d->bottomRightResizeHandleHandler;
943 d->bottomRightResizeHandleHandler = nullptr;
944 }
945
946 d->bottomRightResizeHandle = item;
947
948 if (d->bottomRightResizeHandle != nullptr) {
949 d->bottomRightResizeHandleHandler = new QQuickDragHandler(d->bottomRightResizeHandle);
950 d->bottomRightResizeHandleHandler->setCursorShape(Qt::SizeFDiagCursor);
951 d->bottomRightResizeHandleHandler->setTarget(nullptr);
952
953 connect(sender: d->bottomRightResizeHandleHandler, signal: &QQuickPointerHandler::grabChanged,
954 context: this, slot: &QWaylandQtShellChrome::stopGrab);
955 connect(sender: d->bottomRightResizeHandleHandler, signal: &QQuickMultiPointHandler::centroidChanged,
956 context: this, slot: &QWaylandQtShellChrome::bottomRightResize);
957 }
958
959 emit bottomRightResizeHandleChanged();
960}
961
962/*!
963 * \qmlproperty rect QtShellChrome::maximizedRect
964 *
965 * This property holds the are of the WaylandOutput which is available to be filled by the
966 * window when it is in maximized state. By default, the window will fill the entire geometry
967 * of the WaylandOutput when it is maximized. Changing it can be useful for example when the
968 * compositor has other system UI which should not be obscured by maximized applications, such as
969 * a task bar.
970 */
971void QWaylandQtShellChrome::setMaximizedRect(const QRect &rect)
972{
973 Q_D(QWaylandQtShellChrome);
974 if (d->maximizedRect == rect)
975 return;
976
977 d->maximizedRect = rect;
978 emit maximizedRectChanged();
979}
980
981QRect QWaylandQtShellChrome::maximizedRect() const
982{
983 Q_D(const QWaylandQtShellChrome);
984 if (d->maximizedRect.isValid())
985 return d->maximizedRect;
986 else if (d->shellSurfaceItem != nullptr && d->shellSurfaceItem->output() != nullptr)
987 return d->shellSurfaceItem->output()->geometry();
988
989 return QRect{};
990}
991
992void QWaylandQtShellChrome::updateDecorations()
993{
994 Q_D(QWaylandQtShellChrome);
995 if (d->shellSurface == nullptr)
996 return;
997
998 bool decorations = hasDecorations();
999 bool titleBarShowing = hasTitleBar();
1000
1001 QMargins margins;
1002 if (d->automaticFrameMargins) {
1003 if (d->leftResizeHandle != nullptr && decorations)
1004 margins.setLeft(d->leftResizeHandle->width());
1005 if (d->rightResizeHandle != nullptr && decorations)
1006 margins.setRight(d->rightResizeHandle->width());
1007 if (d->bottomResizeHandle != nullptr && decorations)
1008 margins.setBottom(d->bottomResizeHandle->height());
1009
1010 margins.setTop((decorations && d->topResizeHandle != nullptr ? d->topResizeHandle->height() : 0)
1011 + (titleBarShowing && d->titleBar != nullptr ? d->titleBar->height() : 0));
1012 } else {
1013 margins = d->explicitFrameMargins;
1014 }
1015 d->shellSurface->setFrameMargins(margins);
1016
1017 if (d->titleBar != nullptr)
1018 d->titleBar->setVisible(titleBarShowing);
1019 if (d->leftResizeHandle != nullptr)
1020 d->leftResizeHandle->setVisible(decorations);
1021 if (d->rightResizeHandle != nullptr)
1022 d->rightResizeHandle->setVisible(decorations);
1023 if (d->topResizeHandle != nullptr)
1024 d->topResizeHandle->setVisible(decorations);
1025 if (d->bottomResizeHandle != nullptr)
1026 d->bottomResizeHandle->setVisible(decorations);
1027 if (d->bottomLeftResizeHandle != nullptr)
1028 d->bottomLeftResizeHandle->setVisible(decorations);
1029 if (d->topLeftResizeHandle != nullptr)
1030 d->topLeftResizeHandle->setVisible(decorations);
1031 if (d->bottomRightResizeHandle != nullptr)
1032 d->bottomRightResizeHandle->setVisible(decorations);
1033 if (d->topRightResizeHandle != nullptr)
1034 d->topRightResizeHandle->setVisible(decorations);
1035
1036 bool minimizedOrMaximized = (d->currentState & (Qt::WindowMaximized|Qt::WindowMinimized)) != 0;
1037 if (d->leftResizeHandleHandler != nullptr)
1038 d->leftResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
1039 if (d->rightResizeHandleHandler != nullptr)
1040 d->rightResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
1041 if (d->bottomResizeHandleHandler != nullptr)
1042 d->bottomResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
1043 if (d->topResizeHandleHandler != nullptr)
1044 d->topResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
1045 if (d->bottomLeftResizeHandleHandler != nullptr)
1046 d->bottomLeftResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
1047 if (d->bottomRightResizeHandleHandler != nullptr)
1048 d->bottomRightResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
1049 if (d->topLeftResizeHandleHandler != nullptr)
1050 d->topLeftResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
1051 if (d->topRightResizeHandleHandler != nullptr)
1052 d->topRightResizeHandleHandler->setEnabled(decorations && !minimizedOrMaximized);
1053 if (d->titleBarHandler != nullptr)
1054 d->titleBarHandler->setEnabled(titleBarShowing && !minimizedOrMaximized);
1055}
1056
1057void QWaylandQtShellChrome::updateGeometry()
1058{
1059 Q_D(QWaylandQtShellChrome);
1060 if (d->shellSurface == nullptr)
1061 return;
1062
1063 QRect windowGeometry = d->shellSurface->windowGeometry();
1064
1065 QPointF position = windowGeometry.topLeft();
1066 position.rx() -= d->shellSurface->frameMarginLeft();
1067 position.ry() -= d->shellSurface->frameMarginTop();
1068
1069 QSizeF size = windowGeometry.size();
1070 size.rwidth() += d->shellSurface->frameMarginLeft() + d->shellSurface->frameMarginRight();
1071 size.rheight() += d->shellSurface->frameMarginTop() + d->shellSurface->frameMarginBottom();
1072
1073 setPosition(position);
1074 setSize(size);
1075}
1076
1077void QWaylandQtShellChrome::updateSurface()
1078{
1079 Q_D(QWaylandQtShellChrome);
1080 QWaylandSurface *surface = d->shellSurface != nullptr ? d->shellSurface->surface() : nullptr;
1081 if (d->surface == surface)
1082 return;
1083
1084 if (d->surface != nullptr)
1085 d->surface->disconnect(receiver: this);
1086
1087 d->surface = surface;
1088
1089 if (d->surface != nullptr) {
1090 connect(sender: d->surface, signal: &QWaylandSurface::hasContentChanged,
1091 context: this, slot: &QWaylandQtShellChrome::updateAutomaticPosition);
1092 }
1093}
1094
1095void QWaylandQtShellChrome::updateShellSurface()
1096{
1097 Q_D(QWaylandQtShellChrome);
1098 QWaylandQtShellSurface *sf = d->shellSurfaceItem != nullptr
1099 ? qobject_cast<QWaylandQtShellSurface *>(object: d->shellSurfaceItem->shellSurface())
1100 : nullptr;
1101 if (d->shellSurface == sf)
1102 return;
1103
1104 if (d->shellSurface != nullptr) {
1105 d->shellSurface->disconnect(receiver: this);
1106 if (d->shell != nullptr)
1107 d->shell->unregisterChrome(chrome: this);
1108 d->shell = nullptr;
1109 }
1110
1111 d->shellSurface = sf;
1112 if (d->shellSurface != nullptr) {
1113 d->shell = d->shellSurface->shell();
1114 if (d->shell != nullptr)
1115 d->shell->registerChrome(chrome: this);
1116
1117 updateWindowFlags();
1118 connect(sender: d->shellSurface, signal: &QWaylandQtShellSurface::windowFlagsChanged,
1119 context: this, slot: &QWaylandQtShellChrome::updateWindowFlags);
1120 connect(sender: d->shellSurface, signal: &QWaylandQtShellSurface::windowStateChanged,
1121 context: this, slot: &QWaylandQtShellChrome::updateWindowState);
1122 connect(sender: d->shellSurface, signal: &QWaylandQtShellSurface::frameMarginChanged,
1123 context: this, slot: &QWaylandQtShellChrome::updateGeometry);
1124 connect(sender: d->shellSurface, signal: &QWaylandQtShellSurface::windowGeometryChanged,
1125 context: this, slot: &QWaylandQtShellChrome::updateGeometry);
1126 connect(sender: d->shellSurface, signal: &QWaylandQtShellSurface::raiseRequested,
1127 context: this, slot: &QWaylandQtShellChrome::raise);
1128 connect(sender: d->shellSurface, signal: &QWaylandQtShellSurface::lowerRequested,
1129 context: this, slot: &QWaylandQtShellChrome::lower);
1130 connect(sender: d->shellSurface, signal: &QWaylandQtShellSurface::activeChanged,
1131 context: this, slot: &QWaylandQtShellChrome::updateActiveState);
1132 connect(sender: d->shellSurface, signal: &QWaylandQtShellSurface::surfaceChanged,
1133 context: this, slot: &QWaylandQtShellChrome::updateSurface);
1134 }
1135
1136 updateDecorations();
1137 updateSurface();
1138}
1139
1140void QWaylandQtShellChrome::updateWindowState()
1141{
1142 Q_D(QWaylandQtShellChrome);
1143 if (d->shellSurface == nullptr)
1144 return;
1145
1146 setWindowState(d->shellSurface->windowState());
1147}
1148
1149void QWaylandQtShellChrome::updateWindowFlags()
1150{
1151 Q_D(QWaylandQtShellChrome);
1152
1153 uint nextFlags = d->shellSurface == nullptr || d->shellSurface->windowFlags() == Qt::Window
1154 ? d->defaultFlags
1155 : d->shellSurface->windowFlags();
1156
1157 if (d->currentFlags != nextFlags) {
1158 d->currentFlags = nextFlags;
1159 emit currentWindowFlagsChanged();
1160 }
1161}
1162
1163/*!
1164 * \qmlproperty int QtShellChrome::windowFlags
1165 *
1166 * This property holds the window flags of the QtShellChrome. They will match the \c windowFlags
1167 * property of the associated QtShellSurface, except when this is equal to Qt.Window. In this case,
1168 * a set of default window flags will be used instead. The default window flags are Qt.Window,
1169 * Qt.WindowMaximizeButtonHint, Qt.WindowMinimizeButtonHint and Qt.WindowCloseButtonHint.
1170 */
1171uint QWaylandQtShellChrome::currentWindowFlags() const
1172{
1173 Q_D(const QWaylandQtShellChrome);
1174 return d->currentFlags;
1175}
1176
1177/*!
1178 * \qmlproperty int QtShellChrome::windowState
1179 *
1180 * This property holds the window state of the shell surface. It will be updated immediately when
1181 * the window state is requested on the compositor-side, before this has been acknowledged by the
1182 * client. Therefore, it may in brief periods differ from the shell surface's \c windowState
1183 * property, which will be updated when the client has acknowledged the request.
1184 */
1185uint QWaylandQtShellChrome::currentWindowState() const
1186{
1187 Q_D(const QWaylandQtShellChrome);
1188 return d->currentState;
1189}
1190
1191bool QWaylandQtShellChrome::hasTitleBar() const
1192{
1193 Q_D(const QWaylandQtShellChrome);
1194
1195 bool frameless = (d->currentFlags & Qt::FramelessWindowHint) == Qt::FramelessWindowHint
1196 || ((d->currentFlags & Qt::Popup) == Qt::Popup
1197 && (d->currentFlags & Qt::Tool) != Qt::Tool)
1198 || (d->currentState & Qt::WindowFullScreen) == Qt::WindowFullScreen;
1199 return !frameless;
1200}
1201
1202/*!
1203 * \qmlproperty bool QtShellChrome::hasDecorations
1204 *
1205 * This property is true if the QtShellChrome's decorations should be visible, based on its window
1206 * state and window flags.
1207 */
1208bool QWaylandQtShellChrome::hasDecorations() const
1209{
1210 Q_D(const QWaylandQtShellChrome);
1211
1212 return hasTitleBar() && (d->currentFlags & Qt::Window) == Qt::Window;
1213}
1214
1215QRect QWaylandQtShellChrome::maxContentRect() const
1216{
1217 Q_D(const QWaylandQtShellChrome);
1218 if (d->shellSurface == nullptr)
1219 return QRect{};
1220
1221 int x0 = d->maximizedRect.x() + d->shellSurface->frameMarginLeft();
1222 int x1 = d->maximizedRect.x() + d->maximizedRect.width() - d->shellSurface->frameMarginRight();
1223 int y0 = d->maximizedRect.y() + d->shellSurface->frameMarginTop();
1224 int y1 = d->maximizedRect.y() + d->maximizedRect.height() - d->shellSurface->frameMarginBottom();
1225
1226 return QRect(x0, y0, x1 - x0, y1 - y0);
1227}
1228
1229static int randomPos(int windowSize, int screenSize)
1230{
1231 return (windowSize >= screenSize) ? 0 : rand() % (screenSize - windowSize);
1232}
1233
1234void QWaylandQtShellChrome::setWindowState(uint nextState)
1235{
1236 Q_D(QWaylandQtShellChrome);
1237
1238 if (d->currentState == nextState)
1239 return;
1240
1241 if (d->shellSurface == nullptr || d->shellSurfaceItem == nullptr)
1242 return;
1243
1244 QWaylandOutput *output = d->shellSurfaceItem->output();
1245 if (output == nullptr)
1246 return;
1247
1248 if ((d->currentState & (Qt::WindowMinimized | Qt::WindowMaximized | Qt::WindowFullScreen)) == 0) {
1249 d->restoreGeometry = d->shellSurface->windowGeometry();
1250 }
1251
1252 d->currentState = nextState;
1253 emit currentWindowStateChanged();
1254
1255 if ((nextState & Qt::WindowMinimized) != 0) {
1256 d->shellSurface->requestWindowGeometry(windowState: nextState, windowGeometry: QRect(0, 0, 1, 1));
1257 d->shellSurfaceItem->setVisible(false);
1258 deactivate();
1259 } else if ((nextState & Qt::WindowFullScreen) != 0) {
1260 d->shellSurfaceItem->setVisible(true);
1261 d->shellSurface->requestWindowGeometry(windowState: nextState, windowGeometry: QRect(QPoint(0, 0), output->window()->size()));
1262 activate();
1263 } else if ((nextState & Qt::WindowMaximized) != 0) {
1264 d->shellSurfaceItem->setVisible(true);
1265 d->shellSurface->requestWindowGeometry(windowState: nextState, windowGeometry: maxContentRect());
1266 activate();
1267 } else {
1268 d->shellSurfaceItem->setVisible(true);
1269 d->shellSurface->requestWindowGeometry(windowState: nextState, windowGeometry: d->restoreGeometry);
1270 activate();
1271 }
1272}
1273
1274void QWaylandQtShellChrome::updateAutomaticPosition()
1275{
1276 Q_D(QWaylandQtShellChrome);
1277 if (!d->positionSet && d->shellSurface != nullptr) {
1278 bool randomize = d->shellSurface->positionAutomatic();
1279 QRect rect = d->shellSurface->windowGeometry();
1280 QRect space = maxContentRect();
1281
1282 int xpos = randomize ? randomPos(windowSize: rect.width(), screenSize: space.width()) + space.x()
1283 : qMax(a: rect.x(), b: space.x());
1284 int ypos = randomize ? randomPos(windowSize: rect.height(), screenSize: space.height()) + space.y()
1285 : qMax(a: rect.y(), b: space.y());
1286
1287 d->shellSurface->setWindowPosition(QPoint(xpos, ypos));
1288 d->positionSet = true;
1289 }
1290}
1291
1292/*!
1293 * \qmlmethod void QtShellChrome::deactivate()
1294 *
1295 * Manually deactivates this window. If the window was active, this will activate the next window in
1296 * the stack instead.
1297 */
1298void QWaylandQtShellChrome::deactivate()
1299{
1300 Q_D(QWaylandQtShellChrome);
1301 if (d->shellSurface != nullptr)
1302 d->shellSurface->setActive(false);
1303}
1304
1305void QWaylandQtShellChrome::activateOnGrab(QPointingDevice::GrabTransition transition)
1306{
1307 Q_D(QWaylandQtShellChrome);
1308 if (d->titleBarHandler != nullptr) {
1309 switch (transition) {
1310 case QPointingDevice::GrabPassive:
1311 case QPointingDevice::OverrideGrabPassive:
1312 case QPointingDevice::GrabExclusive:
1313 activate();
1314 break;
1315 default:
1316 break;
1317 }
1318 }
1319}
1320
1321/*!
1322 * \qmlmethod void QtShellChrome::activate()
1323 *
1324 * Manually activate this window. This will also raise the window.
1325 *
1326 * \sa raise()
1327 */
1328void QWaylandQtShellChrome::activate()
1329{
1330 Q_D(QWaylandQtShellChrome);
1331 if (d->shellSurface != nullptr)
1332 d->shellSurface->setActive(true);
1333 raise();
1334}
1335
1336/*!
1337 * \qmlmethod void QtShellChrome::raise()
1338 *
1339 * Raise this window, so that it stacks on top of other windows (except if the other window's
1340 * flags prohibit this.)
1341 */
1342void QWaylandQtShellChrome::raise()
1343{
1344 Q_D(QWaylandQtShellChrome);
1345 if (d->shellSurfaceItem != nullptr)
1346 d->shellSurfaceItem->raise();
1347}
1348
1349/*!
1350 * \qmlmethod void QtShellChrome::lower()
1351 *
1352 * Lower this window, so that it stacks underneath other windows (except if the other window's
1353 * window flags prohibit this.)
1354 */
1355void QWaylandQtShellChrome::lower()
1356{
1357 Q_D(QWaylandQtShellChrome);
1358 if (d->shellSurfaceItem != nullptr)
1359 d->shellSurfaceItem->lower();
1360}
1361
1362void QWaylandQtShellChrome::updateActiveState()
1363{
1364 Q_D(QWaylandQtShellChrome);
1365 if (d->shellSurface == nullptr)
1366 return;
1367
1368 if (d->shellSurface->active()) {
1369 raise();
1370 emit activated();
1371 } else {
1372 emit deactivated();
1373 }
1374}
1375
1376/*!
1377 * \qmlproperty int QtShellChrome::frameMarginLeft
1378 *
1379 * Sets the size of the left margin of the QtShellChrome which is reserved for window decorations.
1380 * By default, this will equal the width of the \l leftResizeHandle if it is set. Otherwise it will
1381 * be 0.
1382 *
1383 * \note By setting this property explicitly, all default frame margins will be overridden with
1384 * their corresponding properties.
1385 */
1386void QWaylandQtShellChrome::setFrameMarginLeft(int left)
1387{
1388 Q_D(QWaylandQtShellChrome);
1389 if (d->explicitFrameMargins.left() == left)
1390 return;
1391
1392 d->explicitFrameMargins.setLeft(left);
1393 d->automaticFrameMargins = false;
1394 updateDecorations();
1395
1396 emit frameMarginChanged();
1397}
1398
1399int QWaylandQtShellChrome::frameMarginLeft() const
1400{
1401 Q_D(const QWaylandQtShellChrome);
1402 if (d->shellSurface == nullptr)
1403 return 0;
1404 return d->shellSurface->frameMarginLeft();
1405}
1406
1407/*!
1408 * \qmlproperty int QtShellChrome::frameMarginRight
1409 *
1410 * Sets the size of the right margin of the QtShellChrome which is reserved for window decorations.
1411 * By default, this will equal the width of the \l rightResizeHandle if it is set. Otherwise it will
1412 * be 0.
1413 *
1414 * \note By setting this property explicitly, all default frame margins will be overridden with
1415 * their corresponding properties.
1416 */
1417void QWaylandQtShellChrome::setFrameMarginRight(int right)
1418{
1419 Q_D(QWaylandQtShellChrome);
1420 if (d->explicitFrameMargins.right() == right)
1421 return;
1422
1423 d->explicitFrameMargins.setRight(right);
1424 d->automaticFrameMargins = false;
1425 updateDecorations();
1426
1427 emit frameMarginChanged();
1428}
1429
1430int QWaylandQtShellChrome::frameMarginRight() const
1431{
1432 Q_D(const QWaylandQtShellChrome);
1433 if (d->shellSurface == nullptr)
1434 return 0;
1435 return d->shellSurface->frameMarginRight();
1436}
1437
1438/*!
1439 * \qmlproperty int QtShellChrome::frameMarginTop
1440 *
1441 * Sets the size of the top margin of the QtShellChrome which is reserved for window decorations.
1442 * By default, this will equal the sum of the \l leftResizeHandle and the \l{titleBar}'s heights,
1443 * if they are set. Otherwise it will be 0.
1444 *
1445 * \note By setting this property explicitly, all default frame margins will be overridden with
1446 * their corresponding properties.
1447 */
1448void QWaylandQtShellChrome::setFrameMarginTop(int top)
1449{
1450 Q_D(QWaylandQtShellChrome);
1451 if (d->explicitFrameMargins.top() == top)
1452 return;
1453 d->explicitFrameMargins.setTop(top);
1454 d->automaticFrameMargins = false;
1455 updateDecorations();
1456
1457 emit frameMarginChanged();
1458}
1459
1460int QWaylandQtShellChrome::frameMarginTop() const
1461{
1462 Q_D(const QWaylandQtShellChrome);
1463 if (d->shellSurface == nullptr)
1464 return 0;
1465 return d->shellSurface->frameMarginTop();
1466}
1467
1468/*!
1469 * \qmlproperty int QtShellChrome::frameMarginBottom
1470 *
1471 * Sets the size of the bottom margin of the QtShellChrome which is reserved for window decorations.
1472 * By default, this will equal the height of the \l bottomResizeHandle if it is set. Otherwise it will
1473 * be 0.
1474 *
1475 * \note By setting this property explicitly, all default frame margins will be overridden with
1476 * their corresponding properties.
1477 */
1478void QWaylandQtShellChrome::setFrameMarginBottom(int bottom)
1479{
1480 Q_D(QWaylandQtShellChrome);
1481 if (d->explicitFrameMargins.bottom() == bottom)
1482 return;
1483 d->explicitFrameMargins.setBottom(bottom);
1484 d->automaticFrameMargins = false;
1485 updateDecorations();
1486
1487 emit frameMarginChanged();
1488}
1489
1490int QWaylandQtShellChrome::frameMarginBottom() const
1491{
1492 Q_D(const QWaylandQtShellChrome);
1493 if (d->shellSurface == nullptr)
1494 return 0;
1495 return d->shellSurface->frameMarginBottom();
1496}
1497
1498QT_END_NAMESPACE
1499
1500#include "moc_qwaylandqtshellchrome.cpp"
1501

source code of qtwayland/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp