on xenial help sign in
Merge lp:~lukas-kde/unity8/newWindowDecosAndPanel
commit340b08cf16a63a196471e9a7e129574735874dff authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateTue 24 Nov 2015, 15:32 (11 years ago) parent5a5376ec45daa8
19 files changed+409−254
qml/Components/PanelState/PanelState.qml+3−2 qml/Components/WindowControlButtons.qml+73−28 qml/Components/graphics/window-close.svg+14 qml/Components/graphics/window-maximize.svg+12 qml/Components/graphics/window-minimize.svg+13 qml/Panel/Handle.qml+2−2 qml/Panel/Indicators/client/IndicatorsClient.qml+1−1 qml/Panel/IndicatorsMenu.qml+11−2 qml/Panel/MenuContent.qml+1−1 qml/Panel/Panel.qml+68−80 qml/Panel/PanelBackground.qml−21 qml/Stages/ApplicationWindow.qml+2−2 qml/Stages/DecoratedWindow.qml+18−15 qml/Stages/DesktopStage.qml+66−42 qml/Stages/WindowDecoration.qml+15−10 qml/Stages/WindowResizeArea.qml+1−1 tests/qmltests/Panel/tst_Panel.qml+44−10 tests/qmltests/Stages/tst_DesktopStage.qml+65−27 tests/qmltests/tst_Shell.qml−10
qml/Components/PanelState/PanelState.qml+3−2
@@ -22,10 +22,11 @@ QtObject {
2222
2323 property string title: ""
2424 property bool buttonsVisible: false
25−
26− property int panelHeight: 0
25+ property bool dropShadow: false
26+ property int panelHeight: units.gu(3)
2727
2828 signal close()
2929 signal minimize()
3030 signal maximize()
31+ signal focusMaximizedApp()
3132}
qml/Components/WindowControlButtons.qml+73−28
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2015 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
@@ -12,8 +12,6 @@
1212 *
1313 * You should have received a copy of the GNU General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Michael Zanetti <michael.zanetti@canonical.com>
1715 */
1816
1917import QtQuick 2.4
@@ -21,43 +19,90 @@ import Ubuntu.Components 1.3
2119
2220Row {
2321 id: root
24− spacing: units.gu(0.5)
22+ spacing: units.gu(1)
23+
24+ // to be set from outside
25+ property bool active: false
2526
2627 signal close()
2728 signal minimize()
2829 signal maximize()
2930
30− Rectangle {
31+ MouseArea {
32+ id: closeWindowButton
3133 objectName: "closeWindowButton"
32− height: parent.height; width: height; radius: height / 2
33− gradient: Gradient {
34− GradientStop { color: "#F49073"; position: 0 }
35− GradientStop { color: "#DF4F1C"; position: 1 }
34+ hoverEnabled: true
35+ height: parent.height
36+ width: height
37+ onClicked: root.close()
38+
39+ Rectangle {
40+ anchors.centerIn: parent
41+ width: units.gu(2)
42+ height: units.gu(2)
43+ radius: height / 2
44+ color: "#ed3146"
45+ visible: parent.containsMouse
46+ }
47+ Icon {
48+ width: height
49+ height: parent.height *.5
50+ anchors.centerIn: parent
51+ source: "graphics/window-close.svg"
52+ color: root.active ? "white" : "#5d5d5d"
53+ keyColor: "black"
3654 }
37− border.width: units.dp(.5)
38− border.color: "black"
39− MouseArea { anchors.fill: parent; onClicked: root.close() }
4055 }
41− Rectangle {
56+
57+ MouseArea {
58+ id: minimizeWindowButton
4259 objectName: "minimizeWindowButton"
43− height: parent.height; width: height; radius: height / 2
44− gradient: Gradient {
45− GradientStop { color: "#92918C"; position: 0 }
46− GradientStop { color: "#5E5D58"; position: 1 }
60+ hoverEnabled: true
61+ height: parent.height
62+ width: height
63+ onClicked: root.minimize()
64+
65+ Rectangle {
66+ anchors.centerIn: parent
67+ width: units.gu(2)
68+ height: units.gu(2)
69+ radius: height / 2
70+ color: "#888888"
71+ visible: parent.containsMouse
72+ }
73+ Icon {
74+ width: height
75+ height: parent.height *.5
76+ anchors.centerIn: parent
77+ source: "graphics/window-minimize.svg"
78+ color: root.active ? "white" : "#5d5d5d"
79+ keyColor: "black"
4780 }
48− border.width: units.dp(.5)
49− border.color: "black"
50− MouseArea { anchors.fill: parent; onClicked: root.minimize() }
5181 }
52− Rectangle {
82+
83+ MouseArea {
84+ id: maximizeWindowButton
5385 objectName: "maximizeWindowButton"
54− height: parent.height; width: height; radius: height / 2
55− gradient: Gradient {
56− GradientStop { color: "#92918C"; position: 0 }
57− GradientStop { color: "#5E5D58"; position: 1 }
86+ hoverEnabled: true
87+ height: parent.height
88+ width: height
89+ onClicked: root.maximize()
90+
91+ Rectangle {
92+ anchors.centerIn: parent
93+ width: units.gu(2)
94+ height: units.gu(2)
95+ radius: height / 2
96+ color: "#888888"
97+ visible: parent.containsMouse
98+ }
99+ Icon {
100+ width: height
101+ height: parent.height *.5
102+ anchors.centerIn: parent
103+ source: "graphics/window-maximize.svg"
104+ color: root.active ? "white" : "#5d5d5d"
105+ keyColor: "black"
58106 }
59− border.width: units.dp(.5)
60− border.color: "black"
61− MouseArea { anchors.fill: parent; onClicked: root.maximize() }
62107 }
63108}
qml/Components/graphics/window-close.svgnew file+14
@@ -0,0 +1,14 @@
1+<?xml version="1.0" encoding="iso-8859-1"?>
2+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5+ width="94.926px" height="94.926px" viewBox="0 0 94.926 94.926" style="enable-background:new 0 0 94.926 94.926;"
6+ xml:space="preserve">
7+<g>
8+ <path d="M55.931,47.463L94.306,9.09c0.826-0.827,0.826-2.167,0-2.994L88.833,0.62C88.436,0.224,87.896,0,87.335,0
9+ c-0.562,0-1.101,0.224-1.498,0.62L47.463,38.994L9.089,0.62c-0.795-0.795-2.202-0.794-2.995,0L0.622,6.096
10+ c-0.827,0.827-0.827,2.167,0,2.994l38.374,38.373L0.622,85.836c-0.827,0.827-0.827,2.167,0,2.994l5.473,5.476
11+ c0.397,0.396,0.936,0.62,1.498,0.62s1.1-0.224,1.497-0.62l38.374-38.374l38.374,38.374c0.397,0.396,0.937,0.62,1.498,0.62
12+ s1.101-0.224,1.498-0.62l5.473-5.476c0.826-0.827,0.826-2.167,0-2.994L55.931,47.463z"/>
13+</g>
14+</svg>
qml/Components/graphics/window-maximize.svgnew file+12
@@ -0,0 +1,12 @@
1+<?xml version="1.0" encoding="iso-8859-1"?>
2+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5+ width="459px" height="459px" viewBox="0 0 459 459" style="enable-background:new 0 0 459 459;" xml:space="preserve">
6+<g>
7+ <g id="check-box-outline-blank">
8+ <path d="M408,51v357H51V51H408 M408,0H51C22.95,0,0,22.95,0,51v357c0,28.05,22.95,51,51,51h357c28.05,0,51-22.95,51-51V51
9+ C459,22.95,436.05,0,408,0L408,0z"/>
10+ </g>
11+</g>
12+</svg>
qml/Components/graphics/window-minimize.svgnew file+13
@@ -0,0 +1,13 @@
1+<?xml version="1.0" encoding="iso-8859-1"?>
2+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5+ width="121.805px" height="121.804px" viewBox="0 0 121.805 121.804" style="enable-background:new 0 0 121.805 121.804;"
6+ xml:space="preserve">
7+<g>
8+ <g>
9+ <path d="M7.308,68.211h107.188c4.037,0,7.309-3.272,7.309-7.31c0-4.037-3.271-7.309-7.309-7.309H7.308
10+ C3.272,53.593,0,56.865,0,60.902C0,64.939,3.272,68.211,7.308,68.211z"/>
11+ </g>
12+</g>
13+</svg>
qml/Panel/Handle.qml+2−2
@@ -19,7 +19,7 @@ import Ubuntu.Components 1.3
1919
2020Rectangle {
2121 id: handle
22− color: "#333333"
22+ color: "#5d5d5d"
2323 height: units.gu(2)
2424 property bool active: false
2525
@@ -35,7 +35,7 @@ Rectangle {
3535 id: dot
3636 width: units.dp(3)
3737 height: width
38− color: handle.active ? "#de4814" : "#717171"
38+ color: handle.active ? UbuntuColors.orange : "#717171"
3939 radius: units.dp(1)
4040 }
4141 }
qml/Panel/Indicators/client/IndicatorsClient.qml+1−1
@@ -22,7 +22,7 @@ import Ubuntu.Components 1.3
2222import Ubuntu.Components.ListItems 1.3 as ListItem
2323
2424Rectangle {
25− color: "black"
25+ color: "#333333"
2626 id: root
2727
2828 Component.onCompleted: {
qml/Panel/IndicatorsMenu.qml+11−2
@@ -38,7 +38,7 @@ Showable {
3838 property bool enableHint: true
3939 property bool contentEnabled: true
4040 property bool showOnClick: true
41− property color panelColor: "black"
41+ property color panelColor: "#333333"
4242
4343 signal showTapped(point position)
4444
@@ -110,12 +110,21 @@ Showable {
110110 height: units.gu(0.5)
111111 gradient: Gradient {
112112 GradientStop { position: 0.0; color: "transparent" }
113− GradientStop { position: 1.0; color: "black" }
113+ GradientStop { position: 1.0; color: "#333333" }
114114 }
115115 opacity: 0.3
116116 }
117117 }
118118
119+ PanelSeparatorLine {
120+ id: indicatorOrangeLine
121+ anchors {
122+ bottom: handle.top
123+ left: handle.left
124+ right: handle.right
125+ }
126+ }
127+
119128 Rectangle {
120129 anchors.fill: bar
121130 color: panelColor
qml/Panel/MenuContent.qml+1−1
@@ -27,7 +27,7 @@ Rectangle {
2727
2828 property QtObject indicatorsModel: null
2929 property int currentMenuIndex: -1
30− color: "#221e1c" // FIXME not in palette yet
30+ color: "#333333" // FIXME not in palette yet
3131
3232 width: units.gu(40)
3333 height: units.gu(42)
qml/Panel/Panel.qml+68−80
@@ -30,23 +30,12 @@ Item {
3030 property real indicatorAreaShowProgress: 1.0
3131 property bool locked: false
3232
33− opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
34−
35− Binding {
36− target: PanelState
37− property: "panelHeight"
38− value: root.panelHeight
39− }
40−
4133 Rectangle {
4234 id: darkenedArea
4335 property real darkenedOpacity: 0.6
4436 anchors {
45− top: parent.top
37+ fill: parent
4638 topMargin: panelHeight
47− left: parent.left
48− right: parent.right
49− bottom: parent.bottom
5039 }
5140 color: "black"
5241 opacity: indicators.unitProgress * darkenedOpacity
@@ -59,16 +48,18 @@ Item {
5948 }
6049 }
6150
51+ Binding {
52+ target: PanelState
53+ property: "panelHeight"
54+ value: indicators.minimizedPanelHeight
55+ }
56+
6257 Item {
6358 id: indicatorArea
6459 objectName: "indicatorArea"
6560
6661 anchors.fill: parent
6762
68− Behavior on anchors.topMargin {
69− NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
70− }
71−
7263 transform: Translate {
7364 y: indicators.state === "initial"
7465 ? (1.0 - indicatorAreaShowProgress) * -d.indicatorHeight
@@ -76,7 +67,7 @@ Item {
7667 }
7768
7869 BorderImage {
79− id: dropShadow
70+ id: indicatorsDropShadow
8071 anchors {
8172 fill: indicators
8273 leftMargin: -units.gu(1)
@@ -86,9 +77,19 @@ Item {
8677 source: "graphics/rectangular_dropshadow.sci"
8778 }
8879
80+ BorderImage {
81+ id: panelDropShadow
82+ anchors {
83+ fill: indicatorAreaBackground
84+ bottomMargin: -units.gu(1)
85+ }
86+ visible: PanelState.dropShadow && !callHint.visible
87+ source: "graphics/rectangular_dropshadow.sci"
88+ }
89+
8990 Rectangle {
9091 id: indicatorAreaBackground
91− color: callHint.visible ? "green" : "black"
92+ color: callHint.visible ? "green" : "#333333"
9293 anchors {
9394 top: parent.top
9495 left: parent.left
@@ -99,30 +100,6 @@ Item {
99100 Behavior on color { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
100101 }
101102
102− PanelSeparatorLine {
103− id: orangeLine
104− anchors {
105− top: indicatorAreaBackground.bottom
106− left: parent.left
107− right: indicators.left
108− }
109− saturation: 1 - indicators.unitProgress
110−
111− // Don't let input event pass trough
112− MouseArea { anchors.fill: parent }
113− }
114−
115− Image {
116− anchors {
117− top: indicators.top
118− bottom: indicators.bottom
119− right: indicators.left
120− topMargin: indicatorArea.anchors.topMargin + indicators.minimizedPanelHeight
121− }
122− width: units.dp(2)
123− source: "graphics/VerticalDivider.png"
124− }
125−
126103 MouseArea {
127104 anchors {
128105 top: parent.top
@@ -130,7 +107,29 @@ Item {
130107 right: indicators.left
131108 }
132109 height: indicators.minimizedPanelHeight
133− onClicked: { if (callHint.visible) { callHint.showLiveCall(); } }
110+ hoverEnabled: true
111+ onClicked: callHint.visible ? callHint.showLiveCall() : PanelState.focusMaximizedApp()
112+ onDoubleClicked: PanelState.maximize()
113+
114+ // WindowControlButtons inside the mouse area, otherwise QML doesn't grok nested hover events :/
115+ // cf. https://bugreports.qt.io/browse/QTBUG-32909
116+ WindowControlButtons {
117+ id: windowControlButtons
118+ objectName: "panelWindowControlButtons"
119+ anchors {
120+ left: parent.left
121+ top: parent.top
122+ leftMargin: units.gu(1)
123+ topMargin: units.gu(0.5)
124+ bottomMargin: units.gu(0.5)
125+ }
126+ height: indicators.minimizedPanelHeight - anchors.topMargin - anchors.bottomMargin
127+ visible: PanelState.buttonsVisible && parent.containsMouse && !root.locked && !callHint.visible
128+ active: PanelState.buttonsVisible
129+ onClose: PanelState.close()
130+ onMinimize: PanelState.minimize()
131+ onMaximize: PanelState.maximize()
132+ }
134133 }
135134
136135 IndicatorsMenu {
@@ -146,7 +145,7 @@ Item {
146145 width: root.width - (windowControlButtons.visible ? windowControlButtons.width + titleLabel.width : 0)
147146 minimizedPanelHeight: units.gu(3)
148147 expandedPanelHeight: units.gu(7)
149− openedHeight: root.height - indicatorOrangeLine.height
148+ openedHeight: root.height
150149
151150 overFlowWidth: {
152151 if (callHint.visible) {
@@ -163,58 +162,34 @@ Item {
163162 callHint.showLiveCall();
164163 }
165164 }
166−
167− hideDragHandle {
168− anchors.bottomMargin: -indicatorOrangeLine.height
169− }
170− }
171−
172− WindowControlButtons {
173− id: windowControlButtons
174− objectName: "panelWindowControlButtons"
175− anchors {
176− left: parent.left
177− top: parent.top
178− margins: units.gu(0.7)
179− }
180− height: indicators.minimizedPanelHeight - anchors.margins * 2
181− visible: PanelState.buttonsVisible && !root.locked
182− onClose: PanelState.close()
183− onMinimize: PanelState.minimize()
184− onMaximize: PanelState.maximize()
185165 }
186166
187167 Label {
188168 id: titleLabel
189169 objectName: "windowDecorationTitle"
190170 anchors {
191− left: windowControlButtons.right
171+ left: parent.left
192172 top: parent.top
193− margins: units.gu(0.7)
173+ leftMargin: units.gu(1)
174+ topMargin: units.gu(0.5)
175+ bottomMargin: units.gu(0.5)
194176 }
195− color: "#DFDBD2"
196− height: windowControlButtons.height
197− visible: windowControlButtons.visible
177+ color: PanelState.buttonsVisible ? "#ffffff" : "#5d5d5d"
178+ height: indicators.minimizedPanelHeight - anchors.topMargin - anchors.bottomMargin
179+ visible: !windowControlButtons.visible && !root.locked && !callHint.visible
198180 verticalAlignment: Text.AlignVCenter
199− fontSize: "small"
200− font.bold: true
181+ fontSize: "medium"
182+ font.weight: Font.Normal
201183 text: PanelState.title
202184 }
203185
204− PanelSeparatorLine {
205− id: indicatorOrangeLine
206− anchors {
207− top: indicators.bottom
208− left: indicators.left
209− right: indicators.right
210− }
211− }
186+ // TODO here would the Locally integrated menus come
212187
213188 ActiveCallHint {
214189 id: __callHint
215190 anchors {
216191 top: parent.top
217− left: windowControlButtons.visible ? windowControlButtons.right : parent.left
192+ left: parent.left
218193 }
219194 height: indicators.minimizedPanelHeight
220195 visible: active && indicators.state == "initial"
@@ -224,7 +199,7 @@ Item {
224199 QtObject {
225200 id: d
226201 objectName: "panelPriv"
227− readonly property real indicatorHeight: indicators.minimizedPanelHeight + indicatorOrangeLine.height
202+ readonly property real indicatorHeight: indicators.minimizedPanelHeight
228203 }
229204
230205 states: [
@@ -234,6 +209,7 @@ Item {
234209 PropertyChanges {
235210 target: indicatorArea;
236211 anchors.topMargin: 0
212+ opacity: 1;
237213 }
238214 },
239215 State {
@@ -242,6 +218,7 @@ Item {
242218 PropertyChanges {
243219 target: indicatorArea;
244220 anchors.topMargin: indicators.state === "initial" ? -d.indicatorHeight : 0
221+ opacity: indicators.fullyClosed ? 0.0 : 1.0
245222 }
246223 PropertyChanges {
247224 target: indicators.showDragHandle;
@@ -249,4 +226,15 @@ Item {
249226 }
250227 }
251228 ]
229+
230+ transitions: [
231+ Transition {
232+ to: "onscreen"
233+ UbuntuNumberAnimation { target: indicatorArea; properties: "anchors.topMargin,opacity" }
234+ },
235+ Transition {
236+ to: "offscreen"
237+ UbuntuNumberAnimation { target: indicatorArea; properties: "anchors.topMargin,opacity" }
238+ }
239+ ]
252240}
qml/Panel/PanelBackground.qmldeleted−21
@@ -1,21 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
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
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−
19−Rectangle {
20− color: "black"
21−}
qml/Stages/ApplicationWindow.qml+2−2
@@ -56,7 +56,7 @@ FocusScope {
5656 // Whether the Application had a surface before but lost it.
5757 property bool hadSurface: sessionContainer.surfaceContainer.hadSurface
5858
59− property bool needToTakeScreenshot:
59+ readonly property bool needToTakeScreenshot:
6060 ((sessionContainer.surface && d.surfaceInitialized) || d.hadSurface)
6161 && screenshotImage.status === Image.Null
6262 && d.applicationState === ApplicationInfoInterface.Stopped
@@ -71,7 +71,7 @@ FocusScope {
7171 // Remove this when possible
7272 property bool surfaceInitialized: false
7373
74− property bool supportsSurfaceResize:
74+ readonly property bool supportsSurfaceResize:
7575 application &&
7676 ((application.supportedOrientations & Qt.PortraitOrientation)
7777 || (application.supportedOrientations & Qt.InvertedPortraitOrientation))
qml/Stages/DecoratedWindow.qml+18−15
@@ -24,14 +24,15 @@ FocusScope {
2424 id: root
2525
2626 width: applicationWindow.width
27− height: (root.decorationShown ? decoration.height : 0) + applicationWindow.height
27+ height: (decorationShown ? decoration.height : 0) + applicationWindow.height
2828
2929 property alias window: applicationWindow
3030 property alias application: applicationWindow.application
3131 property alias active: decoration.active
3232 property alias title: decoration.title
33+ property alias fullscreen: applicationWindow.fullscreen
3334
34− property bool decorationShown: true
35+ readonly property bool decorationShown: !fullscreen
3536 property bool highlightShown: false
3637 property real shadowOpacity: 1
3738
@@ -43,15 +44,6 @@ FocusScope {
4344 signal minimize()
4445 signal decorationPressed()
4546
46− BorderImage {
47− anchors {
48− fill: root
49− margins: -units.gu(2)
50− }
51− source: "graphics/dropshadow2gu.sci"
52− opacity: root.shadowOpacity * .3
53− }
54−
5547 Rectangle {
5648 id: selectionHighlight
5749 anchors.fill: parent
@@ -64,7 +56,17 @@ FocusScope {
6456 anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
6557 height: units.dp(2)
6658 color: UbuntuColors.orange
67− visible: root.highlightShown
59+ visible: highlightShown
60+ }
61+
62+ BorderImage {
63+ anchors {
64+ fill: root
65+ margins: active ? -units.gu(2) : -units.gu(1.5)
66+ }
67+ source: "graphics/dropshadow2gu.sci"
68+ opacity: root.shadowOpacity * .3
69+ enabled: !fullscreen
6870 }
6971
7072 WindowDecoration {
@@ -74,12 +76,13 @@ FocusScope {
7476 anchors { left: parent.left; top: parent.top; right: parent.right }
7577 height: units.gu(3)
7678 width: root.width
77− title: window.title !== "" ? window.title : ""
79+ title: window.title
80+ visible: root.decorationShown
81+
7882 onClose: root.close();
79− onMaximize: root.maximize();
83+ onMaximize: { root.decorationPressed(); root.maximize(); }
8084 onMinimize: root.minimize();
8185 onPressed: root.decorationPressed();
82− visible: decorationShown
8386 }
8487
8588 ApplicationWindow {
qml/Stages/DesktopStage.qml+66−42
@@ -12,12 +12,9 @@
1212 *
1313 * You should have received a copy of the GNU General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Michael Zanetti <michael.zanetti@canonical.com>
1715 */
1816
1917import QtQuick 2.4
20−import QtQuick.Layouts 1.1
2118import Ubuntu.Components 1.3
2219import Unity.Application 0.1
2320import "../Components/PanelState"
@@ -55,7 +52,7 @@ AbstractStage {
5552 onFocusRequested: {
5653 var appIndex = priv.indexOf(appId);
5754 var appDelegate = appRepeater.itemAt(appIndex);
58− appDelegate.restoreFromMinimized();
55+ appDelegate.restore();
5956
6057 if (spread.state == "altTab") {
6158 spread.cancel();
@@ -107,7 +104,7 @@ AbstractStage {
107104 id: minimizeRestoreShortcut
108105 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
109106 onTriggered: priv.focusedAppDelegate.maximized || priv.focusedAppDelegate.maximizedLeft || priv.focusedAppDelegate.maximizedRight
110− ? priv.focusedAppDelegate.restore() : priv.focusedAppDelegate.minimize(true)
107+ ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
111108 active: priv.focusedAppDelegate !== null
112109 }
113110
@@ -119,18 +116,16 @@ AbstractStage {
119116 var index = indexOf(focusedAppId);
120117 return index >= 0 && index < appRepeater.count ? appRepeater.itemAt(index) : null
121118 }
119+ onFocusedAppDelegateChanged: updateForegroundMaximizedApp();
120+
122121 property int foregroundMaximizedAppIdIndex: -1
123122
124123 function updateForegroundMaximizedApp() {
125124 for (var i = 0; i < appRepeater.count; i++) {
126125 var item = appRepeater.itemAt(i);
127−
128126 if (item && item.visuallyMaximized) {
129− var app = ApplicationManager.get(i);
130− if (app) {
131− foregroundMaximizedAppIdIndex = i;
132− return;
133− }
127+ foregroundMaximizedAppIdIndex = i;
128+ return;
134129 }
135130 }
136131 foregroundMaximizedAppIdIndex = -1;
@@ -149,7 +144,7 @@ AbstractStage {
149144 for (var i = 0; i < appRepeater.count; i++) {
150145 var appDelegate = appRepeater.itemAt(i);
151146 if (appDelegate && !appDelegate.minimized) {
152− appDelegate.minimize(false); // minimize but don't switch focus
147+ appDelegate.minimize();
153148 }
154149 }
155150
@@ -173,24 +168,47 @@ AbstractStage {
173168 onClose: {
174169 ApplicationManager.stopApplication(ApplicationManager.focusedApplicationId)
175170 }
176− onMinimize: appRepeater.itemAt(0).minimize(true);
177− onMaximize: appRepeater.itemAt(0).restore();
171+ onMinimize: priv.focusedAppDelegate && priv.focusedAppDelegate.minimize();
172+ onMaximize: priv.focusedAppDelegate // don't restore minimized apps when double clicking the panel
173+ && priv.focusedAppDelegate.restoreFromMaximized();
174+ onFocusMaximizedApp: if (priv.foregroundMaximizedAppIdIndex != -1) {
175+ ApplicationManager.focusApplication(appRepeater.itemAt(priv.foregroundMaximizedAppIdIndex).appId);
176+ }
178177 }
179178
180179 Binding {
181180 target: PanelState
182181 property: "buttonsVisible"
183− value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized
182+ value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized // FIXME for Locally integrated menus
183+ && spread.state == ""
184184 }
185185
186186 Binding {
187187 target: PanelState
188188 property: "title"
189− value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.title
190− when: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized
189+ value: {
190+ if (priv.focusedAppDelegate !== null && spread.state == "") {
191+ if (priv.focusedAppDelegate.maximized)
192+ return priv.focusedAppDelegate.title
193+ else
194+ return priv.focusedAppDelegate.appName
195+ }
196+ return ""
197+ }
198+ when: priv.focusedAppDelegate
191199 }
192200
193− Component.onDestruction: PanelState.buttonsVisible = false;
201+ Binding {
202+ target: PanelState
203+ property: "dropShadow"
204+ value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppIdIndex !== -1
205+ }
206+
207+ Component.onDestruction: {
208+ PanelState.title = "";
209+ PanelState.buttonsVisible = false;
210+ PanelState.dropShadow = false;
211+ }
194212
195213 FocusScope {
196214 id: appContainer
@@ -211,19 +229,16 @@ AbstractStage {
211229 model: ApplicationManager
212230 objectName: "appRepeater"
213231
214− onItemAdded: priv.updateForegroundMaximizedApp()
215− onItemRemoved: priv.updateForegroundMaximizedApp()
216−
217232 delegate: FocusScope {
218233 id: appDelegate
219234 objectName: "appDelegate_" + appId
220235 z: ApplicationManager.count - index
221− y: units.gu(3)
236+ y: PanelState.panelHeight
237+ focus: appId === priv.focusedAppId
222238 width: decoratedWindow.width
223239 height: decoratedWindow.height
224240 property alias requestedWidth: decoratedWindow.requestedWidth
225241 property alias requestedHeight: decoratedWindow.requestedHeight
226− focus: model.appId === priv.focusedAppId
227242
228243 QtObject {
229244 id: appDelegatePrivate
@@ -240,6 +255,7 @@ AbstractStage {
240255 readonly property string appId: model.appId
241256 property bool animationsEnabled: true
242257 property alias title: decoratedWindow.title
258+ readonly property string appName: model.name
243259 property bool visuallyMaximized: false
244260 property bool visuallyMinimized: false
245261
@@ -249,7 +265,6 @@ AbstractStage {
249265 }
250266 }
251267
252− onZChanged: priv.updateForegroundMaximizedApp()
253268 onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
254269
255270 visible: !visuallyMinimized &&
@@ -289,17 +304,16 @@ AbstractStage {
289304 }
290305 function minimize(animated) {
291306 animationsEnabled = (animated === undefined) || animated;
292− appDelegatePrivate.maximized = false;
293307 appDelegatePrivate.minimized = true;
294308 }
295− function restore(animated) {
309+ function restoreFromMaximized(animated) {
296310 animationsEnabled = (animated === undefined) || animated;
297311 appDelegatePrivate.minimized = false;
298312 appDelegatePrivate.maximized = false;
299313 appDelegatePrivate.maximizedLeft = false;
300314 appDelegatePrivate.maximizedRight = false;
301315 }
302− function restoreFromMinimized(animated) {
316+ function restore(animated) {
303317 animationsEnabled = (animated === undefined) || animated;
304318 appDelegatePrivate.minimized = false;
305319 if (maximized)
@@ -312,6 +326,14 @@ AbstractStage {
312326 }
313327
314328 states: [
329+ State {
330+ name: "fullscreen"; when: decoratedWindow.fullscreen
331+ extend: "maximized"
332+ PropertyChanges {
333+ target: appDelegate;
334+ y: -PanelState.panelHeight
335+ }
336+ },
315337 State {
316338 name: "normal";
317339 when: !appDelegate.maximized && !appDelegate.minimized
@@ -323,7 +345,7 @@ AbstractStage {
323345 }
324346 },
325347 State {
326− name: "maximized"; when: appDelegate.maximized
348+ name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
327349 PropertyChanges {
328350 target: appDelegate;
329351 x: 0; y: 0;
@@ -334,11 +356,13 @@ AbstractStage {
334356 },
335357 State {
336358 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
337− PropertyChanges { target: appDelegate; x: 0; y: units.gu(3); width: root.width/2; height: root.height - units.gu(3) }
359+ PropertyChanges { target: appDelegate; x: 0; y: PanelState.panelHeight;
360+ requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
338361 },
339362 State {
340363 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
341− PropertyChanges { target: appDelegate; x: root.width/2; y: units.gu(3); width: root.width/2; height: root.height - units.gu(3) }
364+ PropertyChanges { target: appDelegate; x: root.width/2; y: PanelState.panelHeight;
365+ requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
342366 },
343367 State {
344368 name: "minimized"; when: appDelegate.minimized
@@ -359,15 +383,6 @@ AbstractStage {
359383 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
360384 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
361385 },
362− Transition {
363− to: "maximized"
364− enabled: appDelegate.animationsEnabled
365− PropertyAction { target: appDelegate; property: "visuallyMinimized" }
366− SequentialAnimation {
367− UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
368− PropertyAction { target: appDelegate; property: "visuallyMaximized" }
369− }
370− },
371386 Transition {
372387 to: "minimized"
373388 enabled: appDelegate.animationsEnabled
@@ -377,12 +392,21 @@ AbstractStage {
377392 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
378393 ScriptAction {
379394 script: {
380− if (appDelegate.animationsEnabled && state === "minimized" ) {
395+ if (appDelegate.minimized) {
381396 priv.focusNext();
382397 }
383398 }
384399 }
385400 }
401+ },
402+ Transition {
403+ to: "*" //maximized and fullscreen
404+ enabled: appDelegate.animationsEnabled
405+ PropertyAction { target: appDelegate; property: "visuallyMinimized" }
406+ SequentialAnimation {
407+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
408+ PropertyAction { target: appDelegate; property: "visuallyMaximized" }
409+ }
386410 }
387411 ]
388412
@@ -418,8 +442,8 @@ AbstractStage {
418442
419443 onClose: ApplicationManager.stopApplication(model.appId)
420444 onMaximize: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
421− ? appDelegate.restore() : appDelegate.maximize()
422− onMinimize: appDelegate.minimize(true)
445+ ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
446+ onMinimize: appDelegate.minimize()
423447 onDecorationPressed: { ApplicationManager.focusApplication(model.appId) }
424448 }
425449 }
qml/Stages/WindowDecoration.qml+15−10
@@ -33,6 +33,8 @@ MouseArea {
3333 signal minimize()
3434 signal maximize()
3535
36+ onDoubleClicked: root.maximize()
37+
3638 QtObject {
3739 id: priv
3840 property real distanceX
@@ -65,20 +67,23 @@ MouseArea {
6567 anchors.fill: parent
6668 anchors.bottomMargin: -radius
6769 radius: units.gu(.5)
68− gradient: Gradient {
69− GradientStop { color: "#626055"; position: 0 }
70− GradientStop { color: "#3C3B37"; position: 1 }
71− }
70+ color: "#333333"
7271 }
7372
7473 Row {
75− anchors { fill: parent; margins: units.gu(0.7) }
76− spacing: units.gu(1)
77− opacity: root.active ? 1 : 0.5
74+ anchors {
75+ fill: parent
76+ leftMargin: units.gu(1)
77+ rightMargin: units.gu(1)
78+ topMargin: units.gu(0.5)
79+ bottomMargin: units.gu(0.5)
80+ }
81+ spacing: units.gu(3)
7882
7983 WindowControlButtons {
8084 id: buttons
8185 height: parent.height
86+ active: root.active
8287 onClose: root.close();
8388 onMinimize: root.minimize();
8489 onMaximize: root.maximize();
@@ -87,12 +92,12 @@ MouseArea {
8792 Label {
8893 id: titleLabel
8994 objectName: "windowDecorationTitle"
90− color: "#DFDBD2"
95+ color: root.active ? "white" : "#5d5d5d"
9196 height: parent.height
9297 width: parent.width - buttons.width - parent.anchors.rightMargin - parent.anchors.leftMargin
9398 verticalAlignment: Text.AlignVCenter
94− fontSize: "small"
95− font.bold: true
99+ fontSize: "medium"
100+ font.weight: root.active ? Font.Light : Font.Normal
96101 elide: Text.ElideRight
97102 }
98103 }
qml/Stages/WindowResizeArea.qml+1−1
@@ -25,7 +25,7 @@ MouseArea {
2525 anchors.fill: target
2626 anchors.margins: -borderThickness
2727
28− hoverEnabled: true
28+ hoverEnabled: target && !target.maximized // don't grab the resize under the panel
2929
3030 property var windowStateStorage: WindowStateStorage
3131
tests/qmltests/Panel/tst_Panel.qml+44−10
@@ -23,6 +23,7 @@ import Unity.Application 0.1
2323import Unity.Indicators 0.1 as Indicators
2424import Ubuntu.Telephony 0.1 as Telephony
2525import "../../../qml/Panel"
26+import "../../../qml/Components/PanelState"
2627
2728IndicatorTest {
2829 id: root
@@ -30,6 +31,12 @@ IndicatorTest {
3031 height: units.gu(71)
3132 color: "white"
3233
34+ Binding {
35+ target: mouseEmulation
36+ property: "checked"
37+ value: !windowControlsCB.checked
38+ }
39+
3340 RowLayout {
3441 anchors.fill: parent
3542 anchors.margins: units.gu(1)
@@ -45,17 +52,18 @@ IndicatorTest {
4552 MouseArea {
4653 id: backgroundMouseArea
4754 anchors.fill: parent
48− }
55+ hoverEnabled: true
56+
57+ Panel {
58+ id: panel
59+ anchors.fill: parent
60+ indicators {
61+ width: parent.width > units.gu(60) ? units.gu(40) : parent.width
62+ indicatorsModel: root.indicatorsModel
63+ }
4964
50− Panel {
51− id: panel
52− anchors.fill: parent
53− indicators {
54− width: parent.width > units.gu(60) ? units.gu(40) : parent.width
55− indicatorsModel: root.indicatorsModel
65+ property real panelAndSeparatorHeight: panel.indicators.minimizedPanelHeight
5666 }
57−
58− property real panelAndSeparatorHeight: panel.indicators.minimizedPanelHeight + units.dp(2)
5967 }
6068 }
6169
@@ -93,6 +101,32 @@ IndicatorTest {
93101 }
94102 }
95103
104+ RowLayout {
105+ Layout.fillWidth: true
106+ CheckBox {
107+ id: windowControlsCB
108+ onClicked: PanelState.buttonsVisible = checked
109+ }
110+ Label {
111+ text: "Show window controls"
112+ }
113+ }
114+
115+ RowLayout {
116+ Layout.fillWidth: true
117+ CheckBox {
118+ onClicked: {
119+ if (checked)
120+ PanelState.title = "Fake window title"
121+ else
122+ PanelState.title = ""
123+ }
124+ }
125+ Label {
126+ text: "Show fake window title"
127+ }
128+ }
129+
96130 Rectangle {
97131 Layout.preferredHeight: units.dp(1);
98132 Layout.fillWidth: true;
@@ -127,7 +161,7 @@ IndicatorTest {
127161 color: "black"
128162 }
129163
130− MouseTouchEmulationCheckbox {}
164+ MouseTouchEmulationCheckbox { id: mouseEmulation }
131165 }
132166 }
133167
tests/qmltests/Stages/tst_DesktopStage.qml+65−27
@@ -46,8 +46,8 @@ Item {
4646 WindowStateStorage.geometry = {
4747 'unity8-dash': Qt.rect(0, units.gu(3), units.gu(50), units.gu(40)),
4848 'dialer-app': Qt.rect(units.gu(51), units.gu(3), units.gu(50), units.gu(40)),
49− 'camera-app': Qt.rect(0, units.gu(44), units.gu(50), units.gu(40)),
50− 'gallery-app': Qt.rect(units.gu(51), units.gu(44), units.gu(50), units.gu(40))
49+ 'gmail-webapp': Qt.rect(0, units.gu(44), units.gu(50), units.gu(40)),
50+ 'twitter-webapp': Qt.rect(units.gu(51), units.gu(44), units.gu(50), units.gu(40))
5151 }
5252 }
5353
@@ -60,10 +60,14 @@ Item {
6060
6161 focus: true
6262
63+ property bool itemDestroyed: false
6364 sourceComponent: Component {
6465 DesktopStage {
6566 color: "darkblue"
6667 anchors.fill: parent
68+ Component.onDestruction: {
69+ desktopStageLoader.itemDestroyed = true;
70+ }
6771 orientations: Orientations {}
6872 }
6973 }
@@ -114,10 +118,16 @@ Item {
114118 property Item desktopStage: desktopStageLoader.status === Loader.Ready ? desktopStageLoader.item : null
115119
116120 function cleanup() {
121+ desktopStageLoader.itemDestroyed = false;
117122 desktopStageLoader.active = false;
118123
119124 tryCompare(desktopStageLoader, "status", Loader.Null);
120125 tryCompare(desktopStageLoader, "item", null);
126+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
127+ // actually took place. Likely because Loader waits until the next event loop
128+ // iteration to do its work. So to ensure the reload, we will wait until the
129+ // Shell instance gets destroyed.
130+ tryCompare(desktopStageLoader, "itemDestroyed", true);
121131
122132 killAllRunningApps();
123133
@@ -171,8 +181,8 @@ Item {
171181
172182 function test_tappingOnWindowChangesFocusedApp_data() {
173183 return [
174− {tag: "dash to dialer", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 0, focusTo: 1 },
175− {tag: "dialer to dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 1, focusTo: 0 },
184+ {tag: "dash to dialer", apps: [ "unity8-dash", "dialer-app", "gmail-webapp"], focusfrom: 0, focusTo: 1 },
185+ {tag: "dialer to dash", apps: [ "unity8-dash", "dialer-app", "gmail-webapp"], focusfrom: 1, focusTo: 0 }
176186 ]
177187 }
178188
@@ -218,8 +228,8 @@ Item {
218228
219229 function test_tappingOnDecorationFocusesApplication_data() {
220230 return [
221− {tag: "dash to dialer", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 0, focusTo: 1 },
222− {tag: "dialer to dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 1, focusTo: 0 },
231+ {tag: "dash to dialer", apps: [ "unity8-dash", "dialer-app", "gmail-webapp"], focusfrom: 0, focusTo: 1 },
232+ {tag: "dialer to dash", apps: [ "unity8-dash", "dialer-app", "gmail-webapp"], focusfrom: 1, focusTo: 0 }
223233 ]
224234 }
225235
@@ -229,12 +239,16 @@ Item {
229239 var fromAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusfrom]);
230240 verify(fromAppDecoration);
231241 tap(fromAppDecoration);
232− tryCompare(ApplicationManager.findApplication(data.apps[data.focusfrom]).session.surface, "activeFocus", true);
242+ var fromApp = ApplicationManager.findApplication(data.apps[data.focusfrom]);
243+ verify(fromApp);
244+ tryCompare(fromApp.session.surface, "activeFocus", true);
233245
234246 var toAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusTo]);
235247 verify(toAppDecoration);
236248 tap(toAppDecoration);
237− tryCompare(ApplicationManager.findApplication(data.apps[data.focusTo]).session.surface, "activeFocus", true);
249+ var toApp = ApplicationManager.findApplication(data.apps[data.focusTo]);
250+ verify(toApp);
251+ tryCompare(toApp.session.surface, "activeFocus", true);
238252 }
239253
240254 function test_clickingOnDecorationFocusesApplication_data() {
@@ -354,26 +368,26 @@ Item {
354368 function test_maximizeApplicationHidesSurfacesBehindIt() {
355369 var dashApp = startApplication("unity8-dash");
356370 var dialerApp = startApplication("dialer-app");
357− var cameraApp = startApplication("camera-app");
371+ var gmailApp = startApplication("gmail-webapp");
358372
359373 var dashDelegate = findChild(desktopStage, "appDelegate_unity8-dash");
360374 verify(dashDelegate);
361375 var dialerDelegate = findChild(desktopStage, "appDelegate_dialer-app");
362376 verify(dialerDelegate);
363− var cameraDelegate = findChild(desktopStage, "appDelegate_camera-app");
364− verify(cameraDelegate);
377+ var gmailDelegate = findChild(desktopStage, "appDelegate_gmail-webapp");
378+ verify(gmailDelegate);
365379
366380 // maximize
367− findChild(dialerDelegate, "decoratedWindow").maximize();
381+ dialerDelegate.maximize();
368382 tryCompare(dialerDelegate, "visuallyMaximized", true);
369383
370384 tryCompare(dashApp.session.surface, "visible", false);
371− compare(cameraApp.session.surface.visible, true);
385+ compare(gmailApp.session.surface.visible, true);
372386
373387 // restore
374− findChild(dialerDelegate, "decoratedWindow").maximize();
388+ dialerDelegate.restoreFromMaximized();
375389 compare(dashApp.session.surface.visible, true);
376− compare(cameraApp.session.surface.visible, true);
390+ compare(gmailApp.session.surface.visible, true);
377391 }
378392
379393 function test_applicationsBecomeVisibleWhenOccludingAppRemoved() {
@@ -385,28 +399,52 @@ Item {
385399 var dialerDelegate = findChild(desktopStage, "appDelegate_dialer-app");
386400 verify(dialerDelegate);
387401
388− var cameraApp = startApplication("camera-app");
389− var cameraDelegate = findChild(desktopStage, "appDelegate_camera-app");
390− verify(cameraDelegate);
391− findChild(dialerDelegate, "decoratedWindow").maximize();
402+ var dialerMaximizeButton = findChild(dialerDelegate, "maximizeWindowButton");
403+ verify(dialerMaximizeButton);
404+ mouseClick(dialerMaximizeButton);
405+
406+ var mapApp = startApplication("map");
407+ var mapDelegate = findChild(desktopStage, "appDelegate_map");
408+ verify(mapDelegate);
392409
393− var galleryApp = startApplication("gallery-app");
394− var galleryDelegate = findChild(desktopStage, "appDelegate_gallery-app");
395− verify(galleryDelegate);
396− findChild(galleryDelegate, "decoratedWindow").maximize();
410+ var gmailApp = startApplication("gmail-webapp");
411+ var gmailDelegate = findChild(desktopStage, "appDelegate_gmail-webapp");
412+ verify(gmailDelegate);
413+
414+ var gmailMaximizeButton = findChild(gmailDelegate, "maximizeWindowButton");
415+ verify(gmailMaximizeButton);
416+ mouseClick(gmailMaximizeButton);
397417
398418 tryCompare(dialerDelegate, "visuallyMaximized", true);
399− tryCompare(galleryDelegate, "visuallyMaximized", true);
419+ tryCompare(gmailDelegate, "visuallyMaximized", true);
400420
401421 tryCompare(dashApp.session.surface, "visible", false);
402422 tryCompare(dialerApp.session.surface, "visible", false);
403− tryCompare(cameraApp.session.surface, "visible", false);
423+ tryCompare(mapApp.session.surface, "visible", false);
404424
405− ApplicationManager.stopApplication("gallery-app");
425+ ApplicationManager.stopApplication("gmail-webapp");
406426
407− compare(cameraApp.session.surface.visible, true);
427+ compare(mapApp.session.surface.visible, true);
408428 tryCompare(dialerApp.session.surface, "visible", true);
409429 tryCompare(dashApp.session.surface, "visible", false); // still occluded by maximised dialer
410430 }
431+
432+ function test_maximisedAppStaysVisibleWhenAppStarts() {
433+ var dashApp = startApplication("unity8-dash");
434+ var dashDelegate = findChild(desktopStage, "appDelegate_unity8-dash");
435+ verify(dashDelegate);
436+ // maximize
437+ var dashMaximizeButton = findChild(dashDelegate, "maximizeWindowButton");
438+ verify(dashMaximizeButton);
439+ mouseClick(dashMaximizeButton);
440+ tryCompare(dashDelegate, "visuallyMaximized", true);
441+
442+ var dialerApp = startApplication("dialer-app");
443+ var dialerDelegate = findChild(desktopStage, "appDelegate_dialer-app");
444+ verify(dialerDelegate);
445+
446+ compare(dialerDelegate.visible, true, "Dialer should be visible");
447+ compare(dashDelegate.visible, true, "Dash should still be visible");
448+ }
411449 }
412450}
tests/qmltests/tst_Shell.qml−10
@@ -1777,15 +1777,10 @@ Rectangle {
17771777 tryCompare(panelButtons, "visible", false);
17781778
17791779 appDelegate.maximize(false);
1780− tryCompare(panelButtons, "visible", true);
17811780
17821781 shell.usageScenario = "phone";
17831782 waitForRendering(shell);
17841783 tryCompare(panelButtons, "visible", false);
1785−
1786− shell.usageScenario = "desktop";
1787− waitForRendering(shell);
1788− tryCompare(panelButtons, "visible", true);
17891784 }
17901785
17911786 function test_lockingGreeterHidesPanelButtons() {
@@ -1799,15 +1794,10 @@ Rectangle {
17991794 tryCompare(panelButtons, "visible", false);
18001795
18011796 appDelegate.maximize(false);
1802− tryCompare(panelButtons, "visible", true);
18031797
18041798 LightDM.Greeter.showGreeter();
18051799 waitForRendering(shell);
18061800 tryCompare(panelButtons, "visible", false);
1807−
1808− LightDM.Greeter.hideGreeter();
1809− waitForRendering(shell);
1810− tryCompare(panelButtons, "visible", true);
18111801 }
18121802
18131803 function test_cantMoveWindowUnderPanel() {