on xenial help sign in
merge prereq
23ba7e0Michael Zanetti
debian/control+1−1
@@ -29,7 +29,7 @@ Build-Depends: cmake,
29 libqt5xmlpatterns5-dev,
29 libqt5xmlpatterns5-dev,
30 libsystemsettings-dev,
30 libsystemsettings-dev,
31 libudev-dev,
31 libudev-dev,
32− libunity-api-dev (>= 7.102),
32+ libunity-api-dev (>= 7.101),
33 libusermetricsoutput1-dev,
33 libusermetricsoutput1-dev,
34 libxcb1-dev,
34 libxcb1-dev,
35 pkg-config,
35 pkg-config,
plugins/Utils/windowstatestorage.cpp+61−22
@@ -47,26 +47,38 @@ WindowStateStorage::~WindowStateStorage()
47 m_db.close();
47 m_db.close();
48}
48}
49
49
50−void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect)
50+void WindowStateStorage::saveState(const QString &windowId, WindowStateStorage::WindowState state)
51{
51{
52− QMutexLocker mutexLocker(&s_mutex);
52+ const QString queryString = QStringLiteral("INSERT OR REPLACE INTO state (windowId, state) values ('%1', '%2');")
53+ .arg(windowId)
54+ .arg((int)state);
55+
56+ saveValue(queryString);
57+}
58+
59+WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue) const
60+{
61+ const QString queryString = QStringLiteral("SELECT * FROM state WHERE windowId = '%1';")
62+ .arg(windowId);
53
63
64+ QSqlQuery query = getValue(queryString);
65+
66+ if (!query.first()) {
67+ return defaultValue;
68+ }
69+ return (WindowState)query.value("state").toInt();
70+}
71+
72+void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect)
73+{
54− QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');")
74+ const QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');")
55 .arg(windowId)
75 .arg(windowId)
56 .arg(rect.x())
76 .arg(rect.x())
57 .arg(rect.y())
77 .arg(rect.y())
58 .arg(rect.width())
78 .arg(rect.width())
59 .arg(rect.height());
79 .arg(rect.height());
60
80
61− QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
81+ saveValue(queryString);
62− m_asyncQueries.append(future);
63−
64− QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
65− futureWatcher->setFuture(future);
66− connect(futureWatcher, &QFutureWatcher<void>::finished,
67− this,
68− [=](){ m_asyncQueries.removeAll(futureWatcher->future());
69− futureWatcher->deleteLater(); });
70}
82}
71
83
72void WindowStateStorage::executeAsyncQuery(const QString &queryString)
84void WindowStateStorage::executeAsyncQuery(const QString &queryString)
@@ -82,20 +94,13 @@ void WindowStateStorage::executeAsyncQuery(const QString &queryString)
82 }
94 }
83}
95}
84
96
85−QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue)
97+QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue) const
86{
98{
87− QMutexLocker l(&s_mutex);
88 QString queryString = QStringLiteral("SELECT * FROM geometry WHERE windowId = '%1';")
99 QString queryString = QStringLiteral("SELECT * FROM geometry WHERE windowId = '%1';")
89 .arg(windowId);
100 .arg(windowId);
90− QSqlQuery query;
91
101
92− bool ok = query.exec(queryString);
102+ QSqlQuery query = getValue(queryString);
93− if (!ok) {
103+
94− qWarning() << "Error retrieving window state for" << windowId
95− << "Driver error:" << query.lastError().driverText()
96− << "Database error:" << query.lastError().databaseText();
97− return defaultValue;
98− }
99 if (!query.first()) {
104 if (!query.first()) {
100 return defaultValue;
105 return defaultValue;
101 }
106 }
@@ -114,4 +119,38 @@ void WindowStateStorage::initdb()
114 QSqlQuery query;
119 QSqlQuery query;
115 query.exec(QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);"));
120 query.exec(QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);"));
116 }
121 }
122+
123+ if (!m_db.tables().contains("state")) {
124+ QSqlQuery query;
125+ query.exec("CREATE TABLE state(windowId TEXT UNIQUE, state INTEGER);");
126+ }
127+}
128+
129+void WindowStateStorage::saveValue(const QString &queryString)
130+{
131+ QMutexLocker mutexLocker(&s_mutex);
132+
133+ QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
134+ m_asyncQueries.append(future);
135+
136+ QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
137+ futureWatcher->setFuture(future);
138+ connect(futureWatcher, &QFutureWatcher<void>::finished,
139+ this,
140+ [=](){ m_asyncQueries.removeAll(futureWatcher->future());
141+ futureWatcher->deleteLater(); });
142+}
143+
144+QSqlQuery WindowStateStorage::getValue(const QString &queryString) const
145+{
146+ QMutexLocker l(&s_mutex);
147+ QSqlQuery query;
148+
149+ bool ok = query.exec(queryString);
150+ if (!ok) {
151+ qWarning() << "Error retrieving database query:" << queryString
152+ << "Driver error:" << query.lastError().driverText()
153+ << "Database error:" << query.lastError().databaseText();
154+ }
155+ return query;
117}
156}
plugins/Utils/windowstatestorage.h+13−1
@@ -22,16 +22,28 @@
22class WindowStateStorage: public QObject
22class WindowStateStorage: public QObject
23{
23{
24 Q_OBJECT
24 Q_OBJECT
25+ Q_ENUMS(WindowState)
25public:
26public:
27+ enum WindowState {
28+ WindowStateNormal,
29+ WindowStateMaximized
30+ };
31+
26 WindowStateStorage(QObject *parent = 0);
32 WindowStateStorage(QObject *parent = 0);
27 virtual ~WindowStateStorage();
33 virtual ~WindowStateStorage();
28
34
35+ Q_INVOKABLE void saveState(const QString &windowId, WindowState state);
36+ Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue) const;
37+
29 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
38 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
30− Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue);
39+ Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue) const;
31
40
32private:
41private:
33 void initdb();
42 void initdb();
34
43
44+ void saveValue(const QString &queryString);
45+ QSqlQuery getValue(const QString &queryString) const;
46+
35 static void executeAsyncQuery(const QString &queryString);
47 static void executeAsyncQuery(const QString &queryString);
36 static QMutex s_mutex;
48 static QMutex s_mutex;
37
49
qml/Components/Orientations.qmlnew file+29
@@ -0,0 +1,29 @@
1+/*
2+ * Copyright 2015 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+QtObject {
20+ // Just because "native" is a reserved keyword :(
21+ property int native_: Qt.PortraitOrientation
22+
23+ property int primary: Qt.PortraitOrientation
24+
25+ property int landscape: Qt.LandscapeOrientation
26+ property int invertedLandscape: Qt.InvertedLandscapeOrientation
27+ property int portrait: Qt.PortraitOrientation
28+ property int invertedPortrait: Qt.InvertedPortraitOrientation
29+}
qml/Components/WindowControlButtons.qml+3
@@ -28,6 +28,7 @@ Row {
28 signal maximize()
28 signal maximize()
29
29
30 Rectangle {
30 Rectangle {
31+ objectName: "closeWindowButton"
31 height: parent.height; width: height; radius: height / 2
32 height: parent.height; width: height; radius: height / 2
32 gradient: Gradient {
33 gradient: Gradient {
33 GradientStop { color: "#F49073"; position: 0 }
34 GradientStop { color: "#F49073"; position: 0 }
@@ -38,6 +39,7 @@ Row {
38 MouseArea { anchors.fill: parent; onClicked: root.close() }
39 MouseArea { anchors.fill: parent; onClicked: root.close() }
39 }
40 }
40 Rectangle {
41 Rectangle {
42+ objectName: "minimizeWindowButton"
41 height: parent.height; width: height; radius: height / 2
43 height: parent.height; width: height; radius: height / 2
42 gradient: Gradient {
44 gradient: Gradient {
43 GradientStop { color: "#92918C"; position: 0 }
45 GradientStop { color: "#92918C"; position: 0 }
@@ -48,6 +50,7 @@ Row {
48 MouseArea { anchors.fill: parent; onClicked: root.minimize() }
50 MouseArea { anchors.fill: parent; onClicked: root.minimize() }
49 }
51 }
50 Rectangle {
52 Rectangle {
53+ objectName: "maximizeWindowButton"
51 height: parent.height; width: height; radius: height / 2
54 height: parent.height; width: height; radius: height / 2
52 gradient: Gradient {
55 gradient: Gradient {
53 GradientStop { color: "#92918C"; position: 0 }
56 GradientStop { color: "#92918C"; position: 0 }
qml/DeviceConfiguration.qml+84−64
@@ -16,79 +16,99 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18
18
19−StateGroup {
19+QtObject {
20 id: root
20 id: root
21
21
22 readonly property int useNativeOrientation: -1
22 readonly property int useNativeOrientation: -1
23
23
24− property int primaryOrientation: useNativeOrientation
24+ // The only writable property in the API
25+ // all other properties are set according to the device name
26+ property alias name: priv.state
25
27
26− property int supportedOrientations: Qt.PortraitOrientation
28+ readonly property alias primaryOrientation: priv.primaryOrientation
27− | Qt.InvertedPortraitOrientation
29+ readonly property alias supportedOrientations: priv.supportedOrientations
28− | Qt.LandscapeOrientation
30+ readonly property alias landscapeOrientation: priv.landscapeOrientation
29− | Qt.InvertedLandscapeOrientation
31+ readonly property alias invertedLandscapeOrientation: priv.invertedLandscapeOrientation
32+ readonly property alias portraitOrientation: priv.portraitOrientation
33+ readonly property alias invertedPortraitOrientation: priv.invertedPortraitOrientation
30
34
31− // Supported values so far:
32− // "phone", "tablet" or "desktop"
33− property string category: "phone"
35+ readonly property alias category: priv.category
34
36
35− property int ignoredMice: 0
37+ readonly property alias ignoredMice: priv.ignoredMice
36
38
39+ readonly property var priv: StateGroup {
40+ id: priv
37
41
38− property alias name: root.state
42+ property int primaryOrientation: root.useNativeOrientation
39
43
40− states: [
44+ property int supportedOrientations: Qt.PortraitOrientation
41− State {
45+ | Qt.InvertedPortraitOrientation
42− name: "mako"
43− PropertyChanges {
44− target: root
45− supportedOrientations: Qt.PortraitOrientation
46− | Qt.LandscapeOrientation
46+ | Qt.LandscapeOrientation
47− | Qt.InvertedLandscapeOrientation
47+ | Qt.InvertedLandscapeOrientation
48− }
48+
49− },
49+ property int landscapeOrientation: Qt.LandscapeOrientation
50− State {
51− name: "krillin"
52− PropertyChanges {
53− target: root
54− supportedOrientations: Qt.PortraitOrientation
55− | Qt.LandscapeOrientation
56− | Qt.InvertedLandscapeOrientation
50+ property int invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
57− }
58− },
59− State {
60− name: "arale"
61− PropertyChanges {
62− target: root
63− supportedOrientations: Qt.PortraitOrientation
51+ property int portraitOrientation: Qt.PortraitOrientation
64− | Qt.LandscapeOrientation
52+ property int invertedPortraitOrientation: Qt.InvertedPortraitOrientation
65− | Qt.InvertedLandscapeOrientation
53+
66− ignoredMice: 1
54+ // Supported values so far:
67− }
68− },
69− State {
70− name: "manta"
71− PropertyChanges {
72− target: root
73− category: "tablet"
74− }
75− },
76− State {
77− name: "flo"
78− PropertyChanges {
79− target: root
80− primaryOrientation: Qt.InvertedLandscapeOrientation
81− category: "tablet"
82− }
83− },
84− State {
85− name: "desktop"
55+ // "phone", "tablet" or "desktop"
86− PropertyChanges {
56+ property string category: "phone"
87− target: root
88− category: "desktop"
89− supportedOrientations: root.useNativeOrientation
90− }
91− }
92− ]
93
57
58+ property int ignoredMice: 0
59+
60+ states: [
61+ State {
62+ name: "mako"
63+ PropertyChanges {
64+ target: priv
65+ supportedOrientations: Qt.PortraitOrientation
66+ | Qt.LandscapeOrientation
67+ | Qt.InvertedLandscapeOrientation
68+ }
69+ },
70+ State {
71+ name: "krillin"
72+ PropertyChanges {
73+ target: priv
74+ supportedOrientations: Qt.PortraitOrientation
75+ | Qt.LandscapeOrientation
76+ | Qt.InvertedLandscapeOrientation
77+ }
78+ },
79+ State {
80+ name: "arale"
81+ PropertyChanges {
82+ target: priv
83+ supportedOrientations: Qt.PortraitOrientation
84+ | Qt.LandscapeOrientation
85+ | Qt.InvertedLandscapeOrientation
86+ ignoredMice: 1
87+ }
88+ },
89+ State {
90+ name: "manta"
91+ PropertyChanges {
92+ target: priv
93+ category: "tablet"
94+ }
95+ },
96+ State {
97+ name: "flo"
98+ PropertyChanges {
99+ target: priv
100+ landscapeOrientation: Qt.InvertedLandscapeOrientation
101+ primaryOrientation: Qt.InvertedLandscapeOrientation
102+ category: "tablet"
103+ }
104+ },
105+ State {
106+ name: "desktop"
107+ PropertyChanges {
108+ target: priv
109+ category: "desktop"
110+ }
111+ }
112+ ]
113+ }
94}
114}
qml/OrientedShell.qml+31−21
@@ -32,20 +32,31 @@ Rectangle {
32 implicitWidth: units.gu(40)
32 implicitWidth: units.gu(40)
33 implicitHeight: units.gu(71)
33 implicitHeight: units.gu(71)
34
34
35− // NB: native and primary orientations here don't map exactly to their QScreen counterparts
36− readonly property int nativeOrientation: width > height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
37−
38− readonly property int primaryOrientation:
39− deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
40− ? nativeOrientation : deviceConfiguration.primaryOrientation
41−
42 DeviceConfiguration {
35 DeviceConfiguration {
43 id: deviceConfiguration
36 id: deviceConfiguration
44 name: applicationArguments.deviceName
37 name: applicationArguments.deviceName
45 }
38 }
46
39
40+ property alias orientations: d.orientations
41+
42+ Item {
43+ id: d
44+
45+ property Orientations orientations: Orientations {
46+ id: orientations
47+ // NB: native and primary orientations here don't map exactly to their QScreen counterparts
48+ native_: root.width > root.height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
47
49
50+ primary: deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
51+ ? native_ : deviceConfiguration.primaryOrientation
52+
53+ landscape: deviceConfiguration.landscapeOrientation
54+ invertedLandscape: deviceConfiguration.invertedLandscapeOrientation
55+ portrait: deviceConfiguration.portraitOrientation
56+ invertedPortrait: deviceConfiguration.invertedPortraitOrientation
57+ }
58+ }
48− // to be overwritten by tests
59+ // to be overwritten by tests
49 property var unity8Settings: Unity8Settings {}
60 property var unity8Settings: Unity8Settings {}
50 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
61 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
51
62
@@ -101,7 +112,7 @@ Rectangle {
101
112
102 property int acceptedOrientationAngle: {
113 property int acceptedOrientationAngle: {
103 if (orientation & supportedOrientations) {
114 if (orientation & supportedOrientations) {
104− return Screen.angleBetween(nativeOrientation, orientation);
115+ return Screen.angleBetween(orientations.native_, orientation);
105 } else if (shell.orientation & supportedOrientations) {
116 } else if (shell.orientation & supportedOrientations) {
106 // stay where we are
117 // stay where we are
107 return shell.orientationAngle;
118 return shell.orientationAngle;
@@ -111,16 +122,16 @@ Rectangle {
111 // rotate to some supported orientation as we can't stay where we currently are
122 // rotate to some supported orientation as we can't stay where we currently are
112 // TODO: Choose the closest to the current one
123 // TODO: Choose the closest to the current one
113 if (supportedOrientations & Qt.PortraitOrientation) {
124 if (supportedOrientations & Qt.PortraitOrientation) {
114− return Screen.angleBetween(nativeOrientation, Qt.PortraitOrientation);
125+ return Screen.angleBetween(orientations.native_, Qt.PortraitOrientation);
115 } else if (supportedOrientations & Qt.LandscapeOrientation) {
126 } else if (supportedOrientations & Qt.LandscapeOrientation) {
116− return Screen.angleBetween(nativeOrientation, Qt.LandscapeOrientation);
127+ return Screen.angleBetween(orientations.native_, Qt.LandscapeOrientation);
117 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
128 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
118− return Screen.angleBetween(nativeOrientation, Qt.InvertedPortraitOrientation);
129+ return Screen.angleBetween(orientations.native_, Qt.InvertedPortraitOrientation);
119 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
130 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
120− return Screen.angleBetween(nativeOrientation, Qt.InvertedLandscapeOrientation);
131+ return Screen.angleBetween(orientations.native_, Qt.InvertedLandscapeOrientation);
121 } else {
132 } else {
122 // if all fails, fallback to primary orientation
133 // if all fails, fallback to primary orientation
123− return Screen.angleBetween(nativeOrientation, primaryOrientation);
134+ return Screen.angleBetween(orientations.native_, orientations.primary);
124 }
135 }
125 }
136 }
126 }
137 }
@@ -128,19 +139,19 @@ Rectangle {
128 function angleToOrientation(angle) {
139 function angleToOrientation(angle) {
129 switch (angle) {
140 switch (angle) {
130 case 0:
141 case 0:
131− return nativeOrientation;
142+ return orientations.native_;
132 case 90:
143 case 90:
133− return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
144+ return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
134 : Qt.PortraitOrientation;
145 : Qt.PortraitOrientation;
135 case 180:
146 case 180:
136− return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
147+ return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
137 : Qt.InvertedLandscapeOrientation;
148 : Qt.InvertedLandscapeOrientation;
138 case 270:
149 case 270:
139− return nativeOrientation === Qt.PortraitOrientation ? Qt.LandscapeOrientation
150+ return orientations.native_ === Qt.PortraitOrientation ? Qt.LandscapeOrientation
140 : Qt.InvertedPortraitOrientation;
151 : Qt.InvertedPortraitOrientation;
141 default:
152 default:
142 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
153 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
143− return primaryOrientation;
154+ return orientations.primary;
144 }
155 }
145 }
156 }
146
157
@@ -159,8 +170,7 @@ Rectangle {
159 width: root.width
170 width: root.width
160 height: root.height
171 height: root.height
161 orientation: root.angleToOrientation(orientationAngle)
172 orientation: root.angleToOrientation(orientationAngle)
162− primaryOrientation: root.primaryOrientation
173+ orientations: root.orientations
163− nativeOrientation: root.nativeOrientation
164 nativeWidth: root.width
174 nativeWidth: root.width
165 nativeHeight: root.height
175 nativeHeight: root.height
166 mode: applicationArguments.mode
176 mode: applicationArguments.mode
qml/Panel/Panel.qml+5−3
@@ -28,6 +28,7 @@ Item {
28 property alias callHint: __callHint
28 property alias callHint: __callHint
29 property bool fullscreenMode: false
29 property bool fullscreenMode: false
30 property real indicatorAreaShowProgress: 1.0
30 property real indicatorAreaShowProgress: 1.0
31+ property bool locked: false
31
32
32 opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
33 opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
33
34
@@ -136,7 +137,7 @@ Item {
136 }
137 }
137
138
138 shown: false
139 shown: false
139− width: root.width - (PanelState.buttonsVisible ? windowControlButtons.width : 0)
140+ width: root.width - (windowControlButtons.visible ? windowControlButtons.width : 0)
140 minimizedPanelHeight: units.gu(3)
141 minimizedPanelHeight: units.gu(3)
141 expandedPanelHeight: units.gu(7)
142 expandedPanelHeight: units.gu(7)
142 openedHeight: root.height - indicatorOrangeLine.height
143 openedHeight: root.height - indicatorOrangeLine.height
@@ -164,13 +165,14 @@ Item {
164
165
165 WindowControlButtons {
166 WindowControlButtons {
166 id: windowControlButtons
167 id: windowControlButtons
168+ objectName: "panelWindowControlButtons"
167 anchors {
169 anchors {
168 left: parent.left
170 left: parent.left
169 top: parent.top
171 top: parent.top
170 margins: units.gu(0.7)
172 margins: units.gu(0.7)
171 }
173 }
172 height: indicators.minimizedPanelHeight - anchors.margins * 2
174 height: indicators.minimizedPanelHeight - anchors.margins * 2
173− visible: PanelState.buttonsVisible
175+ visible: PanelState.buttonsVisible && !root.locked
174 onClose: PanelState.close()
176 onClose: PanelState.close()
175 onMinimize: PanelState.minimize()
177 onMinimize: PanelState.minimize()
176 onMaximize: PanelState.maximize()
178 onMaximize: PanelState.maximize()
@@ -189,7 +191,7 @@ Item {
189 id: __callHint
191 id: __callHint
190 anchors {
192 anchors {
191 top: parent.top
193 top: parent.top
192− left: PanelState.buttonsVisible ? windowControlButtons.right : parent.left
194+ left: windowControlButtons.visible ? windowControlButtons.right : parent.left
193 }
195 }
194 height: indicators.minimizedPanelHeight
196 height: indicators.minimizedPanelHeight
195 visible: active && indicators.state == "initial"
197 visible: active && indicators.state == "initial"
qml/Shell.qml+7−11
@@ -48,14 +48,14 @@ Item {
48 // to be set from outside
48 // to be set from outside
49 property int orientationAngle: 0
49 property int orientationAngle: 0
50 property int orientation
50 property int orientation
51− property int primaryOrientation
51+ property Orientations orientations
52− property int nativeOrientation
53 property real nativeWidth
52 property real nativeWidth
54 property real nativeHeight
53 property real nativeHeight
55 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
54 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
56 property bool beingResized
55 property bool beingResized
57 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
56 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
58 property string mode: "full-greeter"
57 property string mode: "full-greeter"
58+ property bool cursorVisible: false
59 function updateFocusedAppOrientation() {
59 function updateFocusedAppOrientation() {
60 applicationsDisplayLoader.item.updateFocusedAppOrientation();
60 applicationsDisplayLoader.item.updateFocusedAppOrientation();
61 }
61 }
@@ -317,18 +317,13 @@ Item {
317 }
317 }
318 Binding {
318 Binding {
319 target: applicationsDisplayLoader.item
319 target: applicationsDisplayLoader.item
320− property: "background"
320+ property: "orientations"
321− value: wallpaperResolver.background
321+ value: shell.orientations
322 }
322 }
323 Binding {
323 Binding {
324 target: applicationsDisplayLoader.item
324 target: applicationsDisplayLoader.item
325− property: "shellPrimaryOrientation"
325+ property: "background"
326− value: shell.primaryOrientation
326+ value: wallpaperResolver.background
327− }
328− Binding {
329− target: applicationsDisplayLoader.item
330− property: "nativeOrientation"
331− value: shell.nativeOrientation
332 }
327 }
333 Binding {
328 Binding {
334 target: applicationsDisplayLoader.item
329 target: applicationsDisplayLoader.item
@@ -555,6 +550,7 @@ Item {
555
550
556 fullscreenMode: (topmostApplicationIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
551 fullscreenMode: (topmostApplicationIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
557 || greeter.hasLockedApp
552 || greeter.hasLockedApp
553+ locked: greeter && greeter.active
558 }
554 }
559
555
560 Launcher {
556 Launcher {
qml/Stages/AbstractStage.qml+2−3
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18−import Ubuntu.Components 1.2
18+import Ubuntu.Components 1.3
19import GSettings 1.0
19import GSettings 1.0
20
20
21Rectangle {
21Rectangle {
@@ -33,11 +33,10 @@ Rectangle {
33 property bool keepDashRunning: true
33 property bool keepDashRunning: true
34 property real maximizedAppTopMargin
34 property real maximizedAppTopMargin
35 property real nativeHeight
35 property real nativeHeight
36− property int nativeOrientation
37 property real nativeWidth
36 property real nativeWidth
37+ property QtObject orientations
38 property int shellOrientation
38 property int shellOrientation
39 property int shellOrientationAngle
39 property int shellOrientationAngle
40− property int shellPrimaryOrientation
41 property bool spreadEnabled: true // If false, animations and right edge will be disabled
40 property bool spreadEnabled: true // If false, animations and right edge will be disabled
42 property bool suspended
41 property bool suspended
43
42
qml/Stages/DesktopStage.qml+10−3
@@ -22,6 +22,7 @@ import Ubuntu.Components 1.1
22import Unity.Application 0.1
22import Unity.Application 0.1
23import "../Components"
23import "../Components"
24import "../Components/PanelState"
24import "../Components/PanelState"
25+import "../Components"
25import Utils 0.1
26import Utils 0.1
26import Ubuntu.Gestures 0.1
27import Ubuntu.Gestures 0.1
27
28
@@ -92,6 +93,7 @@ AbstractStage {
92 property: "buttonsVisible"
93 property: "buttonsVisible"
93 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.state === "maximized"
94 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.state === "maximized"
94 }
95 }
96+ Component.onDestruction: PanelState.buttonsVisible = false;
95
97
96 FocusScope {
98 FocusScope {
97 id: appContainer
99 id: appContainer
@@ -122,6 +124,7 @@ AbstractStage {
122
124
123 property bool maximized: false
125 property bool maximized: false
124 property bool minimized: false
126 property bool minimized: false
127+ property bool animationsEnabled: true
125
128
126 onFocusChanged: {
129 onFocusChanged: {
127 if (focus && ApplicationManager.focusedApplicationId !== model.appId) {
130 if (focus && ApplicationManager.focusedApplicationId !== model.appId) {
@@ -140,15 +143,18 @@ AbstractStage {
140 value: ApplicationInfoInterface.RequestedRunning // Always running for now
143 value: ApplicationInfoInterface.RequestedRunning // Always running for now
141 }
144 }
142
145
143− function maximize() {
146+ function maximize(animated) {
147+ animationsEnabled = (animated === undefined) || animated;
144 minimized = false;
148 minimized = false;
145 maximized = true;
149 maximized = true;
146 }
150 }
147− function minimize() {
151+ function minimize(animated) {
152+ animationsEnabled = (animated === undefined) || animated;
148 maximized = false;
153 maximized = false;
149 minimized = true;
154 minimized = true;
150 }
155 }
151− function unmaximize() {
156+ function unmaximize(animated) {
157+ animationsEnabled = (animated === undefined) || animated;
152 minimized = false;
158 minimized = false;
153 maximized = false;
159 maximized = false;
154 }
160 }
@@ -170,6 +176,7 @@ AbstractStage {
170 Transition {
176 Transition {
171 from: "maximized,minimized,normal,"
177 from: "maximized,minimized,normal,"
172 to: "maximized,minimized,normal,"
178 to: "maximized,minimized,normal,"
179+ enabled: appDelegate.animationsEnabled
173 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
180 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
174 },
181 },
175 Transition {
182 Transition {
qml/Stages/PhoneStage.qml+3−4
@@ -30,6 +30,7 @@ AbstractStage {
30 property bool altTabEnabled: true
30 property bool altTabEnabled: true
31 property real startScale: 1.1
31 property real startScale: 1.1
32 property real endScale: 0.7
32 property real endScale: 0.7
33+
33 onBeingResizedChanged: {
34 onBeingResizedChanged: {
34 if (beingResized) {
35 if (beingResized) {
35 // Brace yourselves for impact!
36 // Brace yourselves for impact!
@@ -58,7 +59,7 @@ AbstractStage {
58
59
59 var supportedOrientations = spreadDelegate.application.supportedOrientations;
60 var supportedOrientations = spreadDelegate.application.supportedOrientations;
60 if (supportedOrientations === Qt.PrimaryOrientation) {
61 if (supportedOrientations === Qt.PrimaryOrientation) {
61− supportedOrientations = spreadDelegate.shellPrimaryOrientation;
62+ supportedOrientations = root.orientations.primary;
62 }
63 }
63
64
64 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
65 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
@@ -523,11 +524,9 @@ AbstractStage {
523 visible: (progress >= 0 && progress < 1.7)
524 visible: (progress >= 0 && progress < 1.7)
524 || (isDash && priv.focusedAppDelegateIsDislocated)
525 || (isDash && priv.focusedAppDelegateIsDislocated)
525
526
526−
527 shellOrientationAngle: root.shellOrientationAngle
527 shellOrientationAngle: root.shellOrientationAngle
528 shellOrientation: root.shellOrientation
528 shellOrientation: root.shellOrientation
529− shellPrimaryOrientation: root.shellPrimaryOrientation
529+ orientations: root.orientations
530− nativeOrientation: root.nativeOrientation
531
530
532 onClicked: {
531 onClicked: {
533 if (root.altTabEnabled && spreadView.phase == 2) {
532 if (root.altTabEnabled && spreadView.phase == 2) {
qml/Stages/SpreadDelegate.qml+8−9
@@ -42,8 +42,7 @@ FocusScope {
42 property alias application: appWindow.application
42 property alias application: appWindow.application
43 property int shellOrientationAngle
43 property int shellOrientationAngle
44 property int shellOrientation
44 property int shellOrientation
45− property int shellPrimaryOrientation
45+ property QtObject orientations
46− property int nativeOrientation
47
46
48 function matchShellOrientation() {
47 function matchShellOrientation() {
49 if (!root.application)
48 if (!root.application)
@@ -157,7 +156,7 @@ FocusScope {
157 var supportedOrientations = root.application.supportedOrientations;
156 var supportedOrientations = root.application.supportedOrientations;
158
157
159 if (supportedOrientations === Qt.PrimaryOrientation) {
158 if (supportedOrientations === Qt.PrimaryOrientation) {
160− supportedOrientations = root.shellPrimaryOrientation;
159+ supportedOrientations = root.orientations.primary;
161 }
160 }
162
161
163 // If it doesn't support shell's current orientation
162 // If it doesn't support shell's current orientation
@@ -166,18 +165,18 @@ FocusScope {
166 if (supportedOrientations & root.shellOrientation) {
165 if (supportedOrientations & root.shellOrientation) {
167 chosenOrientation = root.shellOrientation;
166 chosenOrientation = root.shellOrientation;
168 } else if (supportedOrientations & Qt.PortraitOrientation) {
167 } else if (supportedOrientations & Qt.PortraitOrientation) {
169− chosenOrientation = Qt.PortraitOrientation;
168+ chosenOrientation = root.orientations.portrait;
170 } else if (supportedOrientations & Qt.LandscapeOrientation) {
169 } else if (supportedOrientations & Qt.LandscapeOrientation) {
171− chosenOrientation = Qt.LandscapeOrientation;
170+ chosenOrientation = root.orientations.landscape;
172 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
171 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
173− chosenOrientation = Qt.InvertedPortraitOrientation;
172+ chosenOrientation = root.orientations.invertedPortrait;
174 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
173 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
175− chosenOrientation = Qt.InvertedLandscapeOrientation;
174+ chosenOrientation = root.orientations.invertedLandscape;
176 } else {
175 } else {
177− chosenOrientation = root.shellPrimaryOrientation;
176+ chosenOrientation = root.orientations.primary;
178 }
177 }
179
178
180− return Screen.angleBetween(root.nativeOrientation, chosenOrientation);
179+ return Screen.angleBetween(root.orientations.native_, chosenOrientation);
181 }
180 }
182
181
183 rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
182 rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
qml/Stages/TabletStage.qml+10−5
@@ -47,7 +47,7 @@ AbstractStage {
47
47
48 var supportedOrientations = spreadDelegate.application.supportedOrientations;
48 var supportedOrientations = spreadDelegate.application.supportedOrientations;
49 if (supportedOrientations === Qt.PrimaryOrientation) {
49 if (supportedOrientations === Qt.PrimaryOrientation) {
50− supportedOrientations = spreadDelegate.shellPrimaryOrientation;
50+ supportedOrientations = spreadDelegate.orientations.primary;
51 }
51 }
52
52
53 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
53 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
@@ -110,7 +110,7 @@ AbstractStage {
110 property string oldFocusedAppId: ""
110 property string oldFocusedAppId: ""
111 property bool mainAppOrientationChangesEnabled: false
111 property bool mainAppOrientationChangesEnabled: false
112
112
113− property real landscapeHeight: root.nativeOrientation == Qt.LandscapeOrientation ?
113+ property real landscapeHeight: root.orientations.native_ == Qt.LandscapeOrientation ?
114 root.nativeHeight : root.nativeWidth
114 root.nativeHeight : root.nativeWidth
115
115
116 property bool shellIsLandscape: root.shellOrientation === Qt.LandscapeOrientation
116 property bool shellIsLandscape: root.shellOrientation === Qt.LandscapeOrientation
@@ -674,9 +674,14 @@ AbstractStage {
674
674
675 shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
675 shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
676 shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
676 shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
677+ orientations: Orientations {
677− shellPrimaryOrientation: wantsMainStage ? root.shellPrimaryOrientation : Qt.PortraitOrientation
678+ primary: spreadTile.wantsMainStage ? root.orientations.primary : Qt.PortraitOrientation
678− nativeOrientation: wantsMainStage ? root.nativeOrientation : Qt.PortraitOrientation
679+ native_: spreadTile.wantsMainStage ? root.orientations.native_ : Qt.PortraitOrientation
679−
680+ portrait: root.orientations.portrait
681+ invertedPortrait: root.orientations.invertedPortrait
682+ landscape: root.orientations.landscape
683+ invertedLandscape: root.orientations.invertedLandscape
684+ }
680
685
681 onClicked: {
686 onClicked: {
682 if (spreadView.phase == 2) {
687 if (spreadView.phase == 2) {
qml/Stages/WindowResizeArea.qml+38−7
@@ -36,18 +36,49 @@ MouseArea {
36 property int minWidth: 0
36 property int minWidth: 0
37 property int minHeight: 0
37 property int minHeight: 0
38
38
39+ QtObject {
40+ id: priv
41+
42+ property int normalX: 0
43+ property int normalY: 0
44+ property int normalWidth: 0
45+ property int normalHeight: 0
46+
47+ function updateNormalGeometry() {
48+ if (root.target.state == "normal") {
49+ normalX = root.target.x
50+ normalY = root.target.y
51+ normalWidth = root.target.width
52+ normalHeight = root.target.height
53+ }
54+ }
55+ }
56+
57+ Connections {
58+ target: root.target
59+ onXChanged: priv.updateNormalGeometry();
60+ onYChanged: priv.updateNormalGeometry();
61+ onWidthChanged: priv.updateNormalGeometry();
62+ onHeightChanged: priv.updateNormalGeometry();
63+ }
64+
39 Component.onCompleted: {
65 Component.onCompleted: {
40− var windowState = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
66+ var windowGeometry = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
41− if (windowState !== undefined) {
67+ if (windowGeometry !== undefined) {
42− target.x = windowState.x
68+ target.x = windowGeometry.x
43− target.y = windowState.y
69+ target.y = windowGeometry.y
44− target.width = windowState.width
70+ target.width = windowGeometry.width
45− target.height = windowState.height
71+ target.height = windowGeometry.height
72+ }
73+ var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
74+ if (windowState === WindowStateStorage.WindowStateMaximized) {
75+ target.maximize(false)
46 }
76 }
47 }
77 }
48
78
49 Component.onDestruction: {
79 Component.onDestruction: {
50− windowStateStorage.saveGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
80+ windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal)
81+ windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight))
51 }
82 }
52
83
53 QtObject {
84 QtObject {
tests/mocks/Utils/windowstatestorage.cpp+17
@@ -44,3 +44,20 @@ QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defa
44 if (!m_geometry.contains(windowId)) return defaultValue;
44 if (!m_geometry.contains(windowId)) return defaultValue;
45 return m_geometry.value(windowId).toRect();
45 return m_geometry.value(windowId).toRect();
46}
46}
47+
48+void WindowStateStorage::clear()
49+{
50+ m_state.clear();
51+ m_geometry.clear();
52+}
53+
54+void WindowStateStorage::saveState(const QString &windowId, WindowState state)
55+{
56+ m_state[windowId] = state;
57+}
58+
59+WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue)
60+{
61+ if (!m_state.contains(windowId)) return defaultValue;
62+ return m_state.value(windowId);
63+}
tests/mocks/Utils/windowstatestorage.h+12
@@ -22,12 +22,23 @@ class WindowStateStorage: public QObject
22{
22{
23 Q_OBJECT
23 Q_OBJECT
24 Q_PROPERTY(QVariantMap geometry READ geometry WRITE setGeometry NOTIFY geometryChanged)
24 Q_PROPERTY(QVariantMap geometry READ geometry WRITE setGeometry NOTIFY geometryChanged)
25+ Q_ENUMS(WindowState)
25public:
26public:
27+ enum WindowState {
28+ WindowStateNormal,
29+ WindowStateMaximized
30+ };
26 WindowStateStorage(QObject *parent = 0);
31 WindowStateStorage(QObject *parent = 0);
27
32
33+ Q_INVOKABLE void saveState(const QString &windowId, WindowState state);
34+ Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue);
35+
28 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
36 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
29 Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue);
37 Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue);
30
38
39+ // Only in the mock, to easily restore a fresh state
40+ Q_INVOKABLE void clear();
41+
31Q_SIGNALS:
42Q_SIGNALS:
32 void geometryChanged(const QVariantMap& geometry);
43 void geometryChanged(const QVariantMap& geometry);
33
44
@@ -35,5 +46,6 @@ private:
35 void setGeometry(const QVariantMap& geometry);
46 void setGeometry(const QVariantMap& geometry);
36 QVariantMap geometry() const;
47 QVariantMap geometry() const;
37
48
49+ QHash<QString, WindowState> m_state;
38 QVariantMap m_geometry;
50 QVariantMap m_geometry;
39};
51};
tests/qmltests/Stages/tst_PhoneStage.qml−2
@@ -34,8 +34,6 @@ Item {
34 maximizedAppTopMargin: units.gu(3) + units.dp(2)
34 maximizedAppTopMargin: units.gu(3) + units.dp(2)
35 interactive: true
35 interactive: true
36 shellOrientation: Qt.PortraitOrientation
36 shellOrientation: Qt.PortraitOrientation
37− shellPrimaryOrientation: Qt.PortraitOrientation
38− nativeOrientation: Qt.PortraitOrientation
39 }
37 }
40
38
41 Binding {
39 Binding {
tests/qmltests/Stages/tst_SpreadDelegate.qml+6−2
@@ -18,6 +18,7 @@ import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import Unity.Test 0.1 as UT
19import Unity.Test 0.1 as UT
20import ".."
20import ".."
21+import "../../../qml/Components"
21import "../../../qml/Stages"
22import "../../../qml/Stages"
22import Ubuntu.Components 0.1
23import Ubuntu.Components 0.1
23import Ubuntu.Components.ListItems 1.0 as ListItem
24import Ubuntu.Components.ListItems 1.0 as ListItem
@@ -73,8 +74,11 @@ Rectangle {
73 return Qt.LandscapeOrientation;
74 return Qt.LandscapeOrientation;
74 }
75 }
75 }
76 }
76− shellPrimaryOrientation: Qt.PortraitOrientation
77+
77− nativeOrientation: Qt.PortraitOrientation
78+ orientations: Orientations {
79+ // the default values will do
80+ }
81+
78 maximizedAppTopMargin: units.gu(3)
82 maximizedAppTopMargin: units.gu(3)
79 Component.onDestruction: {
83 Component.onDestruction: {
80 spreadDelegateLoader.itemDestroyed = true;
84 spreadDelegateLoader.itemDestroyed = true;
tests/qmltests/Stages/tst_TabletStage.qml+2−2
@@ -22,6 +22,7 @@ import Unity.Application 0.1
22import Unity.Test 0.1
22import Unity.Test 0.1
23
23
24import "../../../qml/Stages"
24import "../../../qml/Stages"
25+import "../../../qml/Components"
25
26
26Rectangle {
27Rectangle {
27 id: root
28 id: root
@@ -50,10 +51,9 @@ Rectangle {
50 maximizedAppTopMargin: units.gu(3) + units.dp(2)
51 maximizedAppTopMargin: units.gu(3) + units.dp(2)
51 interactive: true
52 interactive: true
52 shellOrientation: Qt.LandscapeOrientation
53 shellOrientation: Qt.LandscapeOrientation
53− shellPrimaryOrientation: Qt.LandscapeOrientation
54− nativeOrientation: Qt.LandscapeOrientation
55 nativeWidth: width
54 nativeWidth: width
56 nativeHeight: height
55 nativeHeight: height
56+ orientations: Orientations{} // Defaults are fine for testing
57 focus: true
57 focus: true
58 }
58 }
59 }
59 }
tests/qmltests/Stages/tst_WindowResizeArea.qml+35−2
@@ -44,8 +44,11 @@ Item {
44 width: units.gu(20)
44 width: units.gu(20)
45 property int windowHeight: height
45 property int windowHeight: height
46 property int windowWidth: width
46 property int windowWidth: width
47− onWindowHeightChanged: height = windowHeight
47+ state: "normal"
48− onWindowWidthChanged: width = windowWidth
48+
49+ function maximize() {
50+ state = "maximized"
51+ }
49
52
50 WindowResizeArea {
53 WindowResizeArea {
51 id: windowResizeArea
54 id: windowResizeArea
@@ -195,5 +198,35 @@ Item {
195 tryCompare(fakeWindow, "width", initialWindowWidth);
198 tryCompare(fakeWindow, "width", initialWindowWidth);
196 tryCompare(fakeWindow, "height", initialWindowHeight);
199 tryCompare(fakeWindow, "height", initialWindowHeight);
197 }
200 }
201+
202+ function test_saveRestoreMaximized() {
203+ var initialWindowX = fakeWindow.x;
204+ var initialWindowY = fakeWindow.y;
205+
206+ var moveDelta = units.gu(5);
207+
208+ fakeWindow.x = initialWindowX + moveDelta
209+ fakeWindow.y = initialWindowY + moveDelta
210+
211+ // Now change the state to maximized. The window should not keep updating the stored values
212+ fakeWindow.state = "maximized"
213+ fakeWindow.x = 31415 // 0 is too risky to pass the test even when broken
214+ fakeWindow.y = 31415
215+
216+ // This will destroy the window and recreate it
217+ windowLoader.active = false;
218+ waitForRendering(root);
219+ windowLoader.active = true;
220+
221+ // Make sure it's again where we left it in normal state before destroying
222+ tryCompare(fakeWindow, "x", initialWindowX + moveDelta)
223+ tryCompare(fakeWindow, "y", initialWindowX + moveDelta)
224+
225+ // Make sure maximize() has been called after restoring
226+ tryCompare(fakeWindow, "state", "maximized")
227+
228+ // clean up
229+ fakeWindow.state = "normal"
230+ }
198 }
231 }
199}
232}
tests/qmltests/tst_OrientedShell.qml+1−1
@@ -840,7 +840,7 @@ Rectangle {
840 // shell should remain in its primery orientation as the app in the main stage
840 // shell should remain in its primery orientation as the app in the main stage
841 // is the one that dictates its orientation. In this case it's unity8-dash
841 // is the one that dictates its orientation. In this case it's unity8-dash
842 // which supports only primary orientation
842 // which supports only primary orientation
843− compare(shell.orientation, orientedShell.primaryOrientation);
843+ compare(shell.orientation, orientedShell.orientations.primary);
844 }
844 }
845
845
846 function test_sideStageAppsRemainPortraitInSpread_data() {
846 function test_sideStageAppsRemainPortraitInSpread_data() {
tests/qmltests/tst_Shell.qml+75−2
@@ -29,8 +29,11 @@ import Unity.Notifications 1.0
29import Unity.Test 0.1
29import Unity.Test 0.1
30import Powerd 0.1
30import Powerd 0.1
31import Wizard 0.1 as Wizard
31import Wizard 0.1 as Wizard
32+import Utils 0.1
32
33
33import "../../qml"
34import "../../qml"
35+import "../../qml/Components"
36+import "../../qml/Components/PanelState"
34import "Stages"
37import "Stages"
35
38
36Rectangle {
39Rectangle {
@@ -97,8 +100,7 @@ Rectangle {
97 id: __shell
100 id: __shell
98 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
101 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
99 orientation: Qt.PortraitOrientation
102 orientation: Qt.PortraitOrientation
100− primaryOrientation: Qt.PortraitOrientation
103+ orientations: Orientations{} // Defaults are fine for testing
101− nativeOrientation: Qt.PortraitOrientation
102 Component.onDestruction: {
104 Component.onDestruction: {
103 shellLoader.itemDestroyed = true;
105 shellLoader.itemDestroyed = true;
104 }
106 }
@@ -302,6 +304,7 @@ Rectangle {
302 mouseEmulation.checked = true;
304 mouseEmulation.checked = true;
303 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
305 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
304 tearDown();
306 tearDown();
307+ WindowStateStorage.clear();
305 }
308 }
306
309
307 function loadShell(formFactor) {
310 function loadShell(formFactor) {
@@ -1710,6 +1713,76 @@ Rectangle {
1710 keyRelease(Qt.Key_Control);
1713 keyRelease(Qt.Key_Control);
1711 }
1714 }
1712
1715
1716+ // regression test for http://pad.lv/1443319
1717+ function test_closeMaximizedAndRestart() {
1718+ loadDesktopShellWithApps();
1719+
1720+ var appRepeater = findChild(shell, "appRepeater")
1721+ var appId = ApplicationManager.get(0).appId;
1722+ var appDelegate = appRepeater.itemAt(0);
1723+ var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
1724+
1725+ wait(5000)
1726+ tryCompare(appDelegate, "state", "normal");
1727+ tryCompare(PanelState, "buttonsVisible", false)
1728+
1729+ wait(5000)
1730+ mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2);
1731+ tryCompare(appDelegate, "state", "maximized");
1732+ tryCompare(PanelState, "buttonsVisible", true)
1733+
1734+ ApplicationManager.stopApplication(appId);
1735+ tryCompare(PanelState, "buttonsVisible", false)
1736+
1737+ ApplicationManager.startApplication(appId);
1738+ tryCompare(PanelState, "buttonsVisible", true)
1739+ }
1740+
1741+ // bug http://pad.lv/1431566
1742+ function test_switchToStagedHidesPanelButtons() {
1743+ loadDesktopShellWithApps();
1744+ var appRepeater = findChild(shell, "appRepeater")
1745+ var appId = ApplicationManager.get(0).appId;
1746+ var appDelegate = appRepeater.itemAt(0);
1747+ var panelButtons = findChild(shell, "panelWindowControlButtons")
1748+
1749+ tryCompare(appDelegate, "state", "normal");
1750+ tryCompare(panelButtons, "visible", false);
1751+
1752+ appDelegate.maximize(false);
1753+ tryCompare(panelButtons, "visible", true);
1754+
1755+ shell.usageScenario = "phone";
1756+ waitForRendering(shell);
1757+ tryCompare(panelButtons, "visible", false);
1758+
1759+ shell.usageScenario = "desktop";
1760+ waitForRendering(shell);
1761+ tryCompare(panelButtons, "visible", true);
1762+ }
1763+
1764+ function test_lockingGreeterHidesPanelButtons() {
1765+ loadDesktopShellWithApps();
1766+ var appRepeater = findChild(shell, "appRepeater")
1767+ var appId = ApplicationManager.get(0).appId;
1768+ var appDelegate = appRepeater.itemAt(0);
1769+ var panelButtons = findChild(shell, "panelWindowControlButtons")
1770+
1771+ tryCompare(appDelegate, "state", "normal");
1772+ tryCompare(panelButtons, "visible", false);
1773+
1774+ appDelegate.maximize(false);
1775+ tryCompare(panelButtons, "visible", true);
1776+
1777+ LightDM.Greeter.showGreeter();
1778+ waitForRendering(shell);
1779+ tryCompare(panelButtons, "visible", false);
1780+
1781+ LightDM.Greeter.hideGreeter();
1782+ waitForRendering(shell);
1783+ tryCompare(panelButtons, "visible", true);
1784+ }
1785+
1713 function test_lifecyclePolicy_data() {
1786 function test_lifecyclePolicy_data() {
1714 return [
1787 return [
1715 {tag: "phone", formFactor: "phone", usageScenario: "phone", suspendsApps: true},
1788 {tag: "phone", formFactor: "phone", usageScenario: "phone", suspendsApps: true},