Merge lp:~mzanetti/unity8/move-screenshots-to-tests into lp:unity8

Proposed by Michael Zanetti
Status: Superseded
Proposed branch: lp:~mzanetti/unity8/move-screenshots-to-tests
Merge into: lp:unity8
Diff against target: 2445 lines (+1138/-270)
47 files modified
CMakeLists.txt (+1/-1)
debian/control (+2/-2)
plugins/Utils/CMakeLists.txt (+2/-0)
plugins/Utils/applicationsfiltermodel.cpp (+101/-0)
plugins/Utils/applicationsfiltermodel.h (+69/-0)
plugins/Utils/plugin.cpp (+2/-0)
plugins/Utils/windowstatestorage.cpp (+62/-23)
plugins/Utils/windowstatestorage.h (+13/-1)
qml/Components/Dialogs.qml (+29/-2)
qml/Components/ModeSwitchWarningDialog.qml (+95/-0)
qml/Components/Orientations.qml (+29/-0)
qml/Components/ShellDialog.qml (+1/-1)
qml/Components/WindowControlButtons.qml (+3/-0)
qml/DeviceConfiguration.qml (+91/-71)
qml/OrientedShell.qml (+32/-22)
qml/Panel/Panel.qml (+5/-3)
qml/Shell.qml (+8/-12)
qml/Stages/AbstractStage.qml (+63/-0)
qml/Stages/DesktopStage.qml (+14/-24)
qml/Stages/PhoneStage.qml (+21/-34)
qml/Stages/ShimStage.qml (+1/-1)
qml/Stages/SpreadDelegate.qml (+8/-9)
qml/Stages/TabletStage.qml (+24/-36)
qml/Stages/WindowResizeArea.qml (+38/-7)
tests/mocks/GSettings.1.0/fake_gsettings.cpp (+31/-0)
tests/mocks/GSettings.1.0/fake_gsettings.h (+10/-0)
tests/mocks/Unity/Application/ApplicationInfo.cpp (+16/-6)
tests/mocks/Unity/Application/ApplicationInfo.h (+4/-0)
tests/mocks/Unity/Application/ApplicationManager.cpp (+10/-0)
tests/mocks/Unity/Application/ApplicationManager.h (+1/-1)
tests/mocks/Unity/Application/ApplicationTestInterface.cpp (+2/-2)
tests/mocks/Unity/Application/resources/surfaces.qrc (+13/-0)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+3/-0)
tests/mocks/Utils/CMakeLists.txt (+2/-0)
tests/mocks/Utils/plugin.cpp (+2/-0)
tests/mocks/Utils/windowstatestorage.cpp (+17/-0)
tests/mocks/Utils/windowstatestorage.h (+12/-0)
tests/plugins/Unity/Launcher/launchermodeltest.cpp (+1/-0)
tests/qmltests/CMakeLists.txt (+1/-0)
tests/qmltests/Components/tst_ModeSwitchWarningDialog.qml (+75/-0)
tests/qmltests/Components/tst_ZoomableImage.qml (+1/-1)
tests/qmltests/Stages/tst_PhoneStage.qml (+0/-2)
tests/qmltests/Stages/tst_SpreadDelegate.qml (+6/-2)
tests/qmltests/Stages/tst_TabletStage.qml (+2/-2)
tests/qmltests/Stages/tst_WindowResizeArea.qml (+35/-2)
tests/qmltests/tst_OrientedShell.qml (+1/-1)
tests/qmltests/tst_Shell.qml (+179/-2)
To merge this branch: bzr merge lp:~mzanetti/unity8/move-screenshots-to-tests
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+276797@code.launchpad.net

This proposal has been superseded by a proposal from 2015-11-05.

Commit message

move screenshots out of the Dash dir

This was consuming 2.5 megs of installed size while they really are
only used for testing.

Description of the change

 * Are there any related MPs required for this MP to build/function as expected? Please list.

see prereq

 * Did you perform an exploratory manual test run of your code change and any related functionality?

yes

 * Did you make sure that your branch does not contain spurious tags?

yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?

n/a

 * If you changed the UI, has there been a design review?

n/a

To post a comment you must log in.
2024. By Michael Zanetti

fix createSession

2025. By Michael Zanetti

merge prereq

2026. By Michael Zanetti

mege trunk

2027. By Michael Zanetti

merge prereq

2028. By Michael Zanetti

