on xenial help sign in
Tell qtmir/miral about the available desktop area
d52069aDaniel d'Andrada
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 @@
1set(WINDOWMANAGER_SRC
1set(WINDOWMANAGER_SRC
2+ AvailableDesktopArea.cpp
2 TopLevelWindowModel.cpp
3 TopLevelWindowModel.cpp
3 Window.cpp
4 Window.cpp
4 WindowManagerPlugin.cpp
5 WindowManagerPlugin.cpp
6+ WindowMargins.cpp
5 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
7 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
6 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
8 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
7 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
9 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
@@ -11,6 +13,11 @@ set(WINDOWMANAGER_SRC
11
13
12add_definitions(-DWINDOWMANAGERQML_LIBRARY)
14add_definitions(-DWINDOWMANAGERQML_LIBRARY)
13
15
16+include_directories(
17+ SYSTEM
18+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
19+)
20+
14add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
21add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
15
22
16qt5_use_modules(windowmanager-qml Qml Quick Gui)
23qt5_use_modules(windowmanager-qml Qml Quick Gui)
plugins/WindowManager/WindowManagerPlugin.cpp+5−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -16,14 +16,18 @@
16
16
17#include "WindowManagerPlugin.h"
17#include "WindowManagerPlugin.h"
18
18
19+#include "AvailableDesktopArea.h"
19#include "TopLevelWindowModel.h"
20#include "TopLevelWindowModel.h"
20#include "Window.h"
21#include "Window.h"
22+#include "WindowMargins.h"
21
23
22#include <QtQml>
24#include <QtQml>
23
25
24void WindowManagerPlugin::registerTypes(const char *uri)
26void WindowManagerPlugin::registerTypes(const char *uri)
25{
27{
28+ qmlRegisterType<AvailableDesktopArea>(uri, 1, 0, "AvailableDesktopArea");
26 qmlRegisterType<TopLevelWindowModel>(uri, 1, 0, "TopLevelWindowModel");
29 qmlRegisterType<TopLevelWindowModel>(uri, 1, 0, "TopLevelWindowModel");
30+ qmlRegisterType<WindowMargins>(uri, 1, 0, "WindowMargins");
27
31
28 qRegisterMetaType<Window*>("Window*");
32 qRegisterMetaType<Window*>("Window*");
29
33
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 {
255 }
255 }
256 }
256 }
257
257
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+
258 GSettings {
265 GSettings {
259 id: settings
266 id: settings
260 schema.id: "com.canonical.Unity8"
267 schema.id: "com.canonical.Unity8"
@@ -290,6 +297,7 @@ StyledItem {
290 topLevelSurfaceList: topLevelSurfaceList
297 topLevelSurfaceList: topLevelSurfaceList
291 inputMethodRect: inputMethod.visibleRect
298 inputMethodRect: inputMethod.visibleRect
292 rightEdgePushProgress: rightEdgeBarrier.progress
299 rightEdgePushProgress: rightEdgeBarrier.progress
300+ availableDesktopArea: availableDesktopAreaItem
293
301
294 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
302 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
295 ? "phone"
303 ? "phone"
@@ -311,7 +319,6 @@ StyledItem {
311
319
312 onInteractiveChanged: { if (interactive) { focus = true; } }
320 onInteractiveChanged: { if (interactive) { focus = true; } }
313
321
314− leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
315 suspended: greeter.shown
322 suspended: greeter.shown
316 altTabPressed: physicalKeysMapper.altTabPressed
323 altTabPressed: physicalKeysMapper.altTabPressed
317 oskEnabled: shell.oskEnabled
324 oskEnabled: shell.oskEnabled
qml/Stage/ChildWindow.qml+8−1
@@ -28,6 +28,7 @@ FocusScope {
28 property Item target
28 property Item target
29 property alias requestedWidth: surfaceContainer.requestedWidth
29 property alias requestedWidth: surfaceContainer.requestedWidth
30 property alias requestedHeight: surfaceContainer.requestedHeight
30 property alias requestedHeight: surfaceContainer.requestedHeight
31+ property real decorationHeight
31
32
32 width: surface ? surface.size.width : 0
33 width: surface ? surface.size.width : 0
33 height: surface ? surface.size.height : 0
34 height: surface ? surface.size.height : 0
@@ -99,7 +100,8 @@ FocusScope {
99
100
100 sourceComponent: Component {
101 sourceComponent: Component {
101 WindowDecoration {
102 WindowDecoration {
102− height: units.gu(3)
103+ id: windowDecoration
104+ height: root.decorationHeight
103 title: root.surface ? root.surface.name : ""
105 title: root.surface ? root.surface.name : ""
104 active: root.surface ? root.surface.focused : false
106 active: root.surface ? root.surface.focused : false
105 closeButtonVisible: root.surface ? root.surface.type === Mir.SatelliteType
107 closeButtonVisible: root.surface ? root.surface.type === Mir.SatelliteType
@@ -115,6 +117,11 @@ FocusScope {
115 }
117 }
116 onReleased: if (d.moveHandler) { d.moveHandler.handleReleased(); }
118 onReleased: if (d.moveHandler) { d.moveHandler.handleReleased(); }
117 onCloseClicked: root.surface.close();
119 onCloseClicked: root.surface.close();
120+ Binding {
121+ target: root.surface
122+ property: "topMargin"
123+ value: windowDecoration.height
124+ }
118 }
125 }
119 }
126 }
120 }
127 }
qml/Stage/ChildWindowTree.qml+1
@@ -25,6 +25,7 @@ FocusScope {
25 property real displacementX: 0
25 property real displacementX: 0
26 property real displacementY: 0
26 property real displacementY: 0
27 property alias boundsItem: childWindow.boundsItem
27 property alias boundsItem: childWindow.boundsItem
28+ property alias decorationHeight: childWindow.decorationHeight
28
29
29 x: surface ? surface.position.x + displacementX : 0
30 x: surface ? surface.position.x + displacementX : 0
30 y: surface ? surface.position.y + displacementY : 0
31 y: surface ? surface.position.y + displacementY : 0
qml/Stage/DecoratedWindow.qml+14−7
@@ -43,6 +43,7 @@ FocusScope {
43 property bool hasDecoration: true
43 property bool hasDecoration: true
44 // This will temporarily show/hide the decoration without actually changing the surface's dimensions
44 // This will temporarily show/hide the decoration without actually changing the surface's dimensions
45 property real showDecoration: 1
45 property real showDecoration: 1
46+ property alias decorationHeight: decoration.height
46 property bool animateDecoration: false
47 property bool animateDecoration: false
47 property bool showHighlight: false
48 property bool showHighlight: false
48 property int highlightSize: units.gu(1)
49 property int highlightSize: units.gu(1)
@@ -55,11 +56,15 @@ FocusScope {
55 property int scaleToPreviewSize: units.gu(30)
56 property int scaleToPreviewSize: units.gu(30)
56
57
57 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
58 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
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
58− readonly property real decorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
62+ readonly property real actualDecorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
63+
59 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
64 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
60
65
61 readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
66 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)
63 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
68 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
64 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
69 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
65 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
70 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
@@ -74,6 +79,8 @@ FocusScope {
74
79
75 property alias altDragEnabled: altDragHandler.enabled
80 property alias altDragEnabled: altDragHandler.enabled
76
81
82+ property Item windowMargins
83+
77 signal closeClicked()
84 signal closeClicked()
78 signal maximizeClicked()
85 signal maximizeClicked()
79 signal maximizeHorizontallyClicked()
86 signal maximizeHorizontallyClicked()
@@ -102,7 +109,7 @@ FocusScope {
102 PropertyChanges {
109 PropertyChanges {
103 target: root
110 target: root
104 implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
111 implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
105− implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
112+ implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
106 }
113 }
107 },
114 },
108 State {
115 State {
@@ -111,7 +118,7 @@ FocusScope {
111 PropertyChanges {
118 PropertyChanges {
112 target: root
119 target: root
113 implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
120 implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
114− implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
121+ implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
115 }
122 }
116 },
123 },
117 State {
124 State {
@@ -150,7 +157,7 @@ FocusScope {
150 margins: active ? -units.gu(2) : -units.gu(1.5)
157 margins: active ? -units.gu(2) : -units.gu(1.5)
151 }
158 }
152 height: Math.min(applicationWindow.implicitHeight, applicationWindow.height) * applicationWindow.itemScale
159 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))
154 source: "../graphics/dropshadow2gu.sci"
161 source: "../graphics/dropshadow2gu.sci"
155 opacity: root.shadowOpacity
162 opacity: root.shadowOpacity
156 }
163 }
@@ -159,7 +166,7 @@ FocusScope {
159 id: applicationWindow
166 id: applicationWindow
160 objectName: "appWindow"
167 objectName: "appWindow"
161 anchors.top: parent.top
168 anchors.top: parent.top
162− anchors.topMargin: root.decorationHeight * Math.min(1, root.showDecoration)
169+ anchors.topMargin: root.actualDecorationHeight * Math.min(1, root.showDecoration)
163 anchors.left: parent.left
170 anchors.left: parent.left
164 width: implicitWidth
171 width: implicitWidth
165 height: implicitHeight
172 height: implicitHeight
@@ -207,7 +214,7 @@ FocusScope {
207 objectName: "appWindowDecoration"
214 objectName: "appWindowDecoration"
208
215
209 anchors { left: parent.left; top: parent.top; right: parent.right }
216 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
211
218
212 title: applicationWindow.title
219 title: applicationWindow.title
213 windowMoving: moveHandler.moving && !altDragHandler.dragging
220 windowMoving: moveHandler.moving && !altDragHandler.dragging
qml/Stage/Stage.qml+57−47
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014-2016 Canonical, Ltd.
2+ * Copyright (C) 2014-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@ import GlobalShortcut 1.0
25import GSettings 1.0
25import GSettings 1.0
26import "Spread"
26import "Spread"
27import "Spread/MathUtils.js" as MathUtils
27import "Spread/MathUtils.js" as MathUtils
28+import WindowManager 1.0
28
29
29FocusScope {
30FocusScope {
30 id: root
31 id: root
@@ -43,10 +44,10 @@ FocusScope {
43 property int shellOrientationAngle
44 property int shellOrientationAngle
44 property bool spreadEnabled: true // If false, animations and right edge will be disabled
45 property bool spreadEnabled: true // If false, animations and right edge will be disabled
45 property bool suspended
46 property bool suspended
46− property int leftMargin: 0
47 property bool oskEnabled: false
47 property bool oskEnabled: false
48 property rect inputMethodRect
48 property rect inputMethodRect
49 property real rightEdgePushProgress: 0
49 property real rightEdgePushProgress: 0
50+ property Item availableDesktopArea
50
51
51 // Configuration
52 // Configuration
52 property string mode: "staged"
53 property string mode: "staged"
@@ -120,6 +121,12 @@ FocusScope {
120 }
121 }
121 }
122 }
122
123
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+
123 property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.window.confinesMousePointer ?
130 property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.window.confinesMousePointer ?
124 priv.focusedAppDelegate.clientAreaItem : null;
131 priv.focusedAppDelegate.clientAreaItem : null;
125
132
@@ -367,6 +374,8 @@ FocusScope {
367 }
374 }
368
375
369 readonly property real virtualKeyboardHeight: root.inputMethodRect.height
376 readonly property real virtualKeyboardHeight: root.inputMethodRect.height
377+
378+ readonly property real windowDecorationHeight: units.gu(3)
370 }
379 }
371
380
372 Component.onCompleted: priv.updateMainAndSideStageIndexes();
381 Component.onCompleted: priv.updateMainAndSideStageIndexes();
@@ -587,7 +596,7 @@ FocusScope {
587 id: spreadItem
596 id: spreadItem
588 objectName: "spreadItem"
597 objectName: "spreadItem"
589 anchors.fill: appContainer
598 anchors.fill: appContainer
590− leftMargin: root.leftMargin
599+ leftMargin: root.availableDesktopArea.x
591 model: root.topLevelSurfaceList
600 model: root.topLevelSurfaceList
592 spreadFlickable: floatingFlickable
601 spreadFlickable: floatingFlickable
593 z: 10
602 z: 10
@@ -695,13 +704,6 @@ FocusScope {
695 }
704 }
696 }
705 }
697
706
698− Item {
699− id: boundariesForWindowPlacement
700− anchors.fill: parent
701− anchors.topMargin: PanelState.panelHeight
702− visible: false
703− }
704−
705 Repeater {
707 Repeater {
706 id: appRepeater
708 id: appRepeater
707 model: topLevelSurfaceList
709 model: topLevelSurfaceList
@@ -799,7 +801,7 @@ FocusScope {
799 target: appDelegate
801 target: appDelegate
800 property: "y"
802 property: "y"
801 value: appDelegate.requestedY -
803 value: appDelegate.requestedY -
802− Math.min(appDelegate.requestedY - PanelState.panelHeight,
804+ Math.min(appDelegate.requestedY - root.availableDesktopArea.y,
803 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
805 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
804 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
806 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
805 && root.inputMethodRect.height > 0
807 && root.inputMethodRect.height > 0
@@ -817,8 +819,8 @@ FocusScope {
817 angleDiff = (360 + angleDiff) % 360;
819 angleDiff = (360 + angleDiff) % 360;
818 if (angleDiff === 90 || angleDiff === 270) {
820 if (angleDiff === 90 || angleDiff === 270) {
819 var aux = decoratedWindow.requestedHeight;
821 var aux = decoratedWindow.requestedHeight;
820− decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.decorationHeight;
822+ decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.actualDecorationHeight;
821− decoratedWindow.requestedWidth = aux - decoratedWindow.decorationHeight;
823+ decoratedWindow.requestedWidth = aux - decoratedWindow.actualDecorationHeight;
822 }
824 }
823 }
825 }
824 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
826 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
@@ -934,8 +936,8 @@ FocusScope {
934 target: appDelegate
936 target: appDelegate
935 screenWidth: appContainer.width
937 screenWidth: appContainer.width
936 screenHeight: appContainer.height
938 screenHeight: appContainer.height
937− leftMargin: root.leftMargin
939+ leftMargin: root.availableDesktopArea.x
938− minimumY: boundariesForWindowPlacement.y
940+ minimumY: root.availableDesktopArea.y
939 }
941 }
940
942
941 Connections {
943 Connections {
@@ -1187,7 +1189,7 @@ FocusScope {
1187
1189
1188 StagedRightEdgeMaths {
1190 StagedRightEdgeMaths {
1189 id: stagedRightEdgeMaths
1191 id: stagedRightEdgeMaths
1190− sceneWidth: appContainer.width - root.leftMargin
1192+ sceneWidth: root.availableDesktopArea.width
1191 sceneHeight: appContainer.height
1193 sceneHeight: appContainer.height
1192 isMainStageApp: priv.mainStageDelegate == appDelegate
1194 isMainStageApp: priv.mainStageDelegate == appDelegate
1193 isSideStageApp: priv.sideStageDelegate == appDelegate
1195 isSideStageApp: priv.sideStageDelegate == appDelegate
@@ -1198,7 +1200,7 @@ FocusScope {
1198 progress: 0
1200 progress: 0
1199 targetHeight: spreadItem.stackHeight
1201 targetHeight: spreadItem.stackHeight
1200 targetX: spreadMaths.targetX
1202 targetX: spreadMaths.targetX
1201− startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1203+ startY: appDelegate.fullscreen ? 0 : root.availableDesktopArea.y
1202 targetY: spreadMaths.targetY
1204 targetY: spreadMaths.targetY
1203 targetAngle: spreadMaths.targetAngle
1205 targetAngle: spreadMaths.targetAngle
1204 targetScale: spreadMaths.targetScale
1206 targetScale: spreadMaths.targetScale
@@ -1319,9 +1321,9 @@ FocusScope {
1319 PropertyChanges {
1321 PropertyChanges {
1320 target: appDelegate
1322 target: appDelegate
1321 x: stageMaths.itemX
1323 x: stageMaths.itemX
1322− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1324+ y: root.availableDesktopArea.y
1323 requestedWidth: appContainer.width
1325 requestedWidth: appContainer.width
1324− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1326+ requestedHeight: root.availableDesktopArea.height
1325 visuallyMaximized: true
1327 visuallyMaximized: true
1326 visible: appDelegate.x < root.width
1328 visible: appDelegate.x < root.width
1327 }
1329 }
@@ -1351,10 +1353,10 @@ FocusScope {
1351 PropertyChanges {
1353 PropertyChanges {
1352 target: appDelegate
1354 target: appDelegate
1353 x: stageMaths.itemX
1355 x: stageMaths.itemX
1354− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1356+ y: root.availableDesktopArea.y
1355 z: stageMaths.itemZ
1357 z: stageMaths.itemZ
1356 requestedWidth: stageMaths.itemWidth
1358 requestedWidth: stageMaths.itemWidth
1357− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1359+ requestedHeight: root.availableDesktopArea.height
1358 visuallyMaximized: true
1360 visuallyMaximized: true
1359 visible: appDelegate.x < root.width
1361 visible: appDelegate.x < root.width
1360 }
1362 }
@@ -1375,11 +1377,11 @@ FocusScope {
1375 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
1377 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
1376 PropertyChanges {
1378 PropertyChanges {
1377 target: appDelegate;
1379 target: appDelegate;
1378− requestedX: root.leftMargin;
1380+ requestedX: root.availableDesktopArea.x;
1379 requestedY: 0;
1381 requestedY: 0;
1380 visuallyMinimized: false;
1382 visuallyMinimized: false;
1381 visuallyMaximized: true
1383 visuallyMaximized: true
1382− requestedWidth: appContainer.width - root.leftMargin;
1384+ requestedWidth: root.availableDesktopArea.width;
1383 requestedHeight: appContainer.height;
1385 requestedHeight: appContainer.height;
1384 }
1386 }
1385 PropertyChanges { target: touchControls; enabled: true }
1387 PropertyChanges { target: touchControls; enabled: true }
@@ -1423,10 +1425,10 @@ FocusScope {
1423 extend: "normal"
1425 extend: "normal"
1424 PropertyChanges {
1426 PropertyChanges {
1425 target: appDelegate
1427 target: appDelegate
1426− windowedX: root.leftMargin
1428+ windowedX: root.availableDesktopArea.x
1427− windowedY: PanelState.panelHeight
1429+ windowedY: root.availableDesktopArea.y
1428− windowedWidth: (appContainer.width - root.leftMargin)/2
1430+ windowedWidth: root.availableDesktopArea.width / 2
1429− windowedHeight: appContainer.height - PanelState.panelHeight
1431+ windowedHeight: root.availableDesktopArea.height
1430 }
1432 }
1431 },
1433 },
1432 State {
1434 State {
@@ -1434,7 +1436,7 @@ FocusScope {
1434 extend: "maximizedLeft"
1436 extend: "maximizedLeft"
1435 PropertyChanges {
1437 PropertyChanges {
1436 target: appDelegate;
1438 target: appDelegate;
1437− windowedX: (appContainer.width + root.leftMargin)/2
1439+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
1438 }
1440 }
1439 },
1441 },
1440 State {
1442 State {
@@ -1442,10 +1444,10 @@ FocusScope {
1442 extend: "normal"
1444 extend: "normal"
1443 PropertyChanges {
1445 PropertyChanges {
1444 target: appDelegate
1446 target: appDelegate
1445− windowedX: root.leftMargin
1447+ windowedX: root.availableDesktopArea.x
1446− windowedY: PanelState.panelHeight
1448+ windowedY: root.availableDesktopArea.y
1447− windowedWidth: (appContainer.width - root.leftMargin)/2
1449+ windowedWidth: root.availableDesktopArea.width / 2
1448− windowedHeight: (appContainer.height - PanelState.panelHeight)/2
1450+ windowedHeight: root.availableDesktopArea.height / 2
1449 }
1451 }
1450 },
1452 },
1451 State {
1453 State {
@@ -1453,7 +1455,7 @@ FocusScope {
1453 extend: "maximizedTopLeft"
1455 extend: "maximizedTopLeft"
1454 PropertyChanges {
1456 PropertyChanges {
1455 target: appDelegate
1457 target: appDelegate
1456− windowedX: (appContainer.width + root.leftMargin)/2
1458+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
1457 }
1459 }
1458 },
1460 },
1459 State {
1461 State {
@@ -1461,10 +1463,10 @@ FocusScope {
1461 extend: "normal"
1463 extend: "normal"
1462 PropertyChanges {
1464 PropertyChanges {
1463 target: appDelegate
1465 target: appDelegate
1464− windowedX: root.leftMargin
1466+ windowedX: root.availableDesktopArea.x
1465− windowedY: (appContainer.height + PanelState.panelHeight)/2
1467+ windowedY: root.availableDesktopArea.y + (root.availableDesktopArea.height / 2)
1466− windowedWidth: (appContainer.width - root.leftMargin)/2
1468+ windowedWidth: root.availableDesktopArea.width / 2
1467− windowedHeight: appContainer.height/2
1469+ windowedHeight: root.availableDesktopArea.height / 2
1468 }
1470 }
1469 },
1471 },
1470 State {
1472 State {
@@ -1472,20 +1474,26 @@ FocusScope {
1472 extend: "maximizedBottomLeft"
1474 extend: "maximizedBottomLeft"
1473 PropertyChanges {
1475 PropertyChanges {
1474 target: appDelegate
1476 target: appDelegate
1475− windowedX: (appContainer.width + root.leftMargin)/2
1477+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
1476 }
1478 }
1477 },
1479 },
1478 State {
1480 State {
1479 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
1481 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
1480 extend: "normal"
1482 extend: "normal"
1483+ PropertyChanges {
1484+ target: appDelegate
1481− PropertyChanges { target: appDelegate; windowedX: root.leftMargin; windowedY: windowedY;
1485+ windowedX: root.availableDesktopArea.x; windowedY: windowedY
1482− windowedWidth: appContainer.width - root.leftMargin; windowedHeight: windowedHeight }
1486+ windowedWidth: root.availableDesktopArea.width; windowedHeight: windowedHeight
1487+ }
1483 },
1488 },
1484 State {
1489 State {
1485 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1490 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1486 extend: "normal"
1491 extend: "normal"
1492+ PropertyChanges {
1493+ target: appDelegate
1487− PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: PanelState.panelHeight;
1494+ windowedX: windowedX; windowedY: root.availableDesktopArea.y
1488− windowedWidth: windowedWidth; windowedHeight: appContainer.height - PanelState.panelHeight }
1495+ windowedWidth: windowedWidth; windowedHeight: root.availableDesktopArea.height
1496+ }
1489 },
1497 },
1490 State {
1498 State {
1491 name: "minimized"; when: appDelegate.minimized
1499 name: "minimized"; when: appDelegate.minimized
@@ -1613,7 +1621,7 @@ FocusScope {
1613 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1621 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1614
1622
1615 target: appDelegate
1623 target: appDelegate
1616− boundsItem: boundariesForWindowPlacement
1624+ boundsItem: root.availableDesktopArea
1617 minWidth: units.gu(10)
1625 minWidth: units.gu(10)
1618 minHeight: units.gu(10)
1626 minHeight: units.gu(10)
1619 borderThickness: units.gu(2)
1627 borderThickness: units.gu(2)
@@ -1636,13 +1644,14 @@ FocusScope {
1636 focus: true
1644 focus: true
1637 interactive: root.interactive
1645 interactive: root.interactive
1638 showDecoration: 1
1646 showDecoration: 1
1647+ decorationHeight: priv.windowDecorationHeight
1639 maximizeButtonShown: appDelegate.canBeMaximized
1648 maximizeButtonShown: appDelegate.canBeMaximized
1640 overlayShown: touchControls.overlayShown
1649 overlayShown: touchControls.overlayShown
1641 width: implicitWidth
1650 width: implicitWidth
1642 height: implicitHeight
1651 height: implicitHeight
1643 highlightSize: windowInfoItem.iconMargin / 2
1652 highlightSize: windowInfoItem.iconMargin / 2
1644− boundsItem: boundariesForWindowPlacement
1645 altDragEnabled: root.mode == "windowed"
1653 altDragEnabled: root.mode == "windowed"
1654+ boundsItem: root.availableDesktopArea
1646
1655
1647 requestedWidth: appDelegate.requestedWidth
1656 requestedWidth: appDelegate.requestedWidth
1648 requestedHeight: appDelegate.requestedHeight
1657 requestedHeight: appDelegate.requestedHeight
@@ -1705,7 +1714,7 @@ FocusScope {
1705 resizeArea: resizeArea
1714 resizeArea: resizeArea
1706 enabled: false
1715 enabled: false
1707 visible: enabled
1716 visible: enabled
1708− boundsItem: boundariesForWindowPlacement
1717+ boundsItem: root.availableDesktopArea
1709
1718
1710 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1719 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1711 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
1720 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
@@ -1826,7 +1835,8 @@ FocusScope {
1826 displacementX: appDelegate.clientAreaItem.x
1835 displacementX: appDelegate.clientAreaItem.x
1827 displacementY: appDelegate.clientAreaItem.y
1836 displacementY: appDelegate.clientAreaItem.y
1828
1837
1829− boundsItem: boundariesForWindowPlacement
1838+ boundsItem: root.availableDesktopArea
1839+ decorationHeight: priv.windowDecorationHeight
1830
1840
1831 z: childWindowRepeater.count - model.index
1841 z: childWindowRepeater.count - model.index
1832
1842
@@ -1847,7 +1857,7 @@ FocusScope {
1847 FakeMaximizeDelegate {
1857 FakeMaximizeDelegate {
1848 id: fakeRectangle
1858 id: fakeRectangle
1849 target: priv.focusedAppDelegate
1859 target: priv.focusedAppDelegate
1850− leftMargin: root.leftMargin
1860+ leftMargin: root.availableDesktopArea.x
1851 appContainerWidth: appContainer.width
1861 appContainerWidth: appContainer.width
1852 appContainerHeight: appContainer.height
1862 appContainerHeight: appContainer.height
1853 }
1863 }
tests/qmltests/Stage/tst_DesktopStage.qml+7
@@ -100,8 +100,15 @@ Item {
100 orientations: Orientations {}
100 orientations: Orientations {}
101 applicationManager: ApplicationManager
101 applicationManager: ApplicationManager
102 topLevelSurfaceList: topSurfaceList
102 topLevelSurfaceList: topSurfaceList
103+ availableDesktopArea: availableDesktopAreaItem
103 interactive: true
104 interactive: true
104 mode: "windowed"
105 mode: "windowed"
106+
107+ Item {
108+ id: availableDesktopAreaItem
109+ anchors.fill: parent
110+ anchors.topMargin: PanelState.panelHeight
111+ }
105 }
112 }
106 }
113 }
107 }
114 }
tests/qmltests/Stage/tst_PhoneStage.qml+5
@@ -52,6 +52,11 @@ Item {
52 applicationManager: ApplicationManager
52 applicationManager: ApplicationManager
53 surfaceManager: sMgr
53 surfaceManager: sMgr
54 }
54 }
55+ availableDesktopArea: availableDesktopAreaItem
56+ Item {
57+ id: availableDesktopAreaItem
58+ anchors.fill: parent
59+ }
55 Component.onCompleted: {
60 Component.onCompleted: {
56 ApplicationManager.startApplication("unity8-dash");
61 ApplicationManager.startApplication("unity8-dash");
57 }
62 }
tests/qmltests/Stage/tst_TabletStage.qml+5
@@ -61,6 +61,11 @@ Rectangle {
61 applicationManager: ApplicationManager
61 applicationManager: ApplicationManager
62 surfaceManager: sMgr
62 surfaceManager: sMgr
63 }
63 }
64+ availableDesktopArea: availableDesktopAreaItem
65+ Item {
66+ id: availableDesktopAreaItem
67+ anchors.fill: parent
68+ }
64 Component.onCompleted: {
69 Component.onCompleted: {
65 ApplicationManager.startApplication("unity8-dash");
70 ApplicationManager.startApplication("unity8-dash");
66 }
71 }