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 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | QPointF 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 | |
22 | void QWaylandQtShellChromePrivate::updateDecorationInteraction(quint8 flags, |
23 | const QQuickHandlerPoint ¢roid) |
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 | */ |
117 | QWaylandQtShellChrome::QWaylandQtShellChrome(QQuickItem *parent) |
118 | : QQuickItem(*new QWaylandQtShellChromePrivate{}, parent) |
119 | { |
120 | init(); |
121 | } |
122 | |
123 | QWaylandQtShellChrome::QWaylandQtShellChrome(QWaylandQtShellChromePrivate &dd, |
124 | QQuickItem *parent) |
125 | : QQuickItem(dd, parent) |
126 | { |
127 | init(); |
128 | } |
129 | |
130 | QWaylandQtShellChrome::~QWaylandQtShellChrome() |
131 | { |
132 | Q_D(QWaylandQtShellChrome); |
133 | if (d->shell != nullptr) |
134 | d->shell->unregisterChrome(chrome: this); |
135 | } |
136 | |
137 | void 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 | */ |
179 | void 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 | */ |
203 | void 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 | */ |
227 | void 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 | */ |
264 | void 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 | |
286 | QWaylandQuickShellSurfaceItem *QWaylandQtShellChrome::shellSurfaceItem() const |
287 | { |
288 | Q_D(const QWaylandQtShellChrome); |
289 | return d->shellSurfaceItem; |
290 | } |
291 | |
292 | void QWaylandQtShellChrome::stopGrab() |
293 | { |
294 | Q_D(QWaylandQtShellChrome); |
295 | d->decorationInteraction = quint8(QWaylandQtShellChromePrivate::DecorationInteraction::None); |
296 | } |
297 | |
298 | void 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 | |
308 | void 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 | |
318 | void 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 | |
328 | void 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 | |
338 | void 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 | |
349 | void 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 | |
360 | void 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 | |
371 | void 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 | |
382 | void 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 | */ |
438 | QQuickItem *QWaylandQtShellChrome::titleBar() const |
439 | { |
440 | Q_D(const QWaylandQtShellChrome); |
441 | return d->titleBar; |
442 | } |
443 | |
444 | void 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 | */ |
503 | QQuickItem *QWaylandQtShellChrome::leftResizeHandle() const |
504 | { |
505 | Q_D(const QWaylandQtShellChrome); |
506 | return d->leftResizeHandle; |
507 | } |
508 | |
509 | void 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 | */ |
567 | QQuickItem *QWaylandQtShellChrome::rightResizeHandle() const |
568 | { |
569 | Q_D(const QWaylandQtShellChrome); |
570 | return d->rightResizeHandle; |
571 | } |
572 | |
573 | void 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 | */ |
631 | QQuickItem *QWaylandQtShellChrome::topResizeHandle() const |
632 | { |
633 | Q_D(const QWaylandQtShellChrome); |
634 | return d->topResizeHandle; |
635 | } |
636 | |
637 | void 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 | */ |
695 | QQuickItem *QWaylandQtShellChrome::bottomResizeHandle() const |
696 | { |
697 | Q_D(const QWaylandQtShellChrome); |
698 | return d->bottomResizeHandle; |
699 | } |
700 | |
701 | void 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 | */ |
758 | QQuickItem *QWaylandQtShellChrome::topLeftResizeHandle() const |
759 | { |
760 | Q_D(const QWaylandQtShellChrome); |
761 | return d->topLeftResizeHandle; |
762 | } |
763 | |
764 | void 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 | */ |
815 | QQuickItem *QWaylandQtShellChrome::bottomLeftResizeHandle() const |
816 | { |
817 | Q_D(const QWaylandQtShellChrome); |
818 | return d->bottomLeftResizeHandle; |
819 | } |
820 | |
821 | void 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 | */ |
872 | QQuickItem *QWaylandQtShellChrome::topRightResizeHandle() const |
873 | { |
874 | Q_D(const QWaylandQtShellChrome); |
875 | return d->topRightResizeHandle; |
876 | } |
877 | |
878 | void 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 | */ |
929 | QQuickItem *QWaylandQtShellChrome::bottomRightResizeHandle() const |
930 | { |
931 | Q_D(const QWaylandQtShellChrome); |
932 | return d->bottomRightResizeHandle; |
933 | } |
934 | |
935 | void 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 | */ |
971 | void 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 | |
981 | QRect 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 | |
992 | void 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 | |
1057 | void 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 | |
1077 | void 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 | |
1095 | void 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 | |
1140 | void QWaylandQtShellChrome::updateWindowState() |
1141 | { |
1142 | Q_D(QWaylandQtShellChrome); |
1143 | if (d->shellSurface == nullptr) |
1144 | return; |
1145 | |
1146 | setWindowState(d->shellSurface->windowState()); |
1147 | } |
1148 | |
1149 | void 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 | */ |
1171 | uint 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 | */ |
1185 | uint QWaylandQtShellChrome::currentWindowState() const |
1186 | { |
1187 | Q_D(const QWaylandQtShellChrome); |
1188 | return d->currentState; |
1189 | } |
1190 | |
1191 | bool 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 | */ |
1208 | bool QWaylandQtShellChrome::hasDecorations() const |
1209 | { |
1210 | Q_D(const QWaylandQtShellChrome); |
1211 | |
1212 | return hasTitleBar() && (d->currentFlags & Qt::Window) == Qt::Window; |
1213 | } |
1214 | |
1215 | QRect 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 | |
1229 | static int randomPos(int windowSize, int screenSize) |
1230 | { |
1231 | return (windowSize >= screenSize) ? 0 : rand() % (screenSize - windowSize); |
1232 | } |
1233 | |
1234 | void 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 | |
1274 | void 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 | */ |
1298 | void QWaylandQtShellChrome::deactivate() |
1299 | { |
1300 | Q_D(QWaylandQtShellChrome); |
1301 | if (d->shellSurface != nullptr) |
1302 | d->shellSurface->setActive(false); |
1303 | } |
1304 | |
1305 | void 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 | */ |
1328 | void 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 | */ |
1342 | void 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 | */ |
1355 | void QWaylandQtShellChrome::lower() |
1356 | { |
1357 | Q_D(QWaylandQtShellChrome); |
1358 | if (d->shellSurfaceItem != nullptr) |
1359 | d->shellSurfaceItem->lower(); |
1360 | } |
1361 | |
1362 | void 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 | */ |
1386 | void 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 | |
1399 | int 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 | */ |
1417 | void 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 | |
1430 | int 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 | */ |
1448 | void 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 | |
1460 | int 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 | */ |
1478 | void 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 | |
1490 | int QWaylandQtShellChrome::frameMarginBottom() const |
1491 | { |
1492 | Q_D(const QWaylandQtShellChrome); |
1493 | if (d->shellSurface == nullptr) |
1494 | return 0; |
1495 | return d->shellSurface->frameMarginBottom(); |
1496 | } |
1497 | |
1498 | QT_END_NAMESPACE |
1499 | |
1500 | #include "moc_qwaylandqtshellchrome.cpp" |
1501 | |