strip qrc to make QImage understand it

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-10-21 11:51:38 +0000
3+++ CMakeLists.txt 2015-11-05 18:02:15 +0000
4@@ -57,7 +57,7 @@
5 find_package(Qt5Concurrent 5.2 REQUIRED)
6 find_package(Qt5Sql 5.2 REQUIRED)
7
8-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=9)
9+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=10)
10
11 # Standard install paths
12 include(GNUInstallDirs)
13
14=== modified file 'debian/control'
15--- debian/control 2015-10-21 11:51:11 +0000
16+++ debian/control 2015-11-05 18:02:15 +0000
17@@ -127,7 +127,7 @@
18 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627),
19 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
20 ubuntu-thumbnailer-impl-0,
21- unity-application-impl-9,
22+ unity-application-impl-10,
23 unity-notifications-impl-3,
24 unity-plugin-scopes | unity-scopes-impl,
25 unity-scopes-impl-7,
26@@ -173,7 +173,7 @@
27 Depends: ${misc:Depends},
28 ${shlibs:Depends},
29 Provides: unity-application-impl,
30- unity-application-impl-9,
31+ unity-application-impl-10,
32 Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
33 Description: Fake environment for running Unity 8 shell
34 Provides fake implementations of some QML modules used by Unity 8 shell
35
36=== modified file 'plugins/Utils/CMakeLists.txt'
37--- plugins/Utils/CMakeLists.txt 2015-09-29 14:46:24 +0000
38+++ plugins/Utils/CMakeLists.txt 2015-11-05 18:02:15 +0000
39@@ -10,6 +10,8 @@
40
41 set(QMLPLUGIN_SRC
42 activefocuslogger.cpp
43+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
44+ applicationsfiltermodel.cpp
45 constants.cpp
46 HomeKeyWatcher.cpp
47 inputwatcher.cpp
48
49=== added file 'plugins/Utils/applicationsfiltermodel.cpp'
50--- plugins/Utils/applicationsfiltermodel.cpp 1970-01-01 00:00:00 +0000
51+++ plugins/Utils/applicationsfiltermodel.cpp 2015-11-05 18:02:15 +0000
52@@ -0,0 +1,101 @@
53+/*
54+ * Copyright (C) 2015 Canonical, Ltd.
55+ *
56+ * This program is free software; you can redistribute it and/or modify
57+ * it under the terms of the GNU General Public License as published by
58+ * the Free Software Foundation; version 3.
59+ *
60+ * This program is distributed in the hope that it will be useful,
61+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
62+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63+ * GNU General Public License for more details.
64+ *
65+ * You should have received a copy of the GNU General Public License
66+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
67+ */
68+
69+// unity-api
70+#include <unity/shell/application/ApplicationManagerInterface.h>
71+#include <unity/shell/application/ApplicationInfoInterface.h>
72+
73+#include "applicationsfiltermodel.h"
74+
75+using namespace unity::shell::application;
76+
77+ApplicationsFilterModel::ApplicationsFilterModel(QObject *parent):
78+ QSortFilterProxyModel(parent),
79+ m_appModel(nullptr),
80+ m_filterTouchApps(false),
81+ m_filterLegacyApps(false)
82+{
83+}
84+
85+ApplicationManagerInterface *ApplicationsFilterModel::applicationsModel() const
86+{
87+ return m_appModel;
88+}
89+
90+void ApplicationsFilterModel::setApplicationsModel(ApplicationManagerInterface *applicationsModel)
91+{
92+ if (m_appModel != applicationsModel) {
93+ if (m_appModel) {
94+ disconnect(m_appModel, &ApplicationManagerInterface::countChanged, this, &ApplicationsFilterModel::countChanged);
95+ }
96+ m_appModel = applicationsModel;
97+ setSourceModel(m_appModel);
98+ Q_EMIT applicationsModelChanged();
99+ connect(m_appModel, &ApplicationManagerInterface::countChanged, this, &ApplicationsFilterModel::countChanged);
100+ }
101+}
102+
103+bool ApplicationsFilterModel::filterTouchApps() const
104+{
105+ return m_filterTouchApps;
106+}
107+
108+void ApplicationsFilterModel::setFilterTouchApps(bool filterTouchApps)
109+{
110+ if (m_filterTouchApps != filterTouchApps) {
111+ m_filterTouchApps = filterTouchApps;
112+ Q_EMIT filterTouchAppsChanged();
113+
114+ invalidateFilter();
115+ Q_EMIT countChanged();
116+ }
117+}
118+
119+bool ApplicationsFilterModel::filterLegacyApps() const
120+{
121+ return m_filterLegacyApps;
122+}
123+
124+void ApplicationsFilterModel::setFilterLegacyApps(bool filterLegacyApps)
125+{
126+ if (m_filterLegacyApps != filterLegacyApps) {
127+ m_filterLegacyApps = filterLegacyApps;
128+ Q_EMIT filterLegacyAppsChanged();
129+
130+ invalidateFilter();
131+ Q_EMIT countChanged();
132+ }
133+}
134+
135+bool ApplicationsFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
136+{
137+ Q_UNUSED(source_parent);
138+
139+ ApplicationInfoInterface *app = m_appModel->get(source_row);
140+ Q_ASSERT(app);
141+ if (m_filterLegacyApps && !app->isTouchApp()) {
142+ return false;
143+ }
144+ if (m_filterTouchApps && app->isTouchApp()) {
145+ return false;
146+ }
147+ return true;
148+}
149+
150+ApplicationInfoInterface *ApplicationsFilterModel::get(int index) const
151+{
152+ return m_appModel->get(mapToSource(this->index(index, 0)).row());
153+}
154
155=== added file 'plugins/Utils/applicationsfiltermodel.h'
156--- plugins/Utils/applicationsfiltermodel.h 1970-01-01 00:00:00 +0000
157+++ plugins/Utils/applicationsfiltermodel.h 2015-11-05 18:02:15 +0000
158@@ -0,0 +1,69 @@
159+/*
160+ * Copyright (C) 2015 Canonical, Ltd.
161+ *
162+ * This program is free software; you can redistribute it and/or modify
163+ * it under the terms of the GNU General Public License as published by
164+ * the Free Software Foundation; version 3.
165+ *
166+ * This program is distributed in the hope that it will be useful,
167+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
168+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
169+ * GNU General Public License for more details.
170+ *
171+ * You should have received a copy of the GNU General Public License
172+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
173+ */
174+
175+#ifndef APPLICATIONSFILTERMODEL_H
176+#define APPLICATIONSFILTERMODEL_H
177+
178+#include <QSortFilterProxyModel>
179+
180+namespace unity {
181+namespace shell {
182+namespace application {
183+class ApplicationManagerInterface;
184+class ApplicationInfoInterface;
185+}
186+}
187+}
188+using namespace unity::shell::application;
189+
190+class ApplicationsFilterModel: public QSortFilterProxyModel
191+{
192+ Q_OBJECT
193+
194+ Q_PROPERTY(unity::shell::application::ApplicationManagerInterface* applicationsModel READ applicationsModel WRITE setApplicationsModel NOTIFY applicationsModelChanged)
195+ Q_PROPERTY(bool filterTouchApps READ filterTouchApps WRITE setFilterTouchApps NOTIFY filterTouchAppsChanged)
196+ Q_PROPERTY(bool filterLegacyApps READ filterLegacyApps WRITE setFilterLegacyApps NOTIFY filterLegacyAppsChanged)
197+
198+ Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
199+public:
200+ ApplicationsFilterModel(QObject *parent = 0);
201+
202+ ApplicationManagerInterface* applicationsModel() const;
203+ void setApplicationsModel(ApplicationManagerInterface* applicationsModel);
204+
205+ bool filterTouchApps() const;
206+ void setFilterTouchApps(bool filterTouchApps);
207+
208+ bool filterLegacyApps() const;
209+ void setFilterLegacyApps(bool filterLegacyApps);
210+
211+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
212+
213+ Q_INVOKABLE unity::shell::application::ApplicationInfoInterface* get(int index) const;
214+
215+Q_SIGNALS:
216+ void applicationsModelChanged();
217+ void filterTouchAppsChanged();
218+ void filterLegacyAppsChanged();
219+ void countChanged();
220+
221+private:
222+ ApplicationManagerInterface* m_appModel;
223+ bool m_filterTouchApps;
224+ bool m_filterLegacyApps;
225+};
226+
227+#endif
228
229=== modified file 'plugins/Utils/plugin.cpp'
230--- plugins/Utils/plugin.cpp 2015-09-29 14:46:24 +0000
231+++ plugins/Utils/plugin.cpp 2015-11-05 18:02:15 +0000
232@@ -35,6 +35,7 @@
233 #include "windowstatestorage.h"
234 #include "constants.h"
235 #include "timezoneFormatter.h"
236+#include "applicationsfiltermodel.h"
237
238 static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
239 {
240@@ -66,6 +67,7 @@
241 qmlRegisterSingletonType<TimezoneFormatter>(uri, 0, 1, "TimezoneFormatter",
242 [](QQmlEngine*, QJSEngine*) -> QObject* { return new TimezoneFormatter; });
243 qmlRegisterType<ActiveFocusLogger>(uri, 0, 1, "ActiveFocusLogger");
244+ qmlRegisterType<ApplicationsFilterModel>(uri, 0, 1, "ApplicationsFilterModel");
245 }
246
247 void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
248
249=== modified file 'plugins/Utils/windowstatestorage.cpp'
250--- plugins/Utils/windowstatestorage.cpp 2015-09-14 09:11:08 +0000
251+++ plugins/Utils/windowstatestorage.cpp 2015-11-05 18:02:15 +0000
252@@ -47,26 +47,38 @@
253 m_db.close();
254 }
255
256+void WindowStateStorage::saveState(const QString &windowId, WindowStateStorage::WindowState state)
257+{
258+ const QString queryString = QStringLiteral("INSERT OR REPLACE INTO state (windowId, state) values ('%1', '%2');")
259+ .arg(windowId)
260+ .arg((int)state);
261+
262+ saveValue(queryString);
263+}
264+
265+WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue) const
266+{
267+ const QString queryString = QStringLiteral("SELECT * FROM state WHERE windowId = '%1';")
268+ .arg(windowId);
269+
270+ QSqlQuery query = getValue(queryString);
271+
272+ if (!query.first()) {
273+ return defaultValue;
274+ }
275+ return (WindowState)query.value("state").toInt();
276+}
277+
278 void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect)
279 {
280- QMutexLocker mutexLocker(&s_mutex);
281-
282- QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');")
283+ const QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');")
284 .arg(windowId)
285 .arg(rect.x())
286 .arg(rect.y())
287 .arg(rect.width())
288 .arg(rect.height());
289
290- QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
291- m_asyncQueries.append(future);
292-
293- QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
294- futureWatcher->setFuture(future);
295- connect(futureWatcher, &QFutureWatcher<void>::finished,
296- this,
297- [=](){ m_asyncQueries.removeAll(futureWatcher->future());
298- futureWatcher->deleteLater(); });
299+ saveValue(queryString);
300 }
301
302 void WindowStateStorage::executeAsyncQuery(const QString &queryString)
303@@ -82,20 +94,13 @@
304 }
305 }
306
307-QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue)
308+QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue) const
309 {
310- QMutexLocker l(&s_mutex);
311 QString queryString = QStringLiteral("SELECT * FROM geometry WHERE windowId = '%1';")
312 .arg(windowId);
313- QSqlQuery query;
314-
315- bool ok = query.exec(queryString);
316- if (!ok) {
317- qWarning() << "Error retrieving window state for" << windowId
318- << "Driver error:" << query.lastError().driverText()
319- << "Database error:" << query.lastError().databaseText();
320- return defaultValue;
321- }
322+
323+ QSqlQuery query = getValue(queryString);
324+
325 if (!query.first()) {
326 return defaultValue;
327 }
328@@ -114,4 +119,38 @@
329 QSqlQuery query;
330 query.exec(QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);"));
331 }
332+
333+ if (!m_db.tables().contains("state")) {
334+ QSqlQuery query;
335+ query.exec("CREATE TABLE state(windowId TEXT UNIQUE, state INTEGER);");
336+ }
337+}
338+
339+void WindowStateStorage::saveValue(const QString &queryString)
340+{
341+ QMutexLocker mutexLocker(&s_mutex);
342+
343+ QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
344+ m_asyncQueries.append(future);
345+
346+ QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
347+ futureWatcher->setFuture(future);
348+ connect(futureWatcher, &QFutureWatcher<void>::finished,
349+ this,
350+ [=](){ m_asyncQueries.removeAll(futureWatcher->future());
351+ futureWatcher->deleteLater(); });
352+}
353+
354+QSqlQuery WindowStateStorage::getValue(const QString &queryString) const
355+{
356+ QMutexLocker l(&s_mutex);
357+ QSqlQuery query;
358+
359+ bool ok = query.exec(queryString);
360+ if (!ok) {
361+ qWarning() << "Error retrieving database query:" << queryString
362+ << "Driver error:" << query.lastError().driverText()
363+ << "Database error:" << query.lastError().databaseText();
364+ }
365+ return query;
366 }
367
368=== modified file 'plugins/Utils/windowstatestorage.h'
369--- plugins/Utils/windowstatestorage.h 2015-03-13 19:01:32 +0000
370+++ plugins/Utils/windowstatestorage.h 2015-11-05 18:02:15 +0000
371@@ -22,16 +22,28 @@
372 class WindowStateStorage: public QObject
373 {
374 Q_OBJECT
375+ Q_ENUMS(WindowState)
376 public:
377+ enum WindowState {
378+ WindowStateNormal,
379+ WindowStateMaximized
380+ };
381+
382 WindowStateStorage(QObject *parent = 0);
383 virtual ~WindowStateStorage();
384
385+ Q_INVOKABLE void saveState(const QString &windowId, WindowState state);
386+ Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue) const;
387+
388 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
389- Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue);
390+ Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue) const;
391
392 private:
393 void initdb();
394
395+ void saveValue(const QString &queryString);
396+ QSqlQuery getValue(const QString &queryString) const;
397+
398 static void executeAsyncQuery(const QString &queryString);
399 static QMutex s_mutex;
400
401
402=== modified file 'qml/Components/Dialogs.qml'
403--- qml/Components/Dialogs.qml 2015-10-09 12:36:14 +0000
404+++ qml/Components/Dialogs.qml 2015-11-05 18:02:15 +0000
405@@ -1,5 +1,5 @@
406 /*
407- * Copyright (C) 2014 Canonical, Ltd.
408+ * Copyright (C) 2014-2015 Canonical, Ltd.
409 *
410 * This program is free software; you can redistribute it and/or modify
411 * it under the terms of the GNU General Public License as published by
412@@ -21,6 +21,7 @@
413 import Ubuntu.Components 1.1
414 import GlobalShortcut 1.0
415 import Unity.Platform 1.0
416+import Utils 0.1
417 import "../Greeter"
418
419 Item {
420@@ -45,6 +46,31 @@
421 d.showPowerDialog();
422 }
423
424+ onUsageScenarioChanged: {
425+ if (usageScenario != "desktop" && legacyAppsModel.count > 0 && !d.modeSwitchWarningPopup) {
426+ var comp = Qt.createComponent(Qt.resolvedUrl("ModeSwitchWarningDialog.qml"))
427+ d.modeSwitchWarningPopup = comp.createObject(root, {model: legacyAppsModel});
428+ d.modeSwitchWarningPopup.forceClose.connect(function() {
429+ while (legacyAppsModel.count > 0) {
430+ ApplicationManager.stopApplication(legacyAppsModel.get(0).appId);
431+ }
432+ d.modeSwitchWarningPopup.hide();
433+ d.modeSwitchWarningPopup.destroy();
434+ d.modeSwitchWarningPopup = null;
435+ })
436+ } else if (usageScenario == "desktop" && d.modeSwitchWarningPopup) {
437+ d.modeSwitchWarningPopup.hide();
438+ d.modeSwitchWarningPopup.destroy();
439+ d.modeSwitchWarningPopup = null;
440+ }
441+ }
442+
443+ ApplicationsFilterModel {
444+ id: legacyAppsModel
445+ applicationsModel: ApplicationManager
446+ filterTouchApps: true
447+ }
448+
449 GlobalShortcut { // reboot/shutdown dialog
450 shortcut: Qt.Key_PowerDown
451 active: Platform.isPC
452@@ -91,6 +117,8 @@
453 id: d // private stuff
454 objectName: "dialogsPrivate"
455
456+ property var modeSwitchWarningPopup: null
457+
458 function showPowerDialog() {
459 if (!dialogLoader.active) {
460 dialogLoader.sourceComponent = powerDialogComponent;
461@@ -270,5 +298,4 @@
462 unitySessionService.endSession();
463 }
464 }
465-
466 }
467
468=== added file 'qml/Components/ModeSwitchWarningDialog.qml'
469--- qml/Components/ModeSwitchWarningDialog.qml 1970-01-01 00:00:00 +0000
470+++ qml/Components/ModeSwitchWarningDialog.qml 2015-11-05 18:02:15 +0000
471@@ -0,0 +1,95 @@
472+/*
473+ * Copyright (C) 2015 Canonical, Ltd.
474+ *
475+ * This program is free software; you can redistribute it and/or modify
476+ * it under the terms of the GNU General Public License as published by
477+ * the Free Software Foundation; version 3.
478+ *
479+ * This program is distributed in the hope that it will be useful,
480+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
481+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
482+ * GNU General Public License for more details.
483+ *
484+ * You should have received a copy of the GNU General Public License
485+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
486+ */
487+
488+import QtQuick 2.4
489+import QtQuick.Layouts 1.1
490+import Ubuntu.Components 1.2
491+import Ubuntu.Components.ListItems 1.2
492+import Ubuntu.Components.Popups 1.2
493+
494+ShellDialog {
495+ id: root
496+ objectName: "modeSwitchWarningDialog"
497+
498+ property alias model: appRepeater.model
499+
500+ signal forceClose();
501+
502+ Label {
503+ text: i18n.tr("Apps may have unsaved data:")
504+ fontSize: "large"
505+ color: "#5D5D5D"
506+ }
507+
508+ Repeater {
509+ id: appRepeater
510+ RowLayout {
511+ spacing: units.gu(2)
512+ Image {
513+ Layout.preferredHeight: units.gu(2)
514+ Layout.preferredWidth: units.gu(2)
515+ source: model.icon
516+ sourceSize.width: width
517+ sourceSize.height: height
518+ }
519+ Label {
520+ Layout.fillWidth: true
521+ text: model.name
522+ color: "#888888"
523+ }
524+ }
525+ }
526+
527+ Label {
528+ text: i18n.tr("Re-dock, save your work and close these apps to continue.")
529+ wrapMode: Text.WordWrap
530+ color: "#888888"
531+ }
532+
533+ Label {
534+ text: i18n.tr("Or force close now (unsaved data will be lost).")
535+ wrapMode: Text.WordWrap
536+ color: "#888888"
537+ }
538+
539+ ThinDivider {}
540+
541+ RowLayout {
542+ Label {
543+ objectName: "reconnectLabel"
544+ Layout.fillWidth: true
545+ property bool clicked: false
546+ property string notClickedText: i18n.tr("OK, I will reconnect")
547+ property string clickedText: i18n.tr("Reconnect now!")
548+ text: clicked ? clickedText : notClickedText
549+ color: "#333333"
550+
551+ MouseArea {
552+ anchors.fill: parent
553+ onClicked: parent.clicked = true;
554+ }
555+ }
556+
557+ Button {
558+ objectName: "forceCloseButton"
559+ text: i18n.tr("Close all")
560+ color: UbuntuColors.red
561+ onClicked: {
562+ root.forceClose();
563+ }
564+ }
565+ }
566+}
567
568=== added file 'qml/Components/Orientations.qml'
569--- qml/Components/Orientations.qml 1970-01-01 00:00:00 +0000
570+++ qml/Components/Orientations.qml 2015-11-05 18:02:15 +0000
571@@ -0,0 +1,29 @@
572+/*
573+ * Copyright 2015 Canonical Ltd.
574+ *
575+ * This program is free software; you can redistribute it and/or modify
576+ * it under the terms of the GNU General Public License as published by
577+ * the Free Software Foundation; version 3.
578+ *
579+ * This program is distributed in the hope that it will be useful,
580+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
581+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
582+ * GNU General Public License for more details.
583+ *
584+ * You should have received a copy of the GNU General Public License
585+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
586+ */
587+
588+import QtQuick 2.4
589+
590+QtObject {
591+ // Just because "native" is a reserved keyword :(
592+ property int native_: Qt.PortraitOrientation
593+
594+ property int primary: Qt.PortraitOrientation
595+
596+ property int landscape: Qt.LandscapeOrientation
597+ property int invertedLandscape: Qt.InvertedLandscapeOrientation
598+ property int portrait: Qt.PortraitOrientation
599+ property int invertedPortrait: Qt.InvertedPortraitOrientation
600+}
601
602=== modified file 'qml/Components/ShellDialog.qml'
603--- qml/Components/ShellDialog.qml 2015-08-24 15:39:53 +0000
604+++ qml/Components/ShellDialog.qml 2015-11-05 18:02:15 +0000
605@@ -31,7 +31,7 @@
606 // NB: PopupBase, Dialog's superclass, will check for the existence of this property
607 property bool reparentToRootItem: false
608
609- onVisibleChanged: { if (!visible) { dialogLoader.active = false; } }
610+ onVisibleChanged: { if (!visible && dialogLoader) { dialogLoader.active = false; } }
611
612 Keys.onEscapePressed: hide()
613
614
615=== modified file 'qml/Components/WindowControlButtons.qml'
616--- qml/Components/WindowControlButtons.qml 2014-11-24 11:21:38 +0000
617+++ qml/Components/WindowControlButtons.qml 2015-11-05 18:02:15 +0000
618@@ -28,6 +28,7 @@
619 signal maximize()
620
621 Rectangle {
622+ objectName: "closeWindowButton"
623 height: parent.height; width: height; radius: height / 2
624 gradient: Gradient {
625 GradientStop { color: "#F49073"; position: 0 }
626@@ -38,6 +39,7 @@
627 MouseArea { anchors.fill: parent; onClicked: root.close() }
628 }
629 Rectangle {
630+ objectName: "minimizeWindowButton"
631 height: parent.height; width: height; radius: height / 2
632 gradient: Gradient {
633 GradientStop { color: "#92918C"; position: 0 }
634@@ -48,6 +50,7 @@
635 MouseArea { anchors.fill: parent; onClicked: root.minimize() }
636 }
637 Rectangle {
638+ objectName: "maximizeWindowButton"
639 height: parent.height; width: height; radius: height / 2
640 gradient: Gradient {
641 GradientStop { color: "#92918C"; position: 0 }
642
643=== modified file 'qml/DeviceConfiguration.qml'
644--- qml/DeviceConfiguration.qml 2015-10-05 16:43:41 +0000
645+++ qml/DeviceConfiguration.qml 2015-11-05 18:02:15 +0000
646@@ -16,79 +16,99 @@
647
648 import QtQuick 2.0
649
650-StateGroup {
651+QtObject {
652 id: root
653
654 readonly property int useNativeOrientation: -1
655
656- property int primaryOrientation: useNativeOrientation
657-
658- property int supportedOrientations: Qt.PortraitOrientation
659- | Qt.InvertedPortraitOrientation
660- | Qt.LandscapeOrientation
661- | Qt.InvertedLandscapeOrientation
662-
663- // Supported values so far:
664- // "phone", "tablet" or "desktop"
665- property string category: "phone"
666-
667- property int ignoredMice: 0
668-
669-
670- property alias name: root.state
671-
672- states: [
673- State {
674- name: "mako"
675- PropertyChanges {
676- target: root
677- supportedOrientations: Qt.PortraitOrientation
678- | Qt.LandscapeOrientation
679- | Qt.InvertedLandscapeOrientation
680- }
681- },
682- State {
683- name: "krillin"
684- PropertyChanges {
685- target: root
686- supportedOrientations: Qt.PortraitOrientation
687- | Qt.LandscapeOrientation
688- | Qt.InvertedLandscapeOrientation
689- }
690- },
691- State {
692- name: "arale"
693- PropertyChanges {
694- target: root
695- supportedOrientations: Qt.PortraitOrientation
696- | Qt.LandscapeOrientation
697- | Qt.InvertedLandscapeOrientation
698- ignoredMice: 1
699- }
700- },
701- State {
702- name: "manta"
703- PropertyChanges {
704- target: root
705- category: "tablet"
706- }
707- },
708- State {
709- name: "flo"
710- PropertyChanges {
711- target: root
712- primaryOrientation: Qt.InvertedLandscapeOrientation
713- category: "tablet"
714- }
715- },
716- State {
717- name: "desktop"
718- PropertyChanges {
719- target: root
720- category: "desktop"
721- supportedOrientations: root.useNativeOrientation
722- }
723- }
724- ]
725-
726+ // The only writable property in the API
727+ // all other properties are set according to the device name
728+ property alias name: priv.state
729+
730+ readonly property alias primaryOrientation: priv.primaryOrientation
731+ readonly property alias supportedOrientations: priv.supportedOrientations
732+ readonly property alias landscapeOrientation: priv.landscapeOrientation
733+ readonly property alias invertedLandscapeOrientation: priv.invertedLandscapeOrientation
734+ readonly property alias portraitOrientation: priv.portraitOrientation
735+ readonly property alias invertedPortraitOrientation: priv.invertedPortraitOrientation
736+
737+ readonly property alias category: priv.category
738+
739+ readonly property alias ignoredMice: priv.ignoredMice
740+
741+ readonly property var priv: StateGroup {
742+ id: priv
743+
744+ property int primaryOrientation: root.useNativeOrientation
745+
746+ property int supportedOrientations: Qt.PortraitOrientation
747+ | Qt.InvertedPortraitOrientation
748+ | Qt.LandscapeOrientation
749+ | Qt.InvertedLandscapeOrientation
750+
751+ property int landscapeOrientation: Qt.LandscapeOrientation
752+ property int invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
753+ property int portraitOrientation: Qt.PortraitOrientation
754+ property int invertedPortraitOrientation: Qt.InvertedPortraitOrientation
755+
756+ // Supported values so far:
757+ // "phone", "tablet" or "desktop"
758+ property string category: "phone"
759+
760+ property int ignoredMice: 0
761+
762+ states: [
763+ State {
764+ name: "mako"
765+ PropertyChanges {
766+ target: priv
767+ supportedOrientations: Qt.PortraitOrientation
768+ | Qt.LandscapeOrientation
769+ | Qt.InvertedLandscapeOrientation
770+ }
771+ },
772+ State {
773+ name: "krillin"
774+ PropertyChanges {
775+ target: priv
776+ supportedOrientations: Qt.PortraitOrientation
777+ | Qt.LandscapeOrientation
778+ | Qt.InvertedLandscapeOrientation
779+ }
780+ },
781+ State {
782+ name: "arale"
783+ PropertyChanges {
784+ target: priv
785+ supportedOrientations: Qt.PortraitOrientation
786+ | Qt.LandscapeOrientation
787+ | Qt.InvertedLandscapeOrientation
788+ ignoredMice: 1
789+ }
790+ },
791+ State {
792+ name: "manta"
793+ PropertyChanges {
794+ target: priv
795+ category: "tablet"
796+ }
797+ },
798+ State {
799+ name: "flo"
800+ PropertyChanges {
801+ target: priv
802+ landscapeOrientation: Qt.InvertedLandscapeOrientation
803+ primaryOrientation: Qt.InvertedLandscapeOrientation
804+ category: "tablet"
805+ }
806+ },
807+ State {
808+ name: "desktop"
809+ PropertyChanges {
810+ target: priv
811+ category: "desktop"
812+ }
813+ }
814+ ]
815+ }
816 }
817
818=== modified file 'qml/OrientedShell.qml'
819--- qml/OrientedShell.qml 2015-10-05 19:15:03 +0000
820+++ qml/OrientedShell.qml 2015-11-05 18:02:15 +0000
821@@ -32,20 +32,31 @@
822 implicitWidth: units.gu(40)
823 implicitHeight: units.gu(71)
824
825- // NB: native and primary orientations here don't map exactly to their QScreen counterparts
826- readonly property int nativeOrientation: width > height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
827-
828- readonly property int primaryOrientation:
829- deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
830- ? nativeOrientation : deviceConfiguration.primaryOrientation
831-
832 DeviceConfiguration {
833 id: deviceConfiguration
834 name: applicationArguments.deviceName
835 }
836
837-
838- // to be overwritten by tests
839+ property alias orientations: d.orientations
840+
841+ Item {
842+ id: d
843+
844+ property Orientations orientations: Orientations {
845+ id: orientations
846+ // NB: native and primary orientations here don't map exactly to their QScreen counterparts
847+ native_: root.width > root.height ? Qt.LandscapeOrientation : Qt.PortraitOrientation
848+
849+ primary: deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
850+ ? native_ : deviceConfiguration.primaryOrientation
851+
852+ landscape: deviceConfiguration.landscapeOrientation
853+ invertedLandscape: deviceConfiguration.invertedLandscapeOrientation
854+ portrait: deviceConfiguration.portraitOrientation
855+ invertedPortrait: deviceConfiguration.invertedPortraitOrientation
856+ }
857+ }
858+ // to be overwritten by tests
859 property var unity8Settings: Unity8Settings {}
860 property var oskSettings: GSettings { schema.id: "com.canonical.keyboard.maliit" }
861
862@@ -101,7 +112,7 @@
863
864 property int acceptedOrientationAngle: {
865 if (orientation & supportedOrientations) {
866- return Screen.angleBetween(nativeOrientation, orientation);
867+ return Screen.angleBetween(orientations.native_, orientation);
868 } else if (shell.orientation & supportedOrientations) {
869 // stay where we are
870 return shell.orientationAngle;
871@@ -111,16 +122,16 @@
872 // rotate to some supported orientation as we can't stay where we currently are
873 // TODO: Choose the closest to the current one
874 if (supportedOrientations & Qt.PortraitOrientation) {
875- return Screen.angleBetween(nativeOrientation, Qt.PortraitOrientation);
876+ return Screen.angleBetween(orientations.native_, Qt.PortraitOrientation);
877 } else if (supportedOrientations & Qt.LandscapeOrientation) {
878- return Screen.angleBetween(nativeOrientation, Qt.LandscapeOrientation);
879+ return Screen.angleBetween(orientations.native_, Qt.LandscapeOrientation);
880 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
881- return Screen.angleBetween(nativeOrientation, Qt.InvertedPortraitOrientation);
882+ return Screen.angleBetween(orientations.native_, Qt.InvertedPortraitOrientation);
883 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
884- return Screen.angleBetween(nativeOrientation, Qt.InvertedLandscapeOrientation);
885+ return Screen.angleBetween(orientations.native_, Qt.InvertedLandscapeOrientation);
886 } else {
887 // if all fails, fallback to primary orientation
888- return Screen.angleBetween(nativeOrientation, primaryOrientation);
889+ return Screen.angleBetween(orientations.native_, orientations.primary);
890 }
891 }
892 }
893@@ -128,19 +139,19 @@
894 function angleToOrientation(angle) {
895 switch (angle) {
896 case 0:
897- return nativeOrientation;
898+ return orientations.native_;
899 case 90:
900- return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
901+ return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedLandscapeOrientation
902 : Qt.PortraitOrientation;
903 case 180:
904- return nativeOrientation === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
905+ return orientations.native_ === Qt.PortraitOrientation ? Qt.InvertedPortraitOrientation
906 : Qt.InvertedLandscapeOrientation;
907 case 270:
908- return nativeOrientation === Qt.PortraitOrientation ? Qt.LandscapeOrientation
909+ return orientations.native_ === Qt.PortraitOrientation ? Qt.LandscapeOrientation
910 : Qt.InvertedPortraitOrientation;
911 default:
912 console.warn("angleToOrientation: Invalid orientation angle: " + angle);
913- return primaryOrientation;
914+ return orientations.primary;
915 }
916 }
917
918@@ -159,8 +170,7 @@
919 width: root.width
920 height: root.height
921 orientation: root.angleToOrientation(orientationAngle)
922- primaryOrientation: root.primaryOrientation
923- nativeOrientation: root.nativeOrientation
924+ orientations: root.orientations
925 nativeWidth: root.width
926 nativeHeight: root.height
927 mode: applicationArguments.mode
928
929=== modified file 'qml/Panel/Panel.qml'
930--- qml/Panel/Panel.qml 2015-09-29 12:48:46 +0000
931+++ qml/Panel/Panel.qml 2015-11-05 18:02:15 +0000
932@@ -28,6 +28,7 @@
933 property alias callHint: __callHint
934 property bool fullscreenMode: false
935 property real indicatorAreaShowProgress: 1.0
936+ property bool locked: false
937
938 opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
939
940@@ -136,7 +137,7 @@
941 }
942
943 shown: false
944- width: root.width - (PanelState.buttonsVisible ? windowControlButtons.width : 0)
945+ width: root.width - (windowControlButtons.visible ? windowControlButtons.width : 0)
946 minimizedPanelHeight: units.gu(3)
947 expandedPanelHeight: units.gu(7)
948 openedHeight: root.height - indicatorOrangeLine.height
949@@ -164,13 +165,14 @@
950
951 WindowControlButtons {
952 id: windowControlButtons
953+ objectName: "panelWindowControlButtons"
954 anchors {
955 left: parent.left
956 top: parent.top
957 margins: units.gu(0.7)
958 }
959 height: indicators.minimizedPanelHeight - anchors.margins * 2
960- visible: PanelState.buttonsVisible
961+ visible: PanelState.buttonsVisible && !root.locked
962 onClose: PanelState.close()
963 onMinimize: PanelState.minimize()
964 onMaximize: PanelState.maximize()
965@@ -189,7 +191,7 @@
966 id: __callHint
967 anchors {
968 top: parent.top
969- left: PanelState.buttonsVisible ? windowControlButtons.right : parent.left
970+ left: windowControlButtons.visible ? windowControlButtons.right : parent.left
971 }
972 height: indicators.minimizedPanelHeight
973 visible: active && indicators.state == "initial"
974
975=== modified file 'qml/Shell.qml'
976--- qml/Shell.qml 2015-10-16 17:11:54 +0000
977+++ qml/Shell.qml 2015-11-05 18:02:15 +0000
978@@ -49,14 +49,14 @@
979 // to be set from outside
980 property int orientationAngle: 0
981 property int orientation
982- property int primaryOrientation
983- property int nativeOrientation
984+ property Orientations orientations
985 property real nativeWidth
986 property real nativeHeight
987 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
988 property bool beingResized
989 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
990 property string mode: "full-greeter"
991+ property bool cursorVisible: false
992 function updateFocusedAppOrientation() {
993 applicationsDisplayLoader.item.updateFocusedAppOrientation();
994 }
995@@ -298,21 +298,16 @@
996 }
997 Binding {
998 target: applicationsDisplayLoader.item
999+ property: "orientations"
1000+ value: shell.orientations
1001+ }
1002+ Binding {
1003+ target: applicationsDisplayLoader.item
1004 property: "background"
1005 value: wallpaperResolver.background
1006 }
1007 Binding {
1008 target: applicationsDisplayLoader.item
1009- property: "shellPrimaryOrientation"
1010- value: shell.primaryOrientation
1011- }
1012- Binding {
1013- target: applicationsDisplayLoader.item
1014- property: "nativeOrientation"
1015- value: shell.nativeOrientation
1016- }
1017- Binding {
1018- target: applicationsDisplayLoader.item
1019 property: "nativeWidth"
1020 value: shell.nativeWidth
1021 }
1022@@ -536,6 +531,7 @@
1023
1024 fullscreenMode: (topmostApplicationIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
1025 || greeter.hasLockedApp
1026+ locked: greeter && greeter.active
1027 }
1028
1029 Launcher {
1030
1031=== added file 'qml/Stages/AbstractStage.qml'
1032--- qml/Stages/AbstractStage.qml 1970-01-01 00:00:00 +0000
1033+++ qml/Stages/AbstractStage.qml 2015-11-05 18:02:15 +0000
1034@@ -0,0 +1,63 @@
1035+/*
1036+ * Copyright (C) 2015 Canonical, Ltd.
1037+ *
1038+ * This program is free software; you can redistribute it and/or modify
1039+ * it under the terms of the GNU General Public License as published by
1040+ * the Free Software Foundation; version 3.
1041+ *
1042+ * This program is distributed in the hope that it will be useful,
1043+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1044+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1045+ * GNU General Public License for more details.
1046+ *
1047+ * You should have received a copy of the GNU General Public License
1048+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1049+ */
1050+
1051+import QtQuick 2.4
1052+import Ubuntu.Components 1.3
1053+import GSettings 1.0
1054+
1055+Rectangle {
1056+ id: root
1057+
1058+ color: "#111111"
1059+
1060+ // Controls to be set from outside
1061+ property bool altTabPressed
1062+ property url background
1063+ property bool beingResized
1064+ property int dragAreaWidth
1065+ property bool interactive
1066+ property real inverseProgress // This is the progress for left edge drags, in pixels.
1067+ property bool keepDashRunning: true
1068+ property real maximizedAppTopMargin
1069+ property real nativeHeight
1070+ property real nativeWidth
1071+ property QtObject orientations
1072+ property int shellOrientation
1073+ property int shellOrientationAngle
1074+ property bool spreadEnabled: true // If false, animations and right edge will be disabled
1075+ property bool suspended
1076+
1077+ // To be read from outside
1078+ property var mainApp: null
1079+ property int mainAppWindowOrientationAngle
1080+ property bool orientationChangesEnabled
1081+
1082+ // Shared code for use in stage implementations
1083+ GSettings {
1084+ id: lifecycleExceptions
1085+ schema.id: "com.canonical.qtmir"
1086+ }
1087+
1088+ function isExemptFromLifecycle(appId) {
1089+ var shortAppId = appId.split('_')[0];
1090+ for (var i = 0; i < lifecycleExceptions.lifecycleExemptAppids.length; i++) {
1091+ if (shortAppId === lifecycleExceptions.lifecycleExemptAppids[i]) {
1092+ return true;
1093+ }
1094+ }
1095+ return false;
1096+ }
1097+}
1098
1099=== modified file 'qml/Stages/DesktopStage.qml'
1100--- qml/Stages/DesktopStage.qml 2015-10-19 14:27:57 +0000
1101+++ qml/Stages/DesktopStage.qml 2015-11-05 18:02:15 +0000
1102@@ -22,39 +22,21 @@
1103 import Unity.Application 0.1
1104 import "../Components"
1105 import "../Components/PanelState"
1106+import "../Components"
1107 import Utils 0.1
1108 import Ubuntu.Gestures 0.1
1109
1110-Rectangle {
1111+AbstractStage {
1112 id: root
1113 anchors.fill: parent
1114
1115- // Controls to be set from outside
1116- property int dragAreaWidth // just to comply with the interface shared between stages
1117- property real maximizedAppTopMargin
1118- property bool interactive
1119- property bool spreadEnabled // just to comply with the interface shared between stages
1120- property real inverseProgress: 0 // just to comply with the interface shared between stages
1121- property int shellOrientationAngle: 0
1122- property int shellOrientation
1123- property int shellPrimaryOrientation
1124- property int nativeOrientation
1125- property bool beingResized: false
1126- property bool keepDashRunning: true
1127- property bool suspended: false
1128- property alias background: wallpaper.source
1129- property alias altTabPressed: spread.altTabPressed
1130-
1131 // functions to be called from outside
1132 function updateFocusedAppOrientation() { /* TODO */ }
1133 function updateFocusedAppOrientationAnimated() { /* TODO */}
1134
1135- // To be read from outside
1136- readonly property var mainApp: ApplicationManager.focusedApplicationId
1137+ mainApp: ApplicationManager.focusedApplicationId
1138 ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
1139 : null
1140- property int mainAppWindowOrientationAngle: 0
1141- readonly property bool orientationChangesEnabled: false
1142
1143 Connections {
1144 target: ApplicationManager
1145@@ -111,6 +93,7 @@
1146 property: "buttonsVisible"
1147 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.state === "maximized"
1148 }
1149+ Component.onDestruction: PanelState.buttonsVisible = false;
1150
1151 FocusScope {
1152 id: appContainer
1153@@ -121,6 +104,7 @@
1154 CrossFadeImage {
1155 id: wallpaper
1156 anchors.fill: parent
1157+ source: root.background
1158 sourceSize { height: root.height; width: root.width }
1159 fillMode: Image.PreserveAspectCrop
1160 }
1161@@ -140,6 +124,7 @@
1162
1163 property bool maximized: false
1164 property bool minimized: false
1165+ property bool animationsEnabled: true
1166
1167 onFocusChanged: {
1168 if (focus && ApplicationManager.focusedApplicationId !== model.appId) {
1169@@ -158,15 +143,18 @@
1170 value: ApplicationInfoInterface.RequestedRunning // Always running for now
1171 }
1172
1173- function maximize() {
1174+ function maximize(animated) {
1175+ animationsEnabled = (animated === undefined) || animated;
1176 minimized = false;
1177 maximized = true;
1178 }
1179- function minimize() {
1180+ function minimize(animated) {
1181+ animationsEnabled = (animated === undefined) || animated;
1182 maximized = false;
1183 minimized = true;
1184 }
1185- function unmaximize() {
1186+ function unmaximize(animated) {
1187+ animationsEnabled = (animated === undefined) || animated;
1188 minimized = false;
1189 maximized = false;
1190 }
1191@@ -188,6 +176,7 @@
1192 Transition {
1193 from: "maximized,minimized,normal,"
1194 to: "maximized,minimized,normal,"
1195+ enabled: appDelegate.animationsEnabled
1196 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
1197 },
1198 Transition {
1199@@ -269,5 +258,6 @@
1200 anchors.fill: parent
1201 workspace: appContainer
1202 focus: state == "altTab"
1203+ altTabPressed: root.altTabPressed
1204 }
1205 }
1206
1207=== modified file 'qml/Stages/PhoneStage.qml'
1208--- qml/Stages/PhoneStage.qml 2015-09-21 13:37:47 +0000
1209+++ qml/Stages/PhoneStage.qml 2015-11-05 18:02:15 +0000
1210@@ -22,29 +22,15 @@
1211 import Utils 0.1
1212 import "../Components"
1213
1214-Rectangle {
1215+AbstractStage {
1216 id: root
1217
1218- // Controls to be set from outside
1219- property int dragAreaWidth
1220- property real maximizedAppTopMargin
1221- property bool interactive
1222- property bool spreadEnabled: true // If false, animations and right edge will be disabled
1223- property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
1224 property QtObject applicationManager: ApplicationManager
1225 property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps
1226 property bool altTabEnabled: true
1227 property real startScale: 1.1
1228 property real endScale: 0.7
1229- property bool keepDashRunning: true
1230- property bool suspended: false
1231- property int shellOrientationAngle: 0
1232- property int shellOrientation
1233- property int shellPrimaryOrientation
1234- property int nativeOrientation
1235- property real nativeWidth
1236- property real nativeHeight
1237- property bool beingResized: false
1238+
1239 onBeingResizedChanged: {
1240 if (beingResized) {
1241 // Brace yourselves for impact!
1242@@ -56,6 +42,8 @@
1243 priv.reset();
1244 }
1245 }
1246+
1247+ // Functions to be called from outside
1248 function updateFocusedAppOrientation() {
1249 if (spreadRepeater.count > 0) {
1250 spreadRepeater.itemAt(0).matchShellOrientation();
1251@@ -71,7 +59,7 @@
1252
1253 var supportedOrientations = spreadDelegate.application.supportedOrientations;
1254 if (supportedOrientations === Qt.PrimaryOrientation) {
1255- supportedOrientations = spreadDelegate.shellPrimaryOrientation;
1256+ supportedOrientations = root.orientations.primary;
1257 }
1258
1259 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
1260@@ -85,16 +73,14 @@
1261 }
1262 }
1263
1264- // To be read from outside
1265- readonly property var mainApp: applicationManager.focusedApplicationId
1266+ mainApp: applicationManager.focusedApplicationId
1267 ? applicationManager.findApplication(applicationManager.focusedApplicationId)
1268 : null
1269
1270- property int mainAppWindowOrientationAngle: 0
1271- readonly property bool orientationChangesEnabled: priv.focusedAppOrientationChangesEnabled
1272- && !priv.focusedAppDelegateIsDislocated
1273- && !(priv.focusedAppDelegate && priv.focusedAppDelegate.xBehavior.running)
1274- && spreadView.phase === 0
1275+ orientationChangesEnabled: priv.focusedAppOrientationChangesEnabled
1276+ && !priv.focusedAppDelegateIsDislocated
1277+ && !(priv.focusedAppDelegate && priv.focusedAppDelegate.xBehavior.running)
1278+ && spreadView.phase === 0
1279
1280 // How far left the stage has been dragged
1281 readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
1282@@ -106,8 +92,6 @@
1283
1284 signal opened()
1285
1286- color: "#111111"
1287-
1288 function select(appId) {
1289 spreadView.snapTo(priv.indexOf(appId));
1290 }
1291@@ -438,16 +422,21 @@
1292 dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated
1293 focusFirstApp: root.focusFirstApp
1294
1295+ readonly property bool isDash: model.appId == "unity8-dash"
1296+
1297+ readonly property bool canSuspend: model.isTouchApp
1298+ && !isExemptFromLifecycle(model.appId)
1299+
1300 Binding {
1301 target: appDelegate.application
1302 property: "requestedState"
1303- value: (isDash && root.keepDashRunning) || (!root.suspended && appDelegate.focus)
1304- ? ApplicationInfoInterface.RequestedRunning
1305- : ApplicationInfoInterface.RequestedSuspended
1306+ value: !canSuspend
1307+ || (isDash && root.keepDashRunning)
1308+ || (!root.suspended && appDelegate.focus)
1309+ ? ApplicationInfoInterface.RequestedRunning
1310+ : ApplicationInfoInterface.RequestedSuspended
1311 }
1312
1313- readonly property bool isDash: model.appId == "unity8-dash"
1314-
1315 z: isDash && !spreadView.active ? -1 : behavioredIndex
1316
1317 x: {
1318@@ -535,11 +524,9 @@
1319 visible: (progress >= 0 && progress < 1.7)
1320 || (isDash && priv.focusedAppDelegateIsDislocated)
1321
1322-
1323 shellOrientationAngle: root.shellOrientationAngle
1324 shellOrientation: root.shellOrientation
1325- shellPrimaryOrientation: root.shellPrimaryOrientation
1326- nativeOrientation: root.nativeOrientation
1327+ orientations: root.orientations
1328
1329 onClicked: {
1330 if (root.altTabEnabled && spreadView.phase == 2) {
1331
1332=== modified file 'qml/Stages/ShimStage.qml'
1333--- qml/Stages/ShimStage.qml 2015-04-21 19:43:25 +0000
1334+++ qml/Stages/ShimStage.qml 2015-11-05 18:02:15 +0000
1335@@ -17,7 +17,7 @@
1336 import QtQuick 2.3
1337 import Ubuntu.Components 0.1
1338
1339-Rectangle {
1340+AbstractStage {
1341 id: shimStage
1342
1343 anchors.fill: parent
1344
1345=== modified file 'qml/Stages/SpreadDelegate.qml'
1346--- qml/Stages/SpreadDelegate.qml 2015-09-21 13:10:02 +0000
1347+++ qml/Stages/SpreadDelegate.qml 2015-11-05 18:02:15 +0000
1348@@ -42,8 +42,7 @@
1349 property alias application: appWindow.application
1350 property int shellOrientationAngle
1351 property int shellOrientation
1352- property int shellPrimaryOrientation
1353- property int nativeOrientation
1354+ property QtObject orientations
1355
1356 function matchShellOrientation() {
1357 if (!root.application)
1358@@ -157,7 +156,7 @@
1359 var supportedOrientations = root.application.supportedOrientations;
1360
1361 if (supportedOrientations === Qt.PrimaryOrientation) {
1362- supportedOrientations = root.shellPrimaryOrientation;
1363+ supportedOrientations = root.orientations.primary;
1364 }
1365
1366 // If it doesn't support shell's current orientation
1367@@ -166,18 +165,18 @@
1368 if (supportedOrientations & root.shellOrientation) {
1369 chosenOrientation = root.shellOrientation;
1370 } else if (supportedOrientations & Qt.PortraitOrientation) {
1371- chosenOrientation = Qt.PortraitOrientation;
1372+ chosenOrientation = root.orientations.portrait;
1373 } else if (supportedOrientations & Qt.LandscapeOrientation) {
1374- chosenOrientation = Qt.LandscapeOrientation;
1375+ chosenOrientation = root.orientations.landscape;
1376 } else if (supportedOrientations & Qt.InvertedPortraitOrientation) {
1377- chosenOrientation = Qt.InvertedPortraitOrientation;
1378+ chosenOrientation = root.orientations.invertedPortrait;
1379 } else if (supportedOrientations & Qt.InvertedLandscapeOrientation) {
1380- chosenOrientation = Qt.InvertedLandscapeOrientation;
1381+ chosenOrientation = root.orientations.invertedLandscape;
1382 } else {
1383- chosenOrientation = root.shellPrimaryOrientation;
1384+ chosenOrientation = root.orientations.primary;
1385 }
1386
1387- return Screen.angleBetween(root.nativeOrientation, chosenOrientation);
1388+ return Screen.angleBetween(root.orientations.native_, chosenOrientation);
1389 }
1390
1391 rotation: normalizeAngle(appWindowWithShadow.orientationAngle - root.shellOrientationAngle)
1392
1393=== modified file 'qml/Stages/TabletStage.qml'
1394--- qml/Stages/TabletStage.qml 2015-08-03 13:47:44 +0000
1395+++ qml/Stages/TabletStage.qml 2015-11-05 18:02:15 +0000
1396@@ -21,29 +21,12 @@
1397 import Utils 0.1
1398 import "../Components"
1399
1400-Rectangle {
1401+AbstractStage {
1402 id: root
1403 objectName: "stages"
1404 anchors.fill: parent
1405- color: "#111111"
1406-
1407- // Controls to be set from outside
1408- property int dragAreaWidth
1409- property real maximizedAppTopMargin
1410- property bool interactive
1411- property alias beingResized: spreadView.beingResized
1412-
1413- property bool spreadEnabled: true // If false, animations and right edge will be disabled
1414-
1415- property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
1416- property bool keepDashRunning: true
1417- property bool suspended: false
1418- property int shellOrientationAngle: 0
1419- property int shellOrientation
1420- property int shellPrimaryOrientation
1421- property int nativeOrientation
1422- property real nativeWidth
1423- property real nativeHeight
1424+
1425+ // Functions to be called from outside
1426 function updateFocusedAppOrientation() {
1427 var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
1428 if (mainStageAppIndex >= 0 && mainStageAppIndex < spreadRepeater.count) {
1429@@ -64,7 +47,7 @@
1430
1431 var supportedOrientations = spreadDelegate.application.supportedOrientations;
1432 if (supportedOrientations === Qt.PrimaryOrientation) {
1433- supportedOrientations = spreadDelegate.shellPrimaryOrientation;
1434+ supportedOrientations = spreadDelegate.orientations.primary;
1435 }
1436
1437 if (delta === 180 && (supportedOrientations & spreadDelegate.shellOrientation)) {
1438@@ -86,10 +69,7 @@
1439 }
1440 }
1441
1442- // To be read from outside
1443- property var mainApp: null
1444- property int mainAppWindowOrientationAngle: 0
1445- readonly property bool orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
1446+ orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
1447
1448 onWidthChanged: {
1449 spreadView.selectedIndex = -1;
1450@@ -130,7 +110,7 @@
1451 property string oldFocusedAppId: ""
1452 property bool mainAppOrientationChangesEnabled: false
1453
1454- property real landscapeHeight: root.nativeOrientation == Qt.LandscapeOrientation ?
1455+ property real landscapeHeight: root.orientations.native_ == Qt.LandscapeOrientation ?
1456 root.nativeHeight : root.nativeWidth
1457
1458 property bool shellIsLandscape: root.shellOrientation === Qt.LandscapeOrientation
1459@@ -302,7 +282,7 @@
1460 }
1461
1462 property bool animateX: true
1463- property bool beingResized: false
1464+ property bool beingResized: root.beingResized
1465 onBeingResizedChanged: {
1466 if (beingResized) {
1467 // Brace yourselves for impact!
1468@@ -629,15 +609,18 @@
1469
1470 readonly property bool isDash: model.appId == "unity8-dash"
1471
1472+ readonly property bool canSuspend: model.isTouchApp
1473+ && !isExemptFromLifecycle(model.appId)
1474+
1475 Binding {
1476 target: spreadTile.application
1477 property: "requestedState"
1478- value: (spreadTile.isDash && root.keepDashRunning)
1479- ||
1480- (!root.suspended && (model.appId == priv.mainStageAppId
1481- || model.appId == priv.sideStageAppId))
1482- ? ApplicationInfoInterface.RequestedRunning
1483- : ApplicationInfoInterface.RequestedSuspended
1484+ value: !canSuspend
1485+ || (isDash && root.keepDashRunning)
1486+ || (!root.suspended && (model.appId == priv.mainStageAppId
1487+ || model.appId == priv.sideStageAppId))
1488+ ? ApplicationInfoInterface.RequestedRunning
1489+ : ApplicationInfoInterface.RequestedSuspended
1490 }
1491
1492 // FIXME: A regular binding doesn't update any more after closing an app.
1493@@ -691,9 +674,14 @@
1494
1495 shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
1496 shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
1497- shellPrimaryOrientation: wantsMainStage ? root.shellPrimaryOrientation : Qt.PortraitOrientation
1498- nativeOrientation: wantsMainStage ? root.nativeOrientation : Qt.PortraitOrientation
1499-
1500+ orientations: Orientations {
1501+ primary: spreadTile.wantsMainStage ? root.orientations.primary : Qt.PortraitOrientation
1502+ native_: spreadTile.wantsMainStage ? root.orientations.native_ : Qt.PortraitOrientation
1503+ portrait: root.orientations.portrait
1504+ invertedPortrait: root.orientations.invertedPortrait
1505+ landscape: root.orientations.landscape
1506+ invertedLandscape: root.orientations.invertedLandscape
1507+ }
1508
1509 onClicked: {
1510 if (spreadView.phase == 2) {
1511
1512=== modified file 'qml/Stages/WindowResizeArea.qml'
1513--- qml/Stages/WindowResizeArea.qml 2015-09-29 12:48:46 +0000
1514+++ qml/Stages/WindowResizeArea.qml 2015-11-05 18:02:15 +0000
1515@@ -36,18 +36,49 @@
1516 property int minWidth: 0
1517 property int minHeight: 0
1518
1519+ QtObject {
1520+ id: priv
1521+
1522+ property int normalX: 0
1523+ property int normalY: 0
1524+ property int normalWidth: 0
1525+ property int normalHeight: 0
1526+
1527+ function updateNormalGeometry() {
1528+ if (root.target.state == "normal") {
1529+ normalX = root.target.x
1530+ normalY = root.target.y
1531+ normalWidth = root.target.width
1532+ normalHeight = root.target.height
1533+ }
1534+ }
1535+ }
1536+
1537+ Connections {
1538+ target: root.target
1539+ onXChanged: priv.updateNormalGeometry();
1540+ onYChanged: priv.updateNormalGeometry();
1541+ onWidthChanged: priv.updateNormalGeometry();
1542+ onHeightChanged: priv.updateNormalGeometry();
1543+ }
1544+
1545 Component.onCompleted: {
1546- var windowState = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
1547- if (windowState !== undefined) {
1548- target.x = windowState.x
1549- target.y = windowState.y
1550- target.width = windowState.width
1551- target.height = windowState.height
1552+ var windowGeometry = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
1553+ if (windowGeometry !== undefined) {
1554+ target.x = windowGeometry.x
1555+ target.y = windowGeometry.y
1556+ target.width = windowGeometry.width
1557+ target.height = windowGeometry.height
1558+ }
1559+ var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
1560+ if (windowState === WindowStateStorage.WindowStateMaximized) {
1561+ target.maximize(false)
1562 }
1563 }
1564
1565 Component.onDestruction: {
1566- windowStateStorage.saveGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
1567+ windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal)
1568+ windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight))
1569 }
1570
1571 QtObject {
1572
1573=== added file 'qml/graphics/applicationIcons/libreoffice@18.png'
1574Binary files qml/graphics/applicationIcons/libreoffice@18.png 1970-01-01 00:00:00 +0000 and qml/graphics/applicationIcons/libreoffice@18.png 2015-11-05 18:02:15 +0000 differ
1575=== modified file 'tests/mocks/GSettings.1.0/fake_gsettings.cpp'
1576--- tests/mocks/GSettings.1.0/fake_gsettings.cpp 2015-09-02 13:06:56 +0000
1577+++ tests/mocks/GSettings.1.0/fake_gsettings.cpp 2015-11-05 18:02:15 +0000
1578@@ -75,6 +75,19 @@
1579 }
1580 }
1581
1582+QStringList GSettingsControllerQml::lifecycleExemptAppids() const
1583+{
1584+ return m_lifecycleExemptAppids;
1585+}
1586+
1587+void GSettingsControllerQml::setLifecycleExemptAppids(const QStringList &appIds)
1588+{
1589+ if (m_lifecycleExemptAppids != appIds) {
1590+ m_lifecycleExemptAppids = appIds;
1591+ Q_EMIT lifecycleExemptAppidsChanged(m_lifecycleExemptAppids);
1592+ }
1593+}
1594+
1595 GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
1596 }
1597
1598@@ -114,6 +127,8 @@
1599 this, &GSettingsQml::usageModeChanged);
1600 connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::lockedOutTimeChanged,
1601 this, &GSettingsQml::lockedOutTimeChanged);
1602+ connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::lifecycleExemptAppidsChanged,
1603+ this, &GSettingsQml::lifecycleExemptAppidsChanged);
1604 }
1605
1606 GSettingsSchemaQml * GSettingsQml::schema() const {
1607@@ -167,3 +182,19 @@
1608 GSettingsControllerQml::instance()->setLockedOutTime(timestamp);
1609 }
1610 }
1611+
1612+QStringList GSettingsQml::lifecycleExemptAppids() const
1613+{
1614+ if (m_schema->id() == "com.canonical.qtmir") {
1615+ return GSettingsControllerQml::instance()->lifecycleExemptAppids();
1616+ } else {
1617+ return QStringList();
1618+ }
1619+}
1620+
1621+void GSettingsQml::setLifecycleExemptAppids(const QStringList &appIds)
1622+{
1623+ if (m_schema->id() == "com.canonical.qtmir") {
1624+ GSettingsControllerQml::instance()->setLifecycleExemptAppids(appIds);
1625+ }
1626+}
1627
1628=== modified file 'tests/mocks/GSettings.1.0/fake_gsettings.h'
1629--- tests/mocks/GSettings.1.0/fake_gsettings.h 2015-08-19 23:41:18 +0000
1630+++ tests/mocks/GSettings.1.0/fake_gsettings.h 2015-11-05 18:02:15 +0000
1631@@ -19,6 +19,7 @@
1632
1633 #include <QList>
1634 #include <QObject>
1635+#include <QStringList>
1636
1637 class GSettingsSchemaQml: public QObject
1638 {
1639@@ -48,6 +49,7 @@
1640 Q_PROPERTY(QString pictureUri READ pictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
1641 Q_PROPERTY(QString usageMode READ usageMode WRITE setUsageMode NOTIFY usageModeChanged)
1642 Q_PROPERTY(qint64 lockedOutTime READ lockedOutTime WRITE setLockedOutTime NOTIFY lockedOutTimeChanged)
1643+ Q_PROPERTY(QStringList lifecycleExemptAppids READ lifecycleExemptAppids WRITE setLifecycleExemptAppids NOTIFY lifecycleExemptAppidsChanged)
1644
1645 public:
1646 GSettingsQml(QObject *parent = nullptr);
1647@@ -56,16 +58,19 @@
1648 QString pictureUri() const;
1649 QString usageMode() const;
1650 qint64 lockedOutTime() const;
1651+ QStringList lifecycleExemptAppids() const;
1652
1653 void setPictureUri(const QString &str);
1654 void setUsageMode(const QString &usageMode);
1655 void setLockedOutTime(qint64 timestamp);
1656+ void setLifecycleExemptAppids(const QStringList &appIds);
1657
1658 Q_SIGNALS:
1659 void schemaChanged();
1660 void pictureUriChanged(const QString&);
1661 void usageModeChanged(const QString&);
1662 void lockedOutTimeChanged(qint64);
1663+ void lifecycleExemptAppidsChanged(const QStringList &);
1664
1665 private:
1666 GSettingsSchemaQml* m_schema;
1667@@ -90,10 +95,14 @@
1668 qint64 lockedOutTime() const;
1669 Q_INVOKABLE void setLockedOutTime(qint64 timestamp);
1670
1671+ QStringList lifecycleExemptAppids() const;
1672+ Q_INVOKABLE void setLifecycleExemptAppids(const QStringList &appIds);
1673+
1674 Q_SIGNALS:
1675 void pictureUriChanged(const QString&);
1676 void usageModeChanged(const QString&);
1677 void lockedOutTimeChanged(qint64 timestamp);
1678+ void lifecycleExemptAppidsChanged(const QStringList&);
1679
1680 private:
1681 GSettingsControllerQml();
1682@@ -101,6 +110,7 @@
1683 QString m_pictureUri;
1684 QString m_usageMode;
1685 qint64 m_lockedOutTime;
1686+ QStringList m_lifecycleExemptAppids;
1687
1688 static GSettingsControllerQml* s_controllerInstance;
1689 QList<GSettingsQml *> m_registeredGSettings;
1690
1691=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp'
1692--- tests/mocks/Unity/Application/ApplicationInfo.cpp 2015-08-31 10:25:07 +0000
1693+++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2015-11-05 18:02:15 +0000
1694@@ -41,6 +41,7 @@
1695 Qt::InvertedLandscapeOrientation)
1696 , m_rotatesWindowContents(false)
1697 , m_requestedState(RequestedRunning)
1698+ , m_isTouchApp(true)
1699 , m_manualSurfaceCreation(false)
1700 {
1701 }
1702@@ -58,6 +59,7 @@
1703 Qt::InvertedLandscapeOrientation)
1704 , m_rotatesWindowContents(false)
1705 , m_requestedState(RequestedRunning)
1706+ , m_isTouchApp(true)
1707 , m_manualSurfaceCreation(false)
1708 {
1709 }
1710@@ -99,6 +101,7 @@
1711 if (m_session) {
1712 m_session->setApplication(this);
1713 m_session->setParent(this);
1714+ m_session->setScreenshot(m_screenshotFileName);
1715 SessionManager::singleton()->registerSession(m_session);
1716 connect(m_session, &Session::surfaceChanged,
1717 this, &ApplicationInfo::onSessionSurfaceChanged);
1718@@ -123,21 +126,18 @@
1719 QString screenshotFileName;
1720
1721 if (screenshotId.endsWith(".svg")) {
1722- screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2")
1723- .arg(qmlDirectory())
1724+ screenshotFileName = QString("qrc:///Unity/Application/screenshots/%2")
1725 .arg(screenshotId);
1726 } else {
1727- screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")
1728- .arg(qmlDirectory())
1729+ screenshotFileName = QString("qrc:///Unity/Application/screenshots/%2@12.png")
1730 .arg(screenshotId);
1731 }
1732
1733 if (screenshotFileName != m_screenshotFileName) {
1734 m_screenshotFileName = screenshotFileName;
1735
1736- QUrl screenshotUrl = QString("file://%1").arg(m_screenshotFileName);
1737 if (m_session) {
1738- m_session->setScreenshot(screenshotUrl);
1739+ m_session->setScreenshot(screenshotFileName);
1740 }
1741 }
1742 }
1743@@ -245,6 +245,16 @@
1744 }
1745 }
1746
1747+bool ApplicationInfo::isTouchApp() const
1748+{
1749+ return m_isTouchApp;
1750+}
1751+
1752+void ApplicationInfo::setIsTouchApp(bool isTouchApp)
1753+{
1754+ m_isTouchApp = isTouchApp;
1755+}
1756+
1757 void ApplicationInfo::onSessionSurfaceChanged(MirSurface* surface)
1758 {
1759 if (surface != nullptr && m_state == Starting) {
1760
1761=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.h'
1762--- tests/mocks/Unity/Application/ApplicationInfo.h 2015-08-03 15:00:47 +0000
1763+++ tests/mocks/Unity/Application/ApplicationInfo.h 2015-11-05 18:02:15 +0000
1764@@ -89,6 +89,9 @@
1765 bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
1766 void setManualSurfaceCreation(bool value);
1767
1768+ bool isTouchApp() const override;
1769+ void setIsTouchApp(bool isTouchApp); // only in mock
1770+
1771 public:
1772 void setSession(Session* session);
1773 Session* session() const { return m_session; }
1774@@ -121,6 +124,7 @@
1775 Qt::ScreenOrientations m_supportedOrientations;
1776 bool m_rotatesWindowContents;
1777 RequestedState m_requestedState;
1778+ bool m_isTouchApp;
1779
1780 bool m_manualSurfaceCreation;
1781 };
1782
1783=== modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp'
1784--- tests/mocks/Unity/Application/ApplicationManager.cpp 2015-08-03 13:47:44 +0000
1785+++ tests/mocks/Unity/Application/ApplicationManager.cpp 2015-11-05 18:02:15 +0000
1786@@ -105,6 +105,8 @@
1787 return app->state();
1788 case RoleFocused:
1789 return app->focused();
1790+ case RoleIsTouchApp:
1791+ return app->isTouchApp();
1792 case RoleSession:
1793 return QVariant::fromValue(app->session());
1794 case RoleFullscreen:
1795@@ -458,6 +460,14 @@
1796 application->setName("YouTube");
1797 application->setIconId("youtube");
1798 m_availableApplications.append(application);
1799+
1800+ application = new ApplicationInfo(this);
1801+ application->setAppId("libreoffice");
1802+ application->setName("LibreOffice");
1803+ application->setIconId("libreoffice");
1804+ application->setScreenshotId("libreoffice");
1805+ application->setIsTouchApp(false);
1806+ m_availableApplications.append(application);
1807 }
1808
1809
1810
1811=== modified file 'tests/mocks/Unity/Application/ApplicationManager.h'
1812--- tests/mocks/Unity/Application/ApplicationManager.h 2015-06-19 18:19:33 +0000
1813+++ tests/mocks/Unity/Application/ApplicationManager.h 2015-11-05 18:02:15 +0000
1814@@ -43,7 +43,7 @@
1815 static ApplicationManager *singleton();
1816
1817 enum MoreRoles {
1818- RoleSession = RoleFocused+1,
1819+ RoleSession = RoleIsTouchApp+1,
1820 RoleFullscreen,
1821 };
1822 enum Flag {
1823
1824=== modified file 'tests/mocks/Unity/Application/ApplicationTestInterface.cpp'
1825--- tests/mocks/Unity/Application/ApplicationTestInterface.cpp 2015-08-03 15:00:47 +0000
1826+++ tests/mocks/Unity/Application/ApplicationTestInterface.cpp 2015-11-05 18:02:15 +0000
1827@@ -40,7 +40,7 @@
1828 {
1829 if (!existingSession) return nullptr;
1830
1831- QUrl screenshotUrl = QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png")
1832+ QUrl screenshotUrl = QString("qrc:///Unity/Application/screenshots/%2@12.png")
1833 .arg(qmlDirectory())
1834 .arg(surfaceImage);
1835
1836@@ -90,7 +90,7 @@
1837 return 0;
1838 }
1839
1840- QUrl screenshotUrl = QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png")
1841+ QUrl screenshotUrl = QString("qrc:///Unity/Application/screenshots/%2@12.png")
1842 .arg(qmlDirectory())
1843 .arg(surfaceImage);
1844
1845
1846=== renamed directory 'qml/Dash/graphics/phone/screenshots' => 'tests/mocks/Unity/Application/resources/screenshots'
1847=== added file 'tests/mocks/Unity/Application/resources/screenshots/libreoffice@12.png'
1848Binary files tests/mocks/Unity/Application/resources/screenshots/libreoffice@12.png 1970-01-01 00:00:00 +0000 and tests/mocks/Unity/Application/resources/screenshots/libreoffice@12.png 2015-11-05 18:02:15 +0000 differ
1849=== modified file 'tests/mocks/Unity/Application/resources/surfaces.qrc'
1850--- tests/mocks/Unity/Application/resources/surfaces.qrc 2015-04-30 20:46:41 +0000
1851+++ tests/mocks/Unity/Application/resources/surfaces.qrc 2015-11-05 18:02:15 +0000
1852@@ -3,5 +3,18 @@
1853 <file>VirtualKeyboard.qml</file>
1854 <file>MirSurfaceItem.qml</file>
1855 <file>vkb_portrait.png</file>
1856+ <file>screenshots/browser@12.png</file>
1857+ <file>screenshots/camera@12.png</file>
1858+ <file>screenshots/dialer@12.png</file>
1859+ <file>screenshots/facebook@12.png</file>
1860+ <file>screenshots/gallery@12.png</file>
1861+ <file>screenshots/gmail-webapp.svg</file>
1862+ <file>screenshots/map@12.png</file>
1863+ <file>screenshots/music@12.png</file>
1864+ <file>screenshots/twitter@12.png</file>
1865+ <file>screenshots/ubuntu-weather-app.svg</file>
1866+ <file>screenshots/unity8-dash@12.png</file>
1867+ <file>screenshots/vkb_portrait.png</file>
1868+ <file>screenshots/libreoffice@12.png</file>
1869 </qresource>
1870 </RCC>
1871
1872=== modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp'
1873--- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-08-12 08:40:47 +0000
1874+++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-11-05 18:02:15 +0000
1875@@ -75,6 +75,9 @@
1876 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
1877 item->setPinned(true);
1878 m_list.append(item);
1879+ item = new MockLauncherItem("libreoffice", "/usr/share/applications/libreoffice.desktop","Libre Office", "libreoffice", this);
1880+ item->setPinned(true);
1881+ m_list.append(item);
1882 }
1883
1884 MockLauncherModel::~MockLauncherModel()
1885
1886=== modified file 'tests/mocks/Utils/CMakeLists.txt'
1887--- tests/mocks/Utils/CMakeLists.txt 2015-09-29 14:46:24 +0000
1888+++ tests/mocks/Utils/CMakeLists.txt 2015-11-05 18:02:15 +0000
1889@@ -18,6 +18,8 @@
1890 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
1891 ${CMAKE_SOURCE_DIR}/plugins/Utils/easingcurve.cpp
1892 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputwatcher.cpp
1893+ ${CMAKE_SOURCE_DIR}/plugins/Utils/applicationsfiltermodel.cpp
1894+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
1895 constants.cpp
1896 plugin.cpp
1897 windowstatestorage.cpp
1898
1899=== modified file 'tests/mocks/Utils/plugin.cpp'
1900--- tests/mocks/Utils/plugin.cpp 2015-09-29 14:46:24 +0000
1901+++ tests/mocks/Utils/plugin.cpp 2015-11-05 18:02:15 +0000
1902@@ -35,6 +35,7 @@
1903 #include <windowkeysfilter.h>
1904 #include <windowscreenshotprovider.h>
1905 #include <easingcurve.h>
1906+#include <applicationsfiltermodel.h>
1907
1908 static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
1909 {
1910@@ -63,6 +64,7 @@
1911 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
1912 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
1913 qmlRegisterType<ActiveFocusLogger>(uri, 0, 1, "ActiveFocusLogger");
1914+ qmlRegisterType<ApplicationsFilterModel>(uri, 0, 1, "ApplicationsFilterModel");
1915 }
1916
1917 void FakeUtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
1918
1919=== modified file 'tests/mocks/Utils/windowstatestorage.cpp'
1920--- tests/mocks/Utils/windowstatestorage.cpp 2015-08-24 15:39:53 +0000
1921+++ tests/mocks/Utils/windowstatestorage.cpp 2015-11-05 18:02:15 +0000
1922@@ -44,3 +44,20 @@
1923 if (!m_geometry.contains(windowId)) return defaultValue;
1924 return m_geometry.value(windowId).toRect();
1925 }
1926+
1927+void WindowStateStorage::clear()
1928+{
1929+ m_state.clear();
1930+ m_geometry.clear();
1931+}
1932+
1933+void WindowStateStorage::saveState(const QString &windowId, WindowState state)
1934+{
1935+ m_state[windowId] = state;
1936+}
1937+
1938+WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue)
1939+{
1940+ if (!m_state.contains(windowId)) return defaultValue;
1941+ return m_state.value(windowId);
1942+}
1943
1944=== modified file 'tests/mocks/Utils/windowstatestorage.h'
1945--- tests/mocks/Utils/windowstatestorage.h 2015-08-24 15:39:53 +0000
1946+++ tests/mocks/Utils/windowstatestorage.h 2015-11-05 18:02:15 +0000
1947@@ -22,12 +22,23 @@
1948 {
1949 Q_OBJECT
1950 Q_PROPERTY(QVariantMap geometry READ geometry WRITE setGeometry NOTIFY geometryChanged)
1951+ Q_ENUMS(WindowState)
1952 public:
1953+ enum WindowState {
1954+ WindowStateNormal,
1955+ WindowStateMaximized
1956+ };
1957 WindowStateStorage(QObject *parent = 0);
1958
1959+ Q_INVOKABLE void saveState(const QString &windowId, WindowState state);
1960+ Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue);
1961+
1962 Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
1963 Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue);
1964
1965+ // Only in the mock, to easily restore a fresh state
1966+ Q_INVOKABLE void clear();
1967+
1968 Q_SIGNALS:
1969 void geometryChanged(const QVariantMap& geometry);
1970
1971@@ -35,5 +46,6 @@
1972 void setGeometry(const QVariantMap& geometry);
1973 QVariantMap geometry() const;
1974
1975+ QHash<QString, WindowState> m_state;
1976 QVariantMap m_geometry;
1977 };
1978
1979=== modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp'
1980--- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-08-19 14:24:07 +0000
1981+++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-11-05 18:02:15 +0000
1982@@ -57,6 +57,7 @@
1983 QColor splashColorFooter() const override { return QColor(0,0,0,0); }
1984 Qt::ScreenOrientations supportedOrientations() const override { return Qt::PortraitOrientation; }
1985 bool rotatesWindowContents() const override { return false; }
1986+ bool isTouchApp() const override { return true; }
1987
1988 // Methods used for mocking (not in the interface)
1989 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
1990
1991=== modified file 'tests/qmltests/CMakeLists.txt'
1992--- tests/qmltests/CMakeLists.txt 2015-10-20 08:10:03 +0000
1993+++ tests/qmltests/CMakeLists.txt 2015-11-05 18:02:15 +0000
1994@@ -11,6 +11,7 @@
1995 add_unity8_qmltest(Components DraggingArea)
1996 add_unity8_qmltest(Components LazyImage)
1997 add_unity8_qmltest(Components Lockscreen)
1998+add_unity8_qmltest(Components ModeSwitchWarningDialog)
1999 add_unity8_qmlunittest(Components PhysicalKeysMapper)
2000 add_unity8_qmltest(Components Rating)
2001 add_unity8_qmltest(Components ResponsiveGridView)
2002
2003=== added file 'tests/qmltests/Components/tst_ModeSwitchWarningDialog.qml'
2004--- tests/qmltests/Components/tst_ModeSwitchWarningDialog.qml 1970-01-01 00:00:00 +0000
2005+++ tests/qmltests/Components/tst_ModeSwitchWarningDialog.qml 2015-11-05 18:02:15 +0000
2006@@ -0,0 +1,75 @@
2007+/*
2008+ * Copyright 2015 Canonical Ltd.
2009+ *
2010+ * This program is free software; you can redistribute it and/or modify
2011+ * it under the terms of the GNU General Public License as published by
2012+ * the Free Software Foundation; version 3.
2013+ *
2014+ * This program is distributed in the hope that it will be useful,
2015+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2016+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2017+ * GNU General Public License for more details.
2018+ *
2019+ * You should have received a copy of the GNU General Public License
2020+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2021+ */
2022+
2023+import QtQuick 2.0
2024+import QtTest 1.0
2025+import "../../../qml/Components"
2026+import Unity.Test 0.1 as UT
2027+import Ubuntu.Components 1.2
2028+import Ubuntu.Components.Popups 1.2
2029+
2030+Rectangle {
2031+ id: root
2032+ width: units.gu(40)
2033+ height: units.gu(70)
2034+ color: "lightgrey"
2035+
2036+ ListModel {
2037+ id: fakeModel
2038+ ListElement { icon: "../graphics/applicationIcons/facebook.png"; name: "Facebook" }
2039+ ListElement { icon: "../graphics/applicationIcons/gmail.png"; name: "Mail" }
2040+ }
2041+
2042+ function openWarning() {
2043+ return PopupUtils.open(Qt.resolvedUrl("../../../qml/Components/ModeSwitchWarningDialog.qml"), root, { model: fakeModel });
2044+ }
2045+
2046+ Button {
2047+ anchors.centerIn: parent
2048+ text: "trigger warning"
2049+ onClicked: {
2050+ openWarning();
2051+ }
2052+ }
2053+
2054+ SignalSpy {
2055+ id: spy
2056+ signalName: "forceClose"
2057+ }
2058+
2059+ UT.UnityTestCase {
2060+ name: "ModeSwitchWarning"
2061+ when: windowShown
2062+
2063+ function test_labelChangesOnClick() {
2064+ var popup = openWarning();
2065+ var reconnectLabel = findChild(popup, "reconnectLabel");
2066+ tryCompare(reconnectLabel, "text", reconnectLabel.notClickedText)
2067+ mouseClick(reconnectLabel, reconnectLabel.width / 2, reconnectLabel.height / 2)
2068+ tryCompare(reconnectLabel, "text", reconnectLabel.clickedText)
2069+ }
2070+
2071+ function test_closeButtonEmitsSignal() {
2072+ var popup = openWarning();
2073+ spy.target = popup;
2074+ spy.clear();
2075+ var closeButton = findChild(popup, "forceCloseButton");
2076+ mouseClick(closeButton, closeButton.width / 2, closeButton.height / 2)
2077+ tryCompare(spy, "count", 1)
2078+
2079+ }
2080+ }
2081+}
2082
2083=== modified file 'tests/qmltests/Components/tst_ZoomableImage.qml'
2084--- tests/qmltests/Components/tst_ZoomableImage.qml 2015-03-18 14:34:18 +0000
2085+++ tests/qmltests/Components/tst_ZoomableImage.qml 2015-11-05 18:02:15 +0000
2086@@ -36,7 +36,7 @@
2087 }
2088
2089 property var widgetData2: {
2090- "source": "../../../qml/Dash/graphics/phone/screenshots/gallery@12.png",
2091+ "source": "../../mocks/Unity/Application/resources/screenshots/gallery@12.png",
2092 "zoomable": true
2093 }
2094
2095
2096=== modified file 'tests/qmltests/Stages/tst_PhoneStage.qml'
2097--- tests/qmltests/Stages/tst_PhoneStage.qml 2015-08-12 15:08:09 +0000
2098+++ tests/qmltests/Stages/tst_PhoneStage.qml 2015-11-05 18:02:15 +0000
2099@@ -34,8 +34,6 @@
2100 maximizedAppTopMargin: units.gu(3) + units.dp(2)
2101 interactive: true
2102 shellOrientation: Qt.PortraitOrientation
2103- shellPrimaryOrientation: Qt.PortraitOrientation
2104- nativeOrientation: Qt.PortraitOrientation
2105 }
2106
2107 Binding {
2108
2109=== modified file 'tests/qmltests/Stages/tst_SpreadDelegate.qml'
2110--- tests/qmltests/Stages/tst_SpreadDelegate.qml 2015-03-06 04:44:11 +0000
2111+++ tests/qmltests/Stages/tst_SpreadDelegate.qml 2015-11-05 18:02:15 +0000
2112@@ -18,6 +18,7 @@
2113 import QtTest 1.0
2114 import Unity.Test 0.1 as UT
2115 import ".."
2116+import "../../../qml/Components"
2117 import "../../../qml/Stages"
2118 import Ubuntu.Components 0.1
2119 import Ubuntu.Components.ListItems 1.0 as ListItem
2120@@ -73,8 +74,11 @@
2121 return Qt.LandscapeOrientation;
2122 }
2123 }
2124- shellPrimaryOrientation: Qt.PortraitOrientation
2125- nativeOrientation: Qt.PortraitOrientation
2126+
2127+ orientations: Orientations {
2128+ // the default values will do
2129+ }
2130+
2131 maximizedAppTopMargin: units.gu(3)
2132 Component.onDestruction: {
2133 spreadDelegateLoader.itemDestroyed = true;
2134
2135=== modified file 'tests/qmltests/Stages/tst_TabletStage.qml'
2136--- tests/qmltests/Stages/tst_TabletStage.qml 2015-09-02 14:26:43 +0000
2137+++ tests/qmltests/Stages/tst_TabletStage.qml 2015-11-05 18:02:15 +0000
2138@@ -22,6 +22,7 @@
2139 import Unity.Test 0.1
2140
2141 import "../../../qml/Stages"
2142+import "../../../qml/Components"
2143
2144 Rectangle {
2145 id: root
2146@@ -50,10 +51,9 @@
2147 maximizedAppTopMargin: units.gu(3) + units.dp(2)
2148 interactive: true
2149 shellOrientation: Qt.LandscapeOrientation
2150- shellPrimaryOrientation: Qt.LandscapeOrientation
2151- nativeOrientation: Qt.LandscapeOrientation
2152 nativeWidth: width
2153 nativeHeight: height
2154+ orientations: Orientations{} // Defaults are fine for testing
2155 focus: true
2156 }
2157 }
2158
2159=== modified file 'tests/qmltests/Stages/tst_WindowResizeArea.qml'
2160--- tests/qmltests/Stages/tst_WindowResizeArea.qml 2015-10-08 14:27:12 +0000
2161+++ tests/qmltests/Stages/tst_WindowResizeArea.qml 2015-11-05 18:02:15 +0000
2162@@ -44,8 +44,11 @@
2163 width: units.gu(20)
2164 property int windowHeight: height
2165 property int windowWidth: width
2166- onWindowHeightChanged: height = windowHeight
2167- onWindowWidthChanged: width = windowWidth
2168+ state: "normal"
2169+
2170+ function maximize() {
2171+ state = "maximized"
2172+ }
2173
2174 WindowResizeArea {
2175 id: windowResizeArea
2176@@ -195,5 +198,35 @@
2177 tryCompare(fakeWindow, "width", initialWindowWidth);
2178 tryCompare(fakeWindow, "height", initialWindowHeight);
2179 }
2180+
2181+ function test_saveRestoreMaximized() {
2182+ var initialWindowX = fakeWindow.x;
2183+ var initialWindowY = fakeWindow.y;
2184+
2185+ var moveDelta = units.gu(5);
2186+
2187+ fakeWindow.x = initialWindowX + moveDelta
2188+ fakeWindow.y = initialWindowY + moveDelta
2189+
2190+ // Now change the state to maximized. The window should not keep updating the stored values
2191+ fakeWindow.state = "maximized"
2192+ fakeWindow.x = 31415 // 0 is too risky to pass the test even when broken
2193+ fakeWindow.y = 31415
2194+
2195+ // This will destroy the window and recreate it
2196+ windowLoader.active = false;
2197+ waitForRendering(root);
2198+ windowLoader.active = true;
2199+
2200+ // Make sure it's again where we left it in normal state before destroying
2201+ tryCompare(fakeWindow, "x", initialWindowX + moveDelta)
2202+ tryCompare(fakeWindow, "y", initialWindowX + moveDelta)
2203+
2204+ // Make sure maximize() has been called after restoring
2205+ tryCompare(fakeWindow, "state", "maximized")
2206+
2207+ // clean up
2208+ fakeWindow.state = "normal"
2209+ }
2210 }
2211 }
2212
2213=== modified file 'tests/qmltests/tst_OrientedShell.qml'
2214--- tests/qmltests/tst_OrientedShell.qml 2015-10-05 22:04:32 +0000
2215+++ tests/qmltests/tst_OrientedShell.qml 2015-11-05 18:02:15 +0000
2216@@ -840,7 +840,7 @@
2217 // shell should remain in its primery orientation as the app in the main stage
2218 // is the one that dictates its orientation. In this case it's unity8-dash
2219 // which supports only primary orientation
2220- compare(shell.orientation, orientedShell.primaryOrientation);
2221+ compare(shell.orientation, orientedShell.orientations.primary);
2222 }
2223
2224 function test_sideStageAppsRemainPortraitInSpread_data() {
2225
2226=== modified file 'tests/qmltests/tst_Shell.qml'
2227--- tests/qmltests/tst_Shell.qml 2015-10-20 08:10:03 +0000
2228+++ tests/qmltests/tst_Shell.qml 2015-11-05 18:02:15 +0000
2229@@ -29,8 +29,11 @@
2230 import Unity.Test 0.1
2231 import Powerd 0.1
2232 import Wizard 0.1 as Wizard
2233+import Utils 0.1
2234
2235 import "../../qml"
2236+import "../../qml/Components"
2237+import "../../qml/Components/PanelState"
2238 import "Stages"
2239
2240 Rectangle {
2241@@ -97,8 +100,7 @@
2242 id: __shell
2243 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
2244 orientation: Qt.PortraitOrientation
2245- primaryOrientation: Qt.PortraitOrientation
2246- nativeOrientation: Qt.PortraitOrientation
2247+ orientations: Orientations{} // Defaults are fine for testing
2248 Component.onDestruction: {
2249 shellLoader.itemDestroyed = true;
2250 }
2251@@ -302,6 +304,7 @@
2252 mouseEmulation.checked = true;
2253 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
2254 tearDown();
2255+ WindowStateStorage.clear();
2256 }
2257
2258 function loadShell(formFactor) {
2259@@ -377,6 +380,8 @@
2260 LightDM.Greeter.authenticate(""); // reset greeter
2261
2262 sessionSpy.clear();
2263+
2264+ GSettingsController.setLifecycleExemptAppids([]);
2265 }
2266
2267 function killApps() {
2268@@ -1707,5 +1712,177 @@
2269
2270 keyRelease(Qt.Key_Control);
2271 }
2272+
2273+ // regression test for http://pad.lv/1443319
2274+ function test_closeMaximizedAndRestart() {
2275+ loadDesktopShellWithApps();
2276+
2277+ var appRepeater = findChild(shell, "appRepeater")
2278+ var appId = ApplicationManager.get(0).appId;
2279+ var appDelegate = appRepeater.itemAt(0);
2280+ var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
2281+
2282+ wait(5000)
2283+ tryCompare(appDelegate, "state", "normal");
2284+ tryCompare(PanelState, "buttonsVisible", false)
2285+
2286+ wait(5000)
2287+ mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2);
2288+ tryCompare(appDelegate, "state", "maximized");
2289+ tryCompare(PanelState, "buttonsVisible", true)
2290+
2291+ ApplicationManager.stopApplication(appId);
2292+ tryCompare(PanelState, "buttonsVisible", false)
2293+
2294+ ApplicationManager.startApplication(appId);
2295+ tryCompare(PanelState, "buttonsVisible", true)
2296+ }
2297+
2298+ // bug http://pad.lv/1431566
2299+ function test_switchToStagedHidesPanelButtons() {
2300+ loadDesktopShellWithApps();
2301+ var appRepeater = findChild(shell, "appRepeater")
2302+ var appId = ApplicationManager.get(0).appId;
2303+ var appDelegate = appRepeater.itemAt(0);
2304+ var panelButtons = findChild(shell, "panelWindowControlButtons")
2305+
2306+ tryCompare(appDelegate, "state", "normal");
2307+ tryCompare(panelButtons, "visible", false);
2308+
2309+ appDelegate.maximize(false);
2310+ tryCompare(panelButtons, "visible", true);
2311+
2312+ shell.usageScenario = "phone";
2313+ waitForRendering(shell);
2314+ tryCompare(panelButtons, "visible", false);
2315+
2316+ shell.usageScenario = "desktop";
2317+ waitForRendering(shell);
2318+ tryCompare(panelButtons, "visible", true);
2319+ }
2320+
2321+ function test_lockingGreeterHidesPanelButtons() {
2322+ loadDesktopShellWithApps();
2323+ var appRepeater = findChild(shell, "appRepeater")
2324+ var appId = ApplicationManager.get(0).appId;
2325+ var appDelegate = appRepeater.itemAt(0);
2326+ var panelButtons = findChild(shell, "panelWindowControlButtons")
2327+
2328+ tryCompare(appDelegate, "state", "normal");
2329+ tryCompare(panelButtons, "visible", false);
2330+
2331+ appDelegate.maximize(false);
2332+ tryCompare(panelButtons, "visible", true);
2333+
2334+ LightDM.Greeter.showGreeter();
2335+ waitForRendering(shell);
2336+ tryCompare(panelButtons, "visible", false);
2337+
2338+ LightDM.Greeter.hideGreeter();
2339+ waitForRendering(shell);
2340+ tryCompare(panelButtons, "visible", true);
2341+ }
2342+
2343+ function test_lifecyclePolicyForNonTouchApp_data() {
2344+ return [
2345+ {tag: "phone", formFactor: "phone", usageScenario: "phone"},
2346+ {tag: "tablet", formFactor: "tablet", usageScenario: "tablet"}
2347+ ]
2348+ }
2349+
2350+ function test_lifecyclePolicyForNonTouchApp(data) {
2351+ loadShell(data.formFactor);
2352+ shell.usageScenario = data.usageScenario;
2353+
2354+ var app1 = ApplicationManager.startApplication("libreoffice");
2355+ waitUntilAppWindowIsFullyLoaded(app1);
2356+ var app2 = ApplicationManager.startApplication("dialer-app");
2357+ waitUntilAppWindowIsFullyLoaded(app2);
2358+
2359+ // Make sure app1 is unfocused but still running
2360+ compare(app1.session.surface.activeFocus, false);
2361+ compare(app1.isTouchApp, false); // sanity check our mock, which sets this for us
2362+ compare(app1.requestedState, ApplicationInfoInterface.RequestedRunning);
2363+ }
2364+
2365+ function test_lifecyclePolicyExemption_data() {
2366+ return [
2367+ {tag: "phone", formFactor: "phone", usageScenario: "phone", suspendsApps: true},
2368+ {tag: "tablet", formFactor: "tablet", usageScenario: "tablet", suspendsApps: true}
2369+ ]
2370+ }
2371+
2372+ function test_lifecyclePolicyExemption(data) {
2373+ loadShell(data.formFactor);
2374+ shell.usageScenario = data.usageScenario;
2375+
2376+ GSettingsController.setLifecycleExemptAppids(["webbrowser-app"]);
2377+
2378+ var app1 = ApplicationManager.startApplication("webbrowser-app");
2379+ waitUntilAppWindowIsFullyLoaded(app1);
2380+ var app2 = ApplicationManager.startApplication("dialer-app");
2381+ waitUntilAppWindowIsFullyLoaded(app2);
2382+
2383+ // Make sure app1 is unfocused but still running
2384+ compare(app1.session.surface.activeFocus, false);
2385+ compare(app1.requestedState, ApplicationInfoInterface.RequestedRunning);
2386+ }
2387+
2388+ function test_switchToStagedForcesLegacyAppClosing_data() {
2389+ return [
2390+ {tag: "forceClose", replug: false },
2391+ {tag: "replug", replug: true }
2392+ ];
2393+ }
2394+
2395+ function test_switchToStagedForcesLegacyAppClosing(data) {
2396+ loadShell("desktop")
2397+ shell.usageScenario = "desktop"
2398+ waitForRendering(shell);
2399+
2400+ ApplicationManager.startApplication("camera-app")
2401+
2402+ shell.usageScenario = "phone"
2403+ waitForRendering(shell);
2404+
2405+ // No legacy app running yet... Popup must *not* show.
2406+ var popup = findChild(root, "modeSwitchWarningDialog");
2407+ compare(popup, null);
2408+
2409+ shell.usageScenario = "desktop"
2410+ waitForRendering(shell);
2411+
2412+ // Now start a legacy app
2413+ ApplicationManager.startApplication("libreoffice")
2414+
2415+ shell.usageScenario = "phone"
2416+ waitForRendering(shell);
2417+
2418+ // The popup must appear now
2419+ popup = findChild(root, "modeSwitchWarningDialog");
2420+ compare(popup !== null, true);
2421+
2422+ if (data.replug) {
2423+ shell.usageScenario = "desktop"
2424+ waitForRendering(shell);
2425+
2426+ } else {
2427+ var forceCloseButton = findChild(popup, "forceCloseButton");
2428+ mouseClick(forceCloseButton, forceCloseButton.width / 2, forceCloseButton.height / 2);
2429+ waitForRendering(root);
2430+ }
2431+
2432+ // Popup must be gone now
2433+ popup = findChild(root, "modeSwitchWarningDialog");
2434+ compare(popup === null, true);
2435+
2436+ if (data.replug) {
2437+ // Libreoffice must still be running
2438+ compare(ApplicationManager.findApplication("libreoffice") !== null, true);
2439+ } else {
2440+ // Libreoffice must be gone now
2441+ compare(ApplicationManager.findApplication("libreoffice") === null, true);
2442+ }
2443+ }
2444 }
2445 }

Subscribers

People subscribed via source and target branches