on xenial help sign in
Tell qtmir/miral about the available desktop area

So that it can make correct window management decisions Plus some refactorings: - Make AvailableDesktopArea provide boundariesForWindowPlacement - AvailableDesktopArea also replaces Stage.leftMargin and Panel.panelHeight in Stage.qml

commitb4dc54fdac606bed86fd434d6daaa00b9a1487e5 authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateFri 24 Mar 2017, 11:04 (10 years ago) parent5e5d7b5
14 files changed+338−57
plugins/WindowManager/AvailableDesktopArea.cpp+50 plugins/WindowManager/AvailableDesktopArea.h+38 plugins/WindowManager/CMakeLists.txt+7 plugins/WindowManager/WindowManagerPlugin.cpp+5−1 plugins/WindowManager/WindowMargins.cpp+74 plugins/WindowManager/WindowMargins.h+59 qml/Shell.qml+8−1 qml/Stage/ChildWindow.qml+8−1 qml/Stage/ChildWindowTree.qml+1 qml/Stage/DecoratedWindow.qml+14−7 qml/Stage/Stage.qml+57−47 tests/qmltests/Stage/tst_DesktopStage.qml+7 tests/qmltests/Stage/tst_PhoneStage.qml+5 tests/qmltests/Stage/tst_TabletStage.qml+5
plugins/WindowManager/AvailableDesktopArea.cppnew file+50
@@ -0,0 +1,50 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "AvailableDesktopArea.h"
18+
19+#include <QGuiApplication>
20+#include <QQuickWindow>
21+#include <qpa/qplatformnativeinterface.h>
22+
23+AvailableDesktopArea::AvailableDesktopArea(QQuickItem *parent)
24+ : QQuickItem(parent)
25+{
26+ connect(this, &QQuickItem::xChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
27+ connect(this, &QQuickItem::yChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
28+ connect(this, &QQuickItem::widthChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
29+ connect(this, &QQuickItem::heightChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
30+}
31+
32+void AvailableDesktopArea::updatePlatformWindowProperty()
33+{
34+ if (!window()) {
35+ return;
36+ }
37+
38+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
39+
40+ QRect rect(x(), y(), width(), height());
41+
42+ nativeInterface->setWindowProperty(window()->handle(), "availableDesktopArea", QVariant(rect));
43+}
44+
45+void AvailableDesktopArea::itemChange(ItemChange change, const ItemChangeData &)
46+{
47+ if (change == ItemSceneChange) {
48+ updatePlatformWindowProperty();
49+ }
50+}
plugins/WindowManager/AvailableDesktopArea.hnew file+38
@@ -0,0 +1,38 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef AVAILABLEDESKTOPAREA_H
18+#define AVAILABLEDESKTOPAREA_H
19+
20+#include <QQuickItem>
21+
22+/**
23+ @brief Used to inform qtmir/miral about the available desktop area of shell
24+
25+ So that qtmir/miral can take correct window management decisions.
26+ */
27+class AvailableDesktopArea : public QQuickItem
28+{
29+ Q_OBJECT
30+public:
31+ AvailableDesktopArea(QQuickItem *parent = nullptr);
32+protected:
33+ void itemChange(ItemChange change, const ItemChangeData &value) override;
34+private Q_SLOTS:
35+ void updatePlatformWindowProperty();
36+};
37+
38+#endif // AVAILABLEDESKTOPAREA_H
plugins/WindowManager/CMakeLists.txt+7
@@ -1,7 +1,9 @@
11set(WINDOWMANAGER_SRC
2+ AvailableDesktopArea.cpp
23 TopLevelWindowModel.cpp
34 Window.cpp
45 WindowManagerPlugin.cpp
6+ WindowMargins.cpp
57 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
68 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
79 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
@@ -11,6 +13,11 @@ set(WINDOWMANAGER_SRC
1113
1214add_definitions(-DWINDOWMANAGERQML_LIBRARY)
1315
16+include_directories(
17+ SYSTEM
18+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
19+)
20+
1421add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
1522
1623qt5_use_modules(windowmanager-qml Qml Quick Gui)
plugins/WindowManager/WindowManagerPlugin.cpp+5−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -16,14 +16,18 @@
1616
1717#include "WindowManagerPlugin.h"
1818
19+#include "AvailableDesktopArea.h"
1920#include "TopLevelWindowModel.h"
2021#include "Window.h"
22+#include "WindowMargins.h"
2123
2224#include <QtQml>
2325
2426void WindowManagerPlugin::registerTypes(const char *uri)
2527{
28+ qmlRegisterType<AvailableDesktopArea>(uri, 1, 0, "AvailableDesktopArea");
2629 qmlRegisterType<TopLevelWindowModel>(uri, 1, 0, "TopLevelWindowModel");
30+ qmlRegisterType<WindowMargins>(uri, 1, 0, "WindowMargins");
2731
2832 qRegisterMetaType<Window*>("Window*");
2933
plugins/WindowManager/WindowMargins.cppnew file+74
@@ -0,0 +1,74 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "WindowMargins.h"
18+
19+#include <QGuiApplication>
20+#include <QQuickWindow>
21+#include <qpa/qplatformnativeinterface.h>
22+
23+void WindowMargins::setNormal(QRectF value)
24+{
25+ if (m_normal == value) {
26+ return;
27+ }
28+
29+ m_normal = value;
30+
31+ if (window()) {
32+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
33+ nativeInterface->setWindowProperty(window()->handle(), "normalWindowMargins", QVariant(m_normal.toRect()));
34+ }
35+
36+ Q_EMIT normalChanged();
37+}
38+
39+QRectF WindowMargins::normal() const
40+{
41+ return m_normal;
42+}
43+
44+void WindowMargins::setDialog(QRectF value)
45+{
46+ if (m_dialog == value) {
47+ return;
48+ }
49+
50+ m_dialog = value;
51+
52+ if (window()) {
53+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
54+ nativeInterface->setWindowProperty(window()->handle(), "dialogWindowMargins", QVariant(m_dialog.toRect()));
55+ }
56+
57+ Q_EMIT dialogChanged();
58+}
59+
60+QRectF WindowMargins::dialog() const
61+{
62+ return m_dialog;
63+}
64+
65+void WindowMargins::itemChange(ItemChange change, const ItemChangeData &data)
66+{
67+ if (change == ItemSceneChange && data.window != nullptr) {
68+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
69+ if (!m_normal.isNull()) {
70+ nativeInterface->setWindowProperty(data.window->handle(), "normalWindowMargins", QVariant(m_normal.toRect()));
71+ nativeInterface->setWindowProperty(data.window->handle(), "dialogWindowMargins", QVariant(m_dialog.toRect()));
72+ }
73+ }
74+}
plugins/WindowManager/WindowMargins.hnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef WINDOWMARGINS_H
18+#define WINDOWMARGINS_H
19+
20+#include <QQuickItem>
21+#include <QRectF>
22+
23+/*
24+ * Specifies window margins for different Mir window types
25+ *
26+ * Used to inform MirAL so that it can take window management decisions that match
27+ * the visuals drawn by Unity.
28+ */
29+class WindowMargins : public QQuickItem
30+{
31+ Q_OBJECT
32+
33+ // Margins for windows of normal type
34+ Q_PROPERTY(QRectF normal READ normal WRITE setNormal NOTIFY normalChanged)
35+
36+ // Margins for windows of dialog type
37+ Q_PROPERTY(QRectF dialog READ dialog WRITE setDialog NOTIFY dialogChanged)
38+
39+ // TODO: Add margins for other window types as needed
40+
41+public:
42+ QRectF normal() const;
43+ void setNormal(QRectF value);
44+
45+ QRectF dialog() const;
46+ void setDialog(QRectF value);
47+
48+protected:
49+ void itemChange(ItemChange change, const ItemChangeData &value) override;
50+
51+Q_SIGNALS:
52+ void normalChanged();
53+ void dialogChanged();
54+private:
55+ QRectF m_normal;
56+ QRectF m_dialog;
57+};
58+
59+#endif // WINDOWMARGINS_H
qml/Shell.qml+8−1
@@ -255,6 +255,13 @@ StyledItem {
255255 }
256256 }
257257
258+ AvailableDesktopArea {
259+ id: availableDesktopAreaItem
260+ anchors.fill: parent
261+ anchors.topMargin: panel.fullscreenMode ? 0 : panel.minimizedPanelHeight
262+ anchors.leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
263+ }
264+
258265 GSettings {
259266 id: settings
260267 schema.id: "com.canonical.Unity8"
@@ -290,6 +297,7 @@ StyledItem {
290297 topLevelSurfaceList: topLevelSurfaceList
291298 inputMethodRect: inputMethod.visibleRect
292299 rightEdgePushProgress: rightEdgeBarrier.progress
300+ availableDesktopArea: availableDesktopAreaItem
293301
294302 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
295303 ? "phone"
@@ -311,7 +319,6 @@ StyledItem {
311319
312320 onInteractiveChanged: { if (interactive) { focus = true; } }
313321
314− leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
315322 suspended: greeter.shown
316323 altTabPressed: physicalKeysMapper.altTabPressed
317324 oskEnabled: shell.oskEnabled
qml/Stage/ChildWindow.qml+8−1
@@ -28,6 +28,7 @@ FocusScope {
2828 property Item target
2929 property alias requestedWidth: surfaceContainer.requestedWidth
3030 property alias requestedHeight: surfaceContainer.requestedHeight
31+ property real decorationHeight
3132
3233 width: surface ? surface.size.width : 0
3334 height: surface ? surface.size.height : 0
@@ -99,7 +100,8 @@ FocusScope {
99100
100101 sourceComponent: Component {
101102 WindowDecoration {
102− height: units.gu(3)
103+ id: windowDecoration
104+ height: root.decorationHeight
103105 title: root.surface ? root.surface.name : ""
104106 active: root.surface ? root.surface.focused : false
105107 closeButtonVisible: root.surface ? root.surface.type === Mir.SatelliteType
@@ -115,6 +117,11 @@ FocusScope {
115117 }
116118 onReleased: if (d.moveHandler) { d.moveHandler.handleReleased(); }
117119 onCloseClicked: root.surface.close();
120+ Binding {
121+ target: root.surface
122+ property: "topMargin"
123+ value: windowDecoration.height
124+ }
118125 }
119126 }
120127 }
qml/Stage/ChildWindowTree.qml+1
@@ -25,6 +25,7 @@ FocusScope {
2525 property real displacementX: 0
2626 property real displacementY: 0
2727 property alias boundsItem: childWindow.boundsItem
28+ property alias decorationHeight: childWindow.decorationHeight
2829
2930 x: surface ? surface.position.x + displacementX : 0
3031 y: surface ? surface.position.y + displacementY : 0
qml/Stage/DecoratedWindow.qml+14−7
@@ -43,6 +43,7 @@ FocusScope {
4343 property bool hasDecoration: true
4444 // This will temporarily show/hide the decoration without actually changing the surface's dimensions
4545 property real showDecoration: 1
46+ property alias decorationHeight: decoration.height
4647 property bool animateDecoration: false
4748 property bool showHighlight: false
4849 property int highlightSize: units.gu(1)
@@ -55,11 +56,15 @@ FocusScope {
5556 property int scaleToPreviewSize: units.gu(30)
5657
5758 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
58− readonly property real decorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
59+
60+ // Height of the decoration that's actually being displayed at this moment. Will match decorationHeight
61+ // when the decoration is being fully displayed
62+ readonly property real actualDecorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
63+
5964 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
6065
6166 readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
62− readonly property int minimumHeight: decorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
67+ readonly property int minimumHeight: actualDecorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
6368 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
6469 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
6570 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
@@ -74,6 +79,8 @@ FocusScope {
7479
7580 property alias altDragEnabled: altDragHandler.enabled
7681
82+ property Item windowMargins
83+
7784 signal closeClicked()
7885 signal maximizeClicked()
7986 signal maximizeHorizontallyClicked()
@@ -102,7 +109,7 @@ FocusScope {
102109 PropertyChanges {
103110 target: root
104111 implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
105− implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
112+ implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
106113 }
107114 },
108115 State {
@@ -111,7 +118,7 @@ FocusScope {
111118 PropertyChanges {
112119 target: root
113120 implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
114− implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
121+ implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
115122 }
116123 },
117124 State {
@@ -150,7 +157,7 @@ FocusScope {
150157 margins: active ? -units.gu(2) : -units.gu(1.5)
151158 }
152159 height: Math.min(applicationWindow.implicitHeight, applicationWindow.height) * applicationWindow.itemScale
153− + root.decorationHeight * Math.min(1, root.showDecoration) + (active ? units.gu(4) : units.gu(3))
160+ + root.actualDecorationHeight * Math.min(1, root.showDecoration) + (active ? units.gu(4) : units.gu(3))
154161 source: "../graphics/dropshadow2gu.sci"
155162 opacity: root.shadowOpacity
156163 }
@@ -159,7 +166,7 @@ FocusScope {
159166 id: applicationWindow
160167 objectName: "appWindow"
161168 anchors.top: parent.top
162− anchors.topMargin: root.decorationHeight * Math.min(1, root.showDecoration)
169+ anchors.topMargin: root.actualDecorationHeight * Math.min(1, root.showDecoration)
163170 anchors.left: parent.left
164171 width: implicitWidth
165172 height: implicitHeight
@@ -207,7 +214,7 @@ FocusScope {
207214 objectName: "appWindowDecoration"
208215
209216 anchors { left: parent.left; top: parent.top; right: parent.right }
210− height: units.gu(3)
217+ height: units.gu(3) // a default value. overwritten by root.decorationHeight
211218
212219 title: applicationWindow.title
213220 windowMoving: moveHandler.moving && !altDragHandler.dragging
qml/Stage/Stage.qml+57−47
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014-2016 Canonical, Ltd.
2+ * Copyright (C) 2014-2017 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@ import GlobalShortcut 1.0
2525import GSettings 1.0
2626import "Spread"
2727import "Spread/MathUtils.js" as MathUtils
28+import WindowManager 1.0
2829
2930FocusScope {
3031 id: root
@@ -43,10 +44,10 @@ FocusScope {
4344 property int shellOrientationAngle
4445 property bool spreadEnabled: true // If false, animations and right edge will be disabled
4546 property bool suspended
46− property int leftMargin: 0
4747 property bool oskEnabled: false
4848 property rect inputMethodRect
4949 property real rightEdgePushProgress: 0
50+ property Item availableDesktopArea
5051
5152 // Configuration
5253 property string mode: "staged"
@@ -120,6 +121,12 @@ FocusScope {
120121 }
121122 }
122123
124+ // For MirAL window management
125+ WindowMargins {
126+ normal: Qt.rect(0, root.mode === "windowed" ? priv.windowDecorationHeight : 0, 0, 0)
127+ dialog: normal
128+ }
129+
123130 property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.window.confinesMousePointer ?
124131 priv.focusedAppDelegate.clientAreaItem : null;
125132
@@ -347,6 +354,8 @@ FocusScope {
347354 }
348355
349356 readonly property real virtualKeyboardHeight: root.inputMethodRect.height
357+
358+ readonly property real windowDecorationHeight: units.gu(3)
350359 }
351360
352361 Component.onCompleted: priv.updateMainAndSideStageIndexes();
@@ -567,7 +576,7 @@ FocusScope {
567576 id: spreadItem
568577 objectName: "spreadItem"
569578 anchors.fill: appContainer
570− leftMargin: root.leftMargin
579+ leftMargin: root.availableDesktopArea.x
571580 model: root.topLevelSurfaceList
572581 spreadFlickable: floatingFlickable
573582 z: 10
@@ -675,13 +684,6 @@ FocusScope {
675684 }
676685 }
677686
678− Item {
679− id: boundariesForWindowPlacement
680− anchors.fill: parent
681− anchors.topMargin: PanelState.panelHeight
682− visible: false
683− }
684−
685687 Repeater {
686688 id: appRepeater
687689 model: topLevelSurfaceList
@@ -779,7 +781,7 @@ FocusScope {
779781 target: appDelegate
780782 property: "y"
781783 value: appDelegate.requestedY -
782− Math.min(appDelegate.requestedY - PanelState.panelHeight,
784+ Math.min(appDelegate.requestedY - root.availableDesktopArea.y,
783785 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
784786 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
785787 && root.inputMethodRect.height > 0
@@ -797,8 +799,8 @@ FocusScope {
797799 angleDiff = (360 + angleDiff) % 360;
798800 if (angleDiff === 90 || angleDiff === 270) {
799801 var aux = decoratedWindow.requestedHeight;
800− decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.decorationHeight;
801− decoratedWindow.requestedWidth = aux - decoratedWindow.decorationHeight;
802+ decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.actualDecorationHeight;
803+ decoratedWindow.requestedWidth = aux - decoratedWindow.actualDecorationHeight;
802804 }
803805 }
804806 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
@@ -914,8 +916,8 @@ FocusScope {
914916 target: appDelegate
915917 screenWidth: appContainer.width
916918 screenHeight: appContainer.height
917− leftMargin: root.leftMargin
918− minimumY: boundariesForWindowPlacement.y
919+ leftMargin: root.availableDesktopArea.x
920+ minimumY: root.availableDesktopArea.y
919921 }
920922
921923 Connections {
@@ -1167,7 +1169,7 @@ FocusScope {
11671169
11681170 StagedRightEdgeMaths {
11691171 id: stagedRightEdgeMaths
1170− sceneWidth: appContainer.width - root.leftMargin
1172+ sceneWidth: root.availableDesktopArea.width
11711173 sceneHeight: appContainer.height
11721174 isMainStageApp: priv.mainStageDelegate == appDelegate
11731175 isSideStageApp: priv.sideStageDelegate == appDelegate
@@ -1178,7 +1180,7 @@ FocusScope {
11781180 progress: 0
11791181 targetHeight: spreadItem.stackHeight
11801182 targetX: spreadMaths.targetX
1181− startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1183+ startY: appDelegate.fullscreen ? 0 : root.availableDesktopArea.y
11821184 targetY: spreadMaths.targetY
11831185 targetAngle: spreadMaths.targetAngle
11841186 targetScale: spreadMaths.targetScale
@@ -1299,9 +1301,9 @@ FocusScope {
12991301 PropertyChanges {
13001302 target: appDelegate
13011303 x: stageMaths.itemX
1302− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1304+ y: root.availableDesktopArea.y
13031305 requestedWidth: appContainer.width
1304− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1306+ requestedHeight: root.availableDesktopArea.height
13051307 visuallyMaximized: true
13061308 visible: appDelegate.x < root.width
13071309 }
@@ -1331,10 +1333,10 @@ FocusScope {
13311333 PropertyChanges {
13321334 target: appDelegate
13331335 x: stageMaths.itemX
1334− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1336+ y: root.availableDesktopArea.y
13351337 z: stageMaths.itemZ
13361338 requestedWidth: stageMaths.itemWidth
1337− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1339+ requestedHeight: root.availableDesktopArea.height
13381340 visuallyMaximized: true
13391341 visible: appDelegate.x < root.width
13401342 }
@@ -1355,11 +1357,11 @@ FocusScope {
13551357 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
13561358 PropertyChanges {
13571359 target: appDelegate;
1358− requestedX: root.leftMargin;
1360+ requestedX: root.availableDesktopArea.x;
13591361 requestedY: 0;
13601362 visuallyMinimized: false;
13611363 visuallyMaximized: true
1362− requestedWidth: appContainer.width - root.leftMargin;
1364+ requestedWidth: root.availableDesktopArea.width;
13631365 requestedHeight: appContainer.height;
13641366 }
13651367 PropertyChanges { target: touchControls; enabled: true }
@@ -1402,10 +1404,10 @@ FocusScope {
14021404 extend: "normal"
14031405 PropertyChanges {
14041406 target: appDelegate
1405− windowedX: root.leftMargin
1406− windowedY: PanelState.panelHeight
1407− windowedWidth: (appContainer.width - root.leftMargin)/2
1408− windowedHeight: appContainer.height - PanelState.panelHeight
1407+ windowedX: root.availableDesktopArea.x
1408+ windowedY: root.availableDesktopArea.y
1409+ windowedWidth: root.availableDesktopArea.width / 2
1410+ windowedHeight: root.availableDesktopArea.height
14091411 }
14101412 },
14111413 State {
@@ -1413,7 +1415,7 @@ FocusScope {
14131415 extend: "maximizedLeft"
14141416 PropertyChanges {
14151417 target: appDelegate;
1416− windowedX: (appContainer.width + root.leftMargin)/2
1418+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
14171419 }
14181420 },
14191421 State {
@@ -1421,10 +1423,10 @@ FocusScope {
14211423 extend: "normal"
14221424 PropertyChanges {
14231425 target: appDelegate
1424− windowedX: root.leftMargin
1425− windowedY: PanelState.panelHeight
1426− windowedWidth: (appContainer.width - root.leftMargin)/2
1427− windowedHeight: (appContainer.height - PanelState.panelHeight)/2
1426+ windowedX: root.availableDesktopArea.x
1427+ windowedY: root.availableDesktopArea.y
1428+ windowedWidth: root.availableDesktopArea.width / 2
1429+ windowedHeight: root.availableDesktopArea.height / 2
14281430 }
14291431 },
14301432 State {
@@ -1432,7 +1434,7 @@ FocusScope {
14321434 extend: "maximizedTopLeft"
14331435 PropertyChanges {
14341436 target: appDelegate
1435− windowedX: (appContainer.width + root.leftMargin)/2
1437+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
14361438 }
14371439 },
14381440 State {
@@ -1440,10 +1442,10 @@ FocusScope {
14401442 extend: "normal"
14411443 PropertyChanges {
14421444 target: appDelegate
1443− windowedX: root.leftMargin
1444− windowedY: (appContainer.height + PanelState.panelHeight)/2
1445− windowedWidth: (appContainer.width - root.leftMargin)/2
1446− windowedHeight: appContainer.height/2
1445+ windowedX: root.availableDesktopArea.x
1446+ windowedY: root.availableDesktopArea.y + (root.availableDesktopArea.height / 2)
1447+ windowedWidth: root.availableDesktopArea.width / 2
1448+ windowedHeight: root.availableDesktopArea.height / 2
14471449 }
14481450 },
14491451 State {
@@ -1451,20 +1453,26 @@ FocusScope {
14511453 extend: "maximizedBottomLeft"
14521454 PropertyChanges {
14531455 target: appDelegate
1454− windowedX: (appContainer.width + root.leftMargin)/2
1456+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
14551457 }
14561458 },
14571459 State {
14581460 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
14591461 extend: "normal"
1460− PropertyChanges { target: appDelegate; windowedX: root.leftMargin; windowedY: windowedY;
1461− windowedWidth: appContainer.width - root.leftMargin; windowedHeight: windowedHeight }
1462+ PropertyChanges {
1463+ target: appDelegate
1464+ windowedX: root.availableDesktopArea.x; windowedY: windowedY
1465+ windowedWidth: root.availableDesktopArea.width; windowedHeight: windowedHeight
1466+ }
14621467 },
14631468 State {
14641469 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
14651470 extend: "normal"
1466− PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: PanelState.panelHeight;
1467− windowedWidth: windowedWidth; windowedHeight: appContainer.height - PanelState.panelHeight }
1471+ PropertyChanges {
1472+ target: appDelegate
1473+ windowedX: windowedX; windowedY: root.availableDesktopArea.y
1474+ windowedWidth: windowedWidth; windowedHeight: root.availableDesktopArea.height
1475+ }
14681476 },
14691477 State {
14701478 name: "minimized"; when: appDelegate.minimized
@@ -1592,7 +1600,7 @@ FocusScope {
15921600 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
15931601
15941602 target: appDelegate
1595− boundsItem: boundariesForWindowPlacement
1603+ boundsItem: root.availableDesktopArea
15961604 minWidth: units.gu(10)
15971605 minHeight: units.gu(10)
15981606 borderThickness: units.gu(2)
@@ -1615,13 +1623,14 @@ FocusScope {
16151623 focus: true
16161624 interactive: root.interactive
16171625 showDecoration: 1
1626+ decorationHeight: priv.windowDecorationHeight
16181627 maximizeButtonShown: appDelegate.canBeMaximized
16191628 overlayShown: touchControls.overlayShown
16201629 width: implicitWidth
16211630 height: implicitHeight
16221631 highlightSize: windowInfoItem.iconMargin / 2
1623− boundsItem: boundariesForWindowPlacement
16241632 altDragEnabled: root.mode == "windowed"
1633+ boundsItem: root.availableDesktopArea
16251634
16261635 requestedWidth: appDelegate.requestedWidth
16271636 requestedHeight: appDelegate.requestedHeight
@@ -1684,7 +1693,7 @@ FocusScope {
16841693 resizeArea: resizeArea
16851694 enabled: false
16861695 visible: enabled
1687− boundsItem: boundariesForWindowPlacement
1696+ boundsItem: root.availableDesktopArea
16881697
16891698 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
16901699 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
@@ -1805,7 +1814,8 @@ FocusScope {
18051814 displacementX: appDelegate.clientAreaItem.x
18061815 displacementY: appDelegate.clientAreaItem.y
18071816
1808− boundsItem: boundariesForWindowPlacement
1817+ boundsItem: root.availableDesktopArea
1818+ decorationHeight: priv.windowDecorationHeight
18091819
18101820 z: childWindowRepeater.count - model.index
18111821
@@ -1826,7 +1836,7 @@ FocusScope {
18261836 FakeMaximizeDelegate {
18271837 id: fakeRectangle
18281838 target: priv.focusedAppDelegate
1829− leftMargin: root.leftMargin
1839+ leftMargin: root.availableDesktopArea.x
18301840 appContainerWidth: appContainer.width
18311841 appContainerHeight: appContainer.height
18321842 }
tests/qmltests/Stage/tst_DesktopStage.qml+7
@@ -100,8 +100,15 @@ Item {
100100 orientations: Orientations {}
101101 applicationManager: ApplicationManager
102102 topLevelSurfaceList: topSurfaceList
103+ availableDesktopArea: availableDesktopAreaItem
103104 interactive: true
104105 mode: "windowed"
106+
107+ Item {
108+ id: availableDesktopAreaItem
109+ anchors.fill: parent
110+ anchors.topMargin: PanelState.panelHeight
111+ }
105112 }
106113 }
107114 }
tests/qmltests/Stage/tst_PhoneStage.qml+5
@@ -52,6 +52,11 @@ Item {
5252 applicationManager: ApplicationManager
5353 surfaceManager: sMgr
5454 }
55+ availableDesktopArea: availableDesktopAreaItem
56+ Item {
57+ id: availableDesktopAreaItem
58+ anchors.fill: parent
59+ }
5560 Component.onCompleted: {
5661 ApplicationManager.startApplication("unity8-dash");
5762 }
tests/qmltests/Stage/tst_TabletStage.qml+5
@@ -61,6 +61,11 @@ Rectangle {
6161 applicationManager: ApplicationManager
6262 surfaceManager: sMgr
6363 }
64+ availableDesktopArea: availableDesktopAreaItem
65+ Item {
66+ id: availableDesktopAreaItem
67+ anchors.fill: parent
68+ }
6469 Component.onCompleted: {
6570 ApplicationManager.startApplication("unity8-dash");
6671 }