on xenial help sign in
merge lp:~mzanetti/unity8/alerting-pips
commitd8e6e9d71c37c84b6303bbd1740fce3bd5b39bff authorLukáš Tinkl <lukas.tinkl@canonical.com> dateFri 17 Jun 2016, 12:42 (10 years ago) parent4e9369f35ade0a
30 files changed+292−306
CMakeLists.txt+1−1 debian/control+1−1 plugins/Greeter/Unity/Launcher/CMakeLists.txt+1−1 plugins/Greeter/Unity/Launcher/launcheritem.cpp+14 plugins/Greeter/Unity/Launcher/launcheritem.h+3−1 plugins/Greeter/Unity/Launcher/launchermodelas.cpp+2−7 plugins/Greeter/Unity/Launcher/launchermodelas.h−1 plugins/Unity/Launcher/CMakeLists.txt+3−1 plugins/Unity/Launcher/Launcher.qmltypes−182 plugins/Unity/Launcher/launcheritem.cpp+14−9 plugins/Unity/Launcher/launcheritem.h+3 plugins/Unity/Launcher/launchermodel.cpp+58−26 plugins/Unity/Launcher/launchermodel.h+1−1 qml/Launcher/LauncherDelegate.qml+4−8 qml/Launcher/LauncherPanel.qml+2 qml/Stages/ApplicationWindow.qml+25−9 tests/mocks/Unity/Application/ApplicationInfo.cpp+29−27 tests/mocks/Unity/Application/ApplicationInfo.h+5−4 tests/mocks/Unity/Application/MirSurfaceListModel.cpp+13−3 tests/mocks/Unity/Application/MirSurfaceListModel.h+1 tests/mocks/Unity/Launcher/CMakeLists.txt+1−1 tests/mocks/Unity/Launcher/MockLauncherItem.cpp+14 tests/mocks/Unity/Launcher/MockLauncherItem.h+3 tests/mocks/Unity/Launcher/MockLauncherModel.cpp+5 tests/mocks/Unity/Launcher/MockLauncherModel.h+1−1 tests/plugins/Unity/Launcher/CMakeLists.txt+1−1 tests/plugins/Unity/Launcher/launchermodeltest.cpp+22−2 tests/qmltests/Launcher/tst_Launcher.qml+25−9 tests/qmltests/Stages/ApplicationCheckBox.qml+1−1 tests/qmltests/Stages/tst_ApplicationWindow.qml+39−9
CMakeLists.txt+1−1
@@ -57,7 +57,7 @@ find_package(Qt5DBus 5.4 REQUIRED)
5757find_package(Qt5Concurrent 5.4 REQUIRED)
5858find_package(Qt5Sql 5.4 REQUIRED)
5959
60−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=17)
60+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=18)
6161pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
6262pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
6363pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
debian/control+1−1
@@ -33,7 +33,7 @@ Build-Depends: cmake,
3333 libubuntugestures5-dev,
3434 libubuntugestures5-private-dev,
3535 libudev-dev,
36− libunity-api-dev (>= 7.113),
36+ libunity-api-dev (>= 7.115),
3737 libusermetricsoutput1-dev,
3838# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
3939 libx11-dev[!armhf],
plugins/Greeter/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=9)
22pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
33
44add_definitions(-DSM_BUSNAME=systemBus)
plugins/Greeter/Unity/Launcher/launcheritem.cpp+14
@@ -32,6 +32,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
3232 m_countVisible(false),
3333 m_focused(false),
3434 m_alerting(false),
35+ m_surfaceCount(0),
3536 m_quickList(new QuickListModel(this))
3637{
3738 QuickListEntry nameAction;
@@ -179,6 +180,19 @@ void LauncherItem::setAlerting(bool alerting)
179180 }
180181}
181182
183+int LauncherItem::surfaceCount() const
184+{
185+ return m_surfaceCount;
186+}
187+
188+void LauncherItem::setSurfaceCount(int surfaceCount)
189+{
190+ if (m_surfaceCount != surfaceCount) {
191+ m_surfaceCount = surfaceCount;
192+ Q_EMIT surfaceCountChanged(surfaceCount);
193+ }
194+}
195+
182196unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
183197{
184198 return m_quickList;
plugins/Greeter/Unity/Launcher/launcheritem.h+3−1
@@ -42,6 +42,7 @@ public:
4242 bool countVisible() const override;
4343 bool focused() const override;
4444 bool alerting() const override;
45+ int surfaceCount() const override;
4546
4647 unity::shell::launcher::QuickListModelInterface *quickList() const override;
4748
@@ -56,7 +57,7 @@ private:
5657 void setCountVisible(bool countVisible);
5758 void setFocused(bool focused);
5859 void setAlerting(bool alerting);
59−
60+ void setSurfaceCount(int surfaceCount);
6061
6162private:
6263 QString m_appId;
@@ -70,6 +71,7 @@ private:
7071 bool m_countVisible;
7172 bool m_focused;
7273 bool m_alerting;
74+ int m_surfaceCount;
7375 QuickListModel *m_quickList;
7476
7577 friend class LauncherModel;
plugins/Greeter/Unity/Launcher/launchermodelas.cpp+2−7
@@ -69,18 +69,13 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
6969 return item->focused();
7070 case RoleRunning:
7171 return item->running();
72+ case RoleSurfaceCount:
73+ return item->surfaceCount();
7274 }
7375
7476 return QVariant();
7577}
7678
77−void LauncherModel::setAlerting(const QString &appId, bool alerting)
78−{
79− Q_UNUSED(appId)
80− Q_UNUSED(alerting)
81− qWarning() << "This is a read only implementation. Cannot set alert-state of items.";
82−}
83−
8479unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
8580{
8681 if (index < 0 || index >= m_list.count()) {
plugins/Greeter/Unity/Launcher/launchermodelas.h−1
@@ -41,7 +41,6 @@ public:
4141
4242 QVariant data(const QModelIndex &index, int role) const override;
4343
44− Q_INVOKABLE void setAlerting(const QString &appId, bool alerting) override;
4544 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
4645 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
4746 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
plugins/Unity/Launcher/CMakeLists.txt+3−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=9)
22pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
33
44add_definitions(-DSM_BUSNAME=systemBus)
@@ -23,6 +23,8 @@ set(QMLLAUNCHERPLUGIN_SRC
2323 asadapter.cpp
2424 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
2525 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
26+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
27+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
2628 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
2729 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
2830 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
plugins/Unity/Launcher/Launcher.qmltypesdeleted−182
@@ -1,182 +0,0 @@
1−import QtQuick.tooling 1.1
2−
3−// This file describes the plugin-supplied types contained in the library.
4−// It is used for QML tooling purposes only.
5−//
6−// This file was auto-generated by:
7−// 'qmlplugindump -notrelocatable Unity.Launcher 0.1 plugins'
8−
9−Module {
10− Component {
11− name: "LauncherItem"
12− prototype: "unity::shell::launcher::LauncherItemInterface"
13− exports: ["Unity.Launcher/LauncherItem 0.1"]
14− isCreatable: false
15− exportMetaObjectRevisions: [0]
16− }
17− Component {
18− name: "LauncherModel"
19− prototype: "unity::shell::launcher::LauncherModelInterface"
20− exports: ["Unity.Launcher/LauncherModel 0.1"]
21− isCreatable: false
22− isSingleton: true
23− exportMetaObjectRevisions: [0]
24− Method {
25− name: "requestRemove"
26− Parameter { name: "appId"; type: "string" }
27− }
28− Method { name: "refresh" }
29− Method {
30− name: "get"
31− type: "unity::shell::launcher::LauncherItemInterface*"
32− Parameter { name: "index"; type: "int" }
33− }
34− Method {
35− name: "move"
36− Parameter { name: "oldIndex"; type: "int" }
37− Parameter { name: "newIndex"; type: "int" }
38− }
39− Method {
40− name: "pin"
41− Parameter { name: "appId"; type: "string" }
42− Parameter { name: "index"; type: "int" }
43− }
44− Method {
45− name: "pin"
46− Parameter { name: "appId"; type: "string" }
47− }
48− Method {
49− name: "quickListActionInvoked"
50− Parameter { name: "appId"; type: "string" }
51− Parameter { name: "actionIndex"; type: "int" }
52− }
53− Method {
54− name: "setUser"
55− Parameter { name: "username"; type: "string" }
56− }
57− Method {
58− name: "getUrlForAppId"
59− type: "string"
60− Parameter { name: "appId"; type: "string" }
61− }
62− }
63− Component {
64− name: "QuickListModel"
65− prototype: "unity::shell::launcher::QuickListModelInterface"
66− exports: ["Unity.Launcher/QuickListModel 0.1"]
67− isCreatable: false
68− exportMetaObjectRevisions: [0]
69− }
70− Component {
71− name: "unity::shell::launcher::LauncherItemInterface"
72− prototype: "QObject"
73− exports: ["Unity.Launcher/LauncherItemInterface 0.1"]
74− isCreatable: false
75− exportMetaObjectRevisions: [0]
76− Property { name: "appId"; type: "string"; isReadonly: true }
77− Property { name: "name"; type: "string"; isReadonly: true }
78− Property { name: "icon"; type: "string"; isReadonly: true }
79− Property { name: "pinned"; type: "bool"; isReadonly: true }
80− Property { name: "running"; type: "bool"; isReadonly: true }
81− Property { name: "recent"; type: "bool"; isReadonly: true }
82− Property { name: "progress"; type: "int"; isReadonly: true }
83− Property { name: "count"; type: "int"; isReadonly: true }
84− Property { name: "countVisible"; type: "bool"; isReadonly: true }
85− Property { name: "focused"; type: "bool"; isReadonly: true }
86− Property {
87− name: "quickList"
88− type: "unity::shell::launcher::QuickListModelInterface"
89− isReadonly: true
90− isPointer: true
91− }
92− Signal {
93− name: "nameChanged"
94− Parameter { name: "name"; type: "string" }
95− }
96− Signal {
97− name: "iconChanged"
98− Parameter { name: "icon"; type: "string" }
99− }
100− Signal {
101− name: "pinnedChanged"
102− Parameter { name: "pinned"; type: "bool" }
103− }
104− Signal {
105− name: "runningChanged"
106− Parameter { name: "running"; type: "bool" }
107− }
108− Signal {
109− name: "recentChanged"
110− Parameter { name: "running"; type: "bool" }
111− }
112− Signal {
113− name: "progressChanged"
114− Parameter { name: "progress"; type: "int" }
115− }
116− Signal {
117− name: "countChanged"
118− Parameter { name: "count"; type: "int" }
119− }
120− Signal {
121− name: "countVisibleChanged"
122− Parameter { name: "countVisible"; type: "bool" }
123− }
124− Signal {
125− name: "focusedChanged"
126− Parameter { name: "focused"; type: "bool" }
127− }
128− }
129− Component {
130− name: "unity::shell::launcher::LauncherModelInterface"
131− prototype: "QAbstractListModel"
132− exports: ["Unity.Launcher/LauncherModelInterface 0.1"]
133− isCreatable: false
134− exportMetaObjectRevisions: [0]
135− Property {
136− name: "applicationManager"
137− type: "unity::shell::application::ApplicationManagerInterface"
138− isPointer: true
139− }
140− Property { name: "onlyPinned"; type: "bool" }
141− Signal { name: "hint" }
142− Method {
143− name: "move"
144− Parameter { name: "oldIndex"; type: "int" }
145− Parameter { name: "newIndex"; type: "int" }
146− }
147− Method {
148− name: "get"
149− type: "unity::shell::launcher::LauncherItemInterface*"
150− Parameter { name: "index"; type: "int" }
151− }
152− Method {
153− name: "pin"
154− Parameter { name: "appId"; type: "string" }
155− Parameter { name: "index"; type: "int" }
156− }
157− Method {
158− name: "pin"
159− Parameter { name: "appId"; type: "string" }
160− }
161− Method {
162− name: "requestRemove"
163− Parameter { name: "appId"; type: "string" }
164− }
165− Method {
166− name: "quickListActionInvoked"
167− Parameter { name: "appId"; type: "string" }
168− Parameter { name: "actionIndex"; type: "int" }
169− }
170− Method {
171− name: "setUser"
172− Parameter { name: "username"; type: "string" }
173− }
174− }
175− Component {
176− name: "unity::shell::launcher::QuickListModelInterface"
177− prototype: "QAbstractListModel"
178− exports: ["Unity.Launcher/QuickListInterface 0.1"]
179− isCreatable: false
180− exportMetaObjectRevisions: [0]
181− }
182−}
plugins/Unity/Launcher/launcheritem.cpp+14−9
@@ -35,6 +35,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
3535 m_countVisible(false),
3636 m_focused(false),
3737 m_alerting(false),
38+ m_surfaceCount(0),
3839 m_quickList(new QuickListModel(this))
3940{
4041 Q_ASSERT(parent != nullptr);
@@ -162,9 +163,6 @@ void LauncherItem::setCount(int count)
162163 if (m_count != count) {
163164 m_count = count;
164165 Q_EMIT countChanged(count);
165− if (m_countVisible) {
166− setAlerting(true);
167− }
168166 }
169167}
170168
@@ -178,9 +176,6 @@ void LauncherItem::setCountVisible(bool countVisible)
178176 if (m_countVisible != countVisible) {
179177 m_countVisible = countVisible;
180178 Q_EMIT countVisibleChanged(countVisible);
181− if (countVisible) {
182− setAlerting(true);
183− }
184179 }
185180}
186181
@@ -193,9 +188,6 @@ void LauncherItem::setFocused(bool focused)
193188{
194189 if (m_focused != focused) {
195190 m_focused = focused;
196− if (focused) {
197− setAlerting(false);
198− }
199191 Q_EMIT focusedChanged(focused);
200192 }
201193}
@@ -213,6 +205,19 @@ void LauncherItem::setAlerting(bool alerting)
213205 }
214206}
215207
208+int LauncherItem::surfaceCount() const
209+{
210+ return m_surfaceCount;
211+}
212+
213+void LauncherItem::setSurfaceCount(int surfaceCount)
214+{
215+ if (m_surfaceCount != surfaceCount) {
216+ m_surfaceCount = surfaceCount;
217+ Q_EMIT surfaceCountChanged(surfaceCount);
218+ }
219+}
220+
216221unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
217222{
218223 return m_quickList;
plugins/Unity/Launcher/launcheritem.h+3
@@ -45,6 +45,7 @@ public:
4545 bool countVisible() const override;
4646 bool focused() const override;
4747 bool alerting() const override;
48+ int surfaceCount() const override;
4849
4950 unity::shell::launcher::QuickListModelInterface *quickList() const override;
5051
@@ -59,6 +60,7 @@ private:
5960 void setCountVisible(bool countVisible);
6061 void setFocused(bool focused);
6162 void setAlerting(bool alerting);
63+ void setSurfaceCount(int surfaceCount);
6264
6365private:
6466 QString m_appId;
@@ -72,6 +74,7 @@ private:
7274 bool m_countVisible;
7375 bool m_focused;
7476 bool m_alerting;
77+ int m_surfaceCount;
7578 QuickListModel *m_quickList;
7679 QuickListEntry m_quitAction;
7780
plugins/Unity/Launcher/launchermodel.cpp+58−26
@@ -25,6 +25,7 @@
2525#include "asadapter.h"
2626
2727#include <unity/shell/application/ApplicationInfoInterface.h>
28+#include <unity/shell/application/MirSurfaceListInterface.h>
2829
2930#include <QDesktopServices>
3031#include <QDebug>
@@ -88,6 +89,8 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
8889 return item->alerting();
8990 case RoleRunning:
9091 return item->running();
92+ case RoleSurfaceCount:
93+ return item->surfaceCount();
9194 default:
9295 qWarning() << Q_FUNC_INFO << "missing role, implement me";
9396 return QVariant();
@@ -96,18 +99,6 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
9699 return QVariant();
97100}
98101
99−void LauncherModel::setAlerting(const QString &appId, bool alerting) {
100− int index = findApplication(appId);
101− if (index >= 0) {
102− QModelIndex modelIndex = this->index(index);
103− LauncherItem *item = m_list.at(index);
104− if (!item->focused()) {
105− item->setAlerting(alerting);
106− Q_EMIT dataChanged(modelIndex, modelIndex, {RoleAlerting});
107− }
108− }
109−}
110−
111102unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
112103{
113104 if (index < 0 || index >= m_list.count()) {
@@ -358,11 +349,13 @@ void LauncherModel::countChanged(const QString &appId, int count)
358349 if (idx >= 0) {
359350 LauncherItem *item = m_list.at(idx);
360351 item->setCount(count);
361− if (item->countVisible()) {
362− setAlerting(item->appId(), true);
352+ QVector<int> changedRoles = {RoleCount};
353+ if (item->countVisible() && !item->alerting() && !item->focused()) {
354+ changedRoles << RoleAlerting;
355+ item->setAlerting(true);
363356 }
364357 m_asAdapter->syncItems(m_list);
365− Q_EMIT dataChanged(index(idx), index(idx), {RoleCount});
358+ Q_EMIT dataChanged(index(idx), index(idx), changedRoles);
366359 }
367360}
368361
@@ -372,10 +365,12 @@ void LauncherModel::countVisibleChanged(const QString &appId, bool countVisible)
372365 if (idx >= 0) {
373366 LauncherItem *item = m_list.at(idx);
374367 item->setCountVisible(countVisible);
375− if (countVisible) {
376− setAlerting(item->appId(), true);
368+ QVector<int> changedRoles = {RoleCount};
369+ if (countVisible && !item->alerting() && !item->focused()) {
370+ changedRoles << RoleAlerting;
371+ item->setAlerting(true);
377372 }
378− Q_EMIT dataChanged(index(idx), index(idx), {RoleCountVisible});
373+ Q_EMIT dataChanged(index(idx), index(idx), changedRoles);
379374
380375 // If countVisible goes to false, and the item is neither pinned nor recent we can drop it
381376 if (!countVisible && !item->pinned() && !item->recent()) {
@@ -498,8 +493,10 @@ void LauncherModel::alert(const QString &appId)
498493 int idx = findApplication(appId);
499494 if (idx >= 0) {
500495 LauncherItem *item = m_list.at(idx);
501− setAlerting(item->appId(), true);
502− Q_EMIT dataChanged(index(idx), index(idx), {RoleAlerting});
496+ if (!item->focused() && !item->alerting()) {
497+ item->setAlerting(true);
498+ Q_EMIT dataChanged(index(idx), index(idx), {RoleAlerting});
499+ }
503500 }
504501}
505502
@@ -525,28 +522,50 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
525522 item->setRecent(true);
526523 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
527524 }
525+ if (item->surfaceCount() != app->surfaceCount()) {
526+ item->setSurfaceCount(app->surfaceCount());
527+ Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleSurfaceCount});
528+ }
529+
528530 item->setRunning(true);
529531 } else {
530532 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
531533 item->setRecent(true);
532534 item->setRunning(true);
533535 item->setFocused(app->focused());
534−
536+ item->setSurfaceCount(app->surfaceCount());
535537 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
536538 m_list.append(item);
537539 endInsertRows();
538540 }
541+ connect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::applicationSurfaceCountChanged);
539542 m_asAdapter->syncItems(m_list);
540543 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRunning});
541544}
542545
546+void LauncherModel::applicationSurfaceCountChanged(int count)
547+{
548+ ApplicationInfoInterface *app = static_cast<ApplicationInfoInterface*>(sender());
549+ int idx = findApplication(app->appId());
550+ if (idx < 0) {
551+ qWarning() << "Received a surface count changed event from an app that's not in the Launcher model";
552+ return;
553+ }
554+ LauncherItem *item = m_list.at(idx);
555+ if (item->surfaceCount() != count) {
556+ item->setSurfaceCount(count);
557+ Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
558+ }
559+}
560+
543561void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
544562{
545563 Q_UNUSED(parent)
546564
565+ ApplicationInfoInterface *app = m_appManager->get(row);
547566 int appIndex = -1;
548567 for (int i = 0; i < m_list.count(); ++i) {
549− if (m_list.at(i)->appId() == m_appManager->get(row)->appId()) {
568+ if (m_list.at(i)->appId() == app->appId()) {
550569 appIndex = i;
551570 break;
552571 }
@@ -557,17 +576,24 @@ void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
557576 return;
558577 }
559578
579+ disconnect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::applicationSurfaceCountChanged);
580+
560581 LauncherItem * item = m_list.at(appIndex);
561− item->setRunning(false);
562582
563583 if (!item->pinned()) {
564584 beginRemoveRows(QModelIndex(), appIndex, appIndex);
565585 m_list.takeAt(appIndex)->deleteLater();
566586 endRemoveRows();
567587 m_asAdapter->syncItems(m_list);
568− Q_EMIT dataChanged(index(appIndex), index(appIndex), {RolePinned});
588+ } else {
589+ QVector<int> changedRoles = {RoleRunning};
590+ item->setRunning(false);
591+ if (item->focused()) {
592+ changedRoles << RoleFocused;
593+ item->setFocused(false);
594+ }
595+ Q_EMIT dataChanged(index(appIndex), index(appIndex), changedRoles);
569596 }
570− Q_EMIT dataChanged(index(appIndex), index(appIndex), {RoleRunning});
571597}
572598
573599void LauncherModel::focusedAppIdChanged()
@@ -576,8 +602,14 @@ void LauncherModel::focusedAppIdChanged()
576602 for (int i = 0; i < m_list.count(); ++i) {
577603 LauncherItem *item = m_list.at(i);
578604 if (!item->focused() && item->appId() == appId) {
605+ QVector<int> changedRoles;
606+ changedRoles << RoleFocused;
579607 item->setFocused(true);
580− Q_EMIT dataChanged(index(i), index(i), {RoleFocused});
608+ if (item->alerting()) {
609+ changedRoles << RoleAlerting;
610+ item->setAlerting(false);
611+ }
612+ Q_EMIT dataChanged(index(i), index(i), changedRoles);
581613 } else if (item->focused() && item->appId() != appId) {
582614 item->setFocused(false);
583615 Q_EMIT dataChanged(index(i), index(i), {RoleFocused});
plugins/Unity/Launcher/launchermodel.h+1−1
@@ -45,7 +45,6 @@ public:
4545
4646 QVariant data(const QModelIndex &index, int role) const override;
4747
48− Q_INVOKABLE void setAlerting(const QString &appId, bool alerting) override;
4948 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
5049 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
5150 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
@@ -79,6 +78,7 @@ private Q_SLOTS:
7978 void applicationAdded(const QModelIndex &parent, int row);
8079 void applicationRemoved(const QModelIndex &parent, int row);
8180 void focusedAppIdChanged();
81+ void applicationSurfaceCountChanged(int);
8282
8383private:
8484 QList<LauncherItem*> m_list;
qml/Launcher/LauncherDelegate.qml+4−8
@@ -32,6 +32,7 @@ Item {
3232 property bool alerting: false
3333 property bool highlighted: false
3434 property bool shortcutHintShown: false
35+ property int surfaceCount: 1
3536
3637 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
3738 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
@@ -114,12 +115,6 @@ Item {
114115 duration: priv.wiggleDuration
115116 easing.type: Easing.OutQuad
116117 }
117−
118− UbuntuNumberAnimation {
119− target: root
120− property: "alerting"
121− to: 0
122− }
123118 }
124119
125120 Item {
@@ -221,12 +216,13 @@ Item {
221216 }
222217 spacing: units.gu(.5)
223218 Repeater {
224− model: 1 // TODO: This should be "Math.min(3, app.surfaceCount)" once we have multiple surfaces
219+ objectName: "surfacePipRepeater"
220+ model: Math.min(3, root.surfaceCount)
225221 Rectangle {
226222 objectName: "runningHighlight" + index
227223 width: units.gu(0.25)
228224 height: units.gu(.5)
229− color: "white"
225+ color: root.alerting ? theme.palette.normal.activity : "white"
230226 visible: root.itemRunning
231227 }
232228 }
qml/Launcher/LauncherPanel.qml+2
@@ -239,6 +239,7 @@ Rectangle {
239239 alerting: model.alerting
240240 highlighted: root.highlightIndex == index
241241 shortcutHintShown: root.shortcutHintsShown && index <= 9
242+ surfaceCount: model.surfaceCount
242243 z: -Math.abs(offset)
243244 maxAngle: 55
244245 property bool dragging: false
@@ -271,6 +272,7 @@ Rectangle {
271272
272273 PropertyAction { target: launcherListViewItem; property: "clip"; value: 1 }
273274 PropertyAction { target: root; property: "visible"; value: (launcher.visibleWidth === 0) ? 0 : 1 }
275+ PropertyAction { target: launcherListView; property: "peekingIndex"; value: -1 }
274276 }
275277
276278 onAlertingChanged: {
qml/Stages/ApplicationWindow.qml+25−9
@@ -121,15 +121,12 @@ FocusScope {
121121
122122 property bool surfaceOldEnoughToBeResized: false
123123
124− property var focusedSurface: {
125− if (promptSurfacesRepeater.count == 0) {
126− return surfaceContainer;
127− } else {
128− return promptSurfacesRepeater.itemAt(promptSurfacesRepeater.count - 1);
129− }
130− }
124+ property Item focusedSurface: promptSurfacesRepeater.count === 0 ? surfaceContainer
125+ : promptSurfacesRepeater.first
131126 onFocusedSurfaceChanged: {
132− focusedSurface.focus = true;
127+ if (focusedSurface) {
128+ focusedSurface.focus = true;
129+ }
133130 }
134131 }
135132
@@ -158,6 +155,7 @@ FocusScope {
158155 objectName: "screenshotImage"
159156 anchors.fill: parent
160157 antialiasing: !root.interactive
158+ z: 1
161159
162160 function take() {
163161 // Save memory by using a half-resolution (thus quarter size) screenshot.
@@ -175,6 +173,7 @@ FocusScope {
175173 visible: active
176174 active: false
177175 anchors.fill: parent
176+ z: screenshotImage.z + 1
178177 sourceComponent: Component {
179178 Splash {
180179 id: splash
@@ -191,6 +190,7 @@ FocusScope {
191190
192191 SurfaceContainer {
193192 id: surfaceContainer
193+ z: splashLoader.z + 1
194194 requestedWidth: root.requestedWidth
195195 requestedHeight: root.requestedHeight
196196 surfaceOrientationAngle: application && application.rotatesWindowContents ? root.surfaceOrientationAngle : 0
@@ -208,12 +208,28 @@ FocusScope {
208208 }
209209 }
210210 delegate: SurfaceContainer {
211− interactive: index == (promptSurfacesRepeater.count - 1) && root.interactive
211+ id: promptSurfaceContainer
212+ interactive: index === 0 && root.interactive
212213 surface: model.surface
213214 width: root.width
214215 height: root.height
215216 isPromptSurface: true
217+ z: surfaceContainer.z + (promptSurfacesRepeater.count - index)
218+ property int index: model.index
219+ onIndexChanged: updateFirst()
220+ Component.onCompleted: updateFirst()
221+ function updateFirst() {
222+ if (index === 0) {
223+ promptSurfacesRepeater.first = promptSurfaceContainer;
224+ }
225+ }
226+ }
227+ onCountChanged: {
228+ if (count === 0) {
229+ first = null;
230+ }
216231 }
232+ property Item first: null
217233 }
218234
219235 // SurfaceContainer size drives ApplicationWindow size
tests/mocks/Unity/Application/ApplicationInfo.cpp+29−27
@@ -55,8 +55,10 @@ QString stateToStr(ApplicationInfo::State state)
5555ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
5656 : ApplicationInfoInterface(appId, parent)
5757 , m_appId(appId)
58+ , m_surfaceList(new MirSurfaceListModel(this))
59+ , m_promptSurfaceList(new MirSurfaceListModel(this))
5860{
59− connect(&m_surfaceList, &MirSurfaceListModel::countChanged,
61+ connect(m_surfaceList, &MirSurfaceListModel::countChanged,
6062 this, &ApplicationInfo::onSurfaceCountChanged, Qt::QueuedConnection);
6163
6264 m_surfaceCreationTimer.setSingleShot(true);
@@ -78,8 +80,8 @@ void ApplicationInfo::createSurface()
7880 if (state() == ApplicationInfo::Stopped) { return; }
7981
8082 QString surfaceName = name();
81− if (m_surfaceList.count() > 0) {
82− surfaceName.append(QString(" %1").arg(m_surfaceList.count()+1));
83+ if (m_surfaceList->count() > 0) {
84+ surfaceName.append(QString(" %1").arg(m_surfaceList->count()+1));
8385 }
8486
8587 auto surfaceManager = SurfaceManager::instance();
@@ -95,7 +97,7 @@ void ApplicationInfo::createSurface()
9597
9698 surface->setShellChrome(m_shellChrome);
9799
98− m_surfaceList.appendSurface(surface);
100+ m_surfaceList->appendSurface(surface);
99101
100102 ++m_liveSurfaceCount;
101103 connect(surface, &MirSurface::liveChanged, this, [this, surface](){
@@ -186,16 +188,16 @@ void ApplicationInfo::setState(State value)
186188 if (value != m_state) {
187189 DEBUG_MSG(qPrintable(stateToStr(value)));
188190 if (!m_manualSurfaceCreation && value == ApplicationInfo::Starting) {
189− Q_ASSERT(m_surfaceList.count() == 0);
191+ Q_ASSERT(m_surfaceList->count() == 0);
190192 m_surfaceCreationTimer.start();
191193 } else if (value == ApplicationInfo::Stopped) {
192194 m_surfaceCreationTimer.stop();
193− for (int i = 0; i < m_surfaceList.count(); ++i) {
194− MirSurface *surface = static_cast<MirSurface*>(m_surfaceList.get(i));
195+ for (int i = 0; i < m_surfaceList->count(); ++i) {
196+ MirSurface *surface = static_cast<MirSurface*>(m_surfaceList->get(i));
195197 surface->setLive(false);
196198 }
197− for (int i = 0; i < m_promptSurfaceList.count(); ++i) {
198− auto surface = static_cast<MirSurface*>(m_promptSurfaceList.get(i));
199+ for (int i = 0; i < m_promptSurfaceList->count(); ++i) {
200+ auto surface = static_cast<MirSurface*>(m_promptSurfaceList->get(i));
199201 surface->setLive(false);
200202 }
201203 }
@@ -209,9 +211,9 @@ void ApplicationInfo::close()
209211{
210212 DEBUG_MSG("");
211213
212− if (m_surfaceList.count() > 0) {
213− for (int i = 0; i < m_surfaceList.count(); ++i) {
214− MirSurface *surface = static_cast<MirSurface*>(m_surfaceList.get(i));
214+ if (m_surfaceList->count() > 0) {
215+ for (int i = 0; i < m_surfaceList->count(); ++i) {
216+ MirSurface *surface = static_cast<MirSurface*>(m_surfaceList->get(i));
215217 surface->close();
216218 }
217219 } else {
@@ -223,15 +225,15 @@ void ApplicationInfo::close()
223225void ApplicationInfo::setFullscreen(bool value)
224226{
225227 m_fullscreen = value;
226− if (m_surfaceList.rowCount() > 0) {
227− m_surfaceList.get(0)->setState(Mir::FullscreenState);
228+ if (m_surfaceList->rowCount() > 0) {
229+ m_surfaceList->get(0)->setState(Mir::FullscreenState);
228230 }
229231}
230232
231233bool ApplicationInfo::fullscreen() const
232234{
233− if (m_surfaceList.rowCount() > 0) {
234− return m_surfaceList.get(0)->state() == Mir::FullscreenState;
235+ if (m_surfaceList->rowCount() > 0) {
236+ return m_surfaceList->get(0)->state() == Mir::FullscreenState;
235237 } else {
236238 return m_fullscreen;
237239 }
@@ -341,16 +343,16 @@ void ApplicationInfo::setInitialSurfaceSize(const QSize &size)
341343void ApplicationInfo::setShellChrome(Mir::ShellChrome shellChrome)
342344{
343345 m_shellChrome = shellChrome;
344− if (m_surfaceList.rowCount() > 0) {
345− static_cast<MirSurface*>(m_surfaceList.get(0))->setShellChrome(shellChrome);
346+ if (m_surfaceList->rowCount() > 0) {
347+ static_cast<MirSurface*>(m_surfaceList->get(0))->setShellChrome(shellChrome);
346348 }
347349}
348350
349351bool ApplicationInfo::focused() const
350352{
351353 bool someSurfaceHasFocus = false; // to be proven wrong
352− for (int i = 0; i < m_surfaceList.count() && !someSurfaceHasFocus; ++i) {
353− someSurfaceHasFocus = m_surfaceList.get(i)->focused();
354+ for (int i = 0; i < m_surfaceList->count() && !someSurfaceHasFocus; ++i) {
355+ someSurfaceHasFocus = m_surfaceList->get(i)->focused();
354356 }
355357 return someSurfaceHasFocus;
356358}
@@ -362,12 +364,12 @@ void ApplicationInfo::setFocused(bool value)
362364 }
363365
364366 if (value) {
365− if (m_surfaceList.count() > 0) {
366− m_surfaceList.get(0)->requestFocus();
367+ if (m_surfaceList->count() > 0) {
368+ m_surfaceList->get(0)->requestFocus();
367369 }
368370 } else {
369− for (int i = 0; i < m_surfaceList.count(); ++i) {
370− MirSurface *surface = static_cast<MirSurface*>(m_surfaceList.get(i));
371+ for (int i = 0; i < m_surfaceList->count(); ++i) {
372+ MirSurface *surface = static_cast<MirSurface*>(m_surfaceList->get(i));
371373 if (surface->focused()) {
372374 surface->setFocused(false);
373375 }
@@ -377,16 +379,16 @@ void ApplicationInfo::setFocused(bool value)
377379
378380void ApplicationInfo::onSurfaceCountChanged()
379381{
380− if (m_surfaceList.count() == 0 && m_state == Running) {
382+ if (m_surfaceList->count() == 0 && m_state == Running) {
381383 setState(Stopped);
382384 }
383385}
384386
385387void ApplicationInfo::requestFocus()
386388{
387− if (m_surfaceList.count() == 0) {
389+ if (m_surfaceList->count() == 0) {
388390 Q_EMIT focusRequested();
389391 } else {
390− m_surfaceList.get(0)->requestFocus();
392+ m_surfaceList->get(0)->requestFocus();
391393 }
392394}
tests/mocks/Unity/Application/ApplicationInfo.h+5−4
@@ -107,8 +107,9 @@ public:
107107
108108 Q_INVOKABLE void setShellChrome(Mir::ShellChrome shellChrome);
109109
110− MirSurfaceListInterface* surfaceList() override { return &m_surfaceList; }
111− MirSurfaceListInterface* promptSurfaceList() override { return &m_promptSurfaceList; }
110+ MirSurfaceListInterface* surfaceList() const override { return m_surfaceList; }
111+ MirSurfaceListInterface* promptSurfaceList() const override { return m_promptSurfaceList; }
112+ int surfaceCount() const override { return m_surfaceList->count(); }
112113
113114 void setFocused(bool value);
114115
@@ -148,8 +149,8 @@ private:
148149 bool m_isTouchApp{true};
149150 bool m_exemptFromLifecycle{false};
150151 QSize m_initialSurfaceSize;
151− MirSurfaceListModel m_surfaceList;
152− MirSurfaceListModel m_promptSurfaceList;
152+ MirSurfaceListModel *m_surfaceList;
153+ MirSurfaceListModel *m_promptSurfaceList;
153154 int m_liveSurfaceCount{0};
154155 QTimer m_surfaceCreationTimer;
155156 QList<MirSurface*> m_closingSurfaces;
tests/mocks/Unity/Application/MirSurfaceListModel.cpp+13−3
@@ -66,12 +66,22 @@ void MirSurfaceListModel::appendSurface(MirSurface *surface)
6666 m_surfaceList.append(surface);
6767 connectSurface(surface);
6868 endInsertRows();
69− Q_EMIT countChanged();
69+ Q_EMIT countChanged(m_surfaceList.count());
7070 if (m_surfaceList.count() == 1) {
7171 Q_EMIT firstChanged();
7272 }
7373}
7474
75+void MirSurfaceListModel::prependSurface(MirSurface *surface)
76+{
77+ beginInsertRows(QModelIndex(), 0, 0);
78+ m_surfaceList.prepend(surface);
79+ connectSurface(surface);
80+ endInsertRows();
81+ Q_EMIT countChanged(m_surfaceList.count());
82+ Q_EMIT firstChanged();
83+}
84+
7585void MirSurfaceListModel::connectSurface(MirSurface *surface)
7686{
7787 connect(surface, &MirSurface::raiseRequested, this, [this, surface](){ this->raise(surface); });
@@ -85,7 +95,7 @@ void MirSurfaceListModel::removeSurface(MirSurface *surface)
8595 beginRemoveRows(QModelIndex(), i, i);
8696 m_surfaceList.removeAt(i);
8797 endRemoveRows();
88− Q_EMIT countChanged();
98+ Q_EMIT countChanged(m_surfaceList.count());
8999 if (m_surfaceList.count() == 0 || i == 0) {
90100 Q_EMIT firstChanged();
91101 }
@@ -143,7 +153,7 @@ MirSurfaceInterface *MirSurfaceListModel::createSurface()
143153 Mir::RestoredState,
144154 screenshotUrl);
145155
146− appendSurface(surface);
156+ prependSurface(surface);
147157
148158 return surface;
149159}
tests/mocks/Unity/Application/MirSurfaceListModel.h+1
@@ -49,6 +49,7 @@ public:
4949 Q_INVOKABLE unity::shell::application::MirSurfaceInterface *createSurface();
5050
5151private:
52+ void prependSurface(MirSurface *surface);
5253 void raise(MirSurface *surface);
5354 void moveSurface(int from, int to);
5455 void connectSurface(MirSurface *surface);
tests/mocks/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=9)
22
33include_directories(
44 ${CMAKE_CURRENT_SOURCE_DIR}
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+14
@@ -38,6 +38,7 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
3838 m_countVisible(false),
3939 m_focused(false),
4040 m_alerting(false),
41+ m_surfaceCount(0),
4142 m_quickList(new MockQuickListModel(this))
4243{
4344}
@@ -182,6 +183,19 @@ void MockLauncherItem::setAlerting(bool alerting)
182183 }
183184}
184185
186+int MockLauncherItem::surfaceCount() const
187+{
188+ return m_surfaceCount;
189+}
190+
191+void MockLauncherItem::setSurfaceCount(int surfaceCount)
192+{
193+ if (m_surfaceCount != surfaceCount) {
194+ m_surfaceCount = surfaceCount;
195+ Q_EMIT surfaceCountChanged(surfaceCount);
196+ }
197+}
198+
185199unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
186200{
187201 return m_quickList;
tests/mocks/Unity/Launcher/MockLauncherItem.h+3
@@ -46,6 +46,7 @@ public:
4646 bool countVisible() const override;
4747 bool focused() const override;
4848 bool alerting() const override;
49+ int surfaceCount() const override;
4950
5051 unity::shell::launcher::QuickListModelInterface *quickList() const override;
5152
@@ -58,6 +59,7 @@ private:
5859 void setCountVisible(bool countVisible);
5960 void setFocused(bool focused);
6061 void setAlerting(bool alerting);
62+ void setSurfaceCount(int surfaceCount);
6163
6264 QString m_appId;
6365 QString m_desktopFile;
@@ -71,6 +73,7 @@ private:
7173 bool m_countVisible;
7274 bool m_focused;
7375 bool m_alerting;
76+ int m_surfaceCount;
7477 MockQuickListModel *m_quickList;
7578
7679 friend class MockLauncherModel;
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+5
@@ -25,6 +25,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
2525 MockLauncherItem *item = new MockLauncherItem("dialer-app", "/usr/share/applications/dialer-app.desktop", "Dialer", "dialer-app", this);
2626 item->setProgress(0);
2727 item->setPinned(true);
28+ item->setSurfaceCount(1);
2829 item->setRunning(true);
2930 item->setFocused(true);
3031 m_list.append(item);
@@ -36,6 +37,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
3637 item->setProgress(50);
3738 item->setCountVisible(true);
3839 item->setRunning(true);
40+ item->setSurfaceCount(2);
3941 item->setAlerting(false);
4042 m_list.append(item);
4143 item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
@@ -44,6 +46,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
4446 item->setProgress(150);
4547 m_list.append(item);
4648 item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this);
49+ item->setSurfaceCount(5);
4750 item->setCount(1);
4851 item->setCountVisible(true);
4952 item->setRunning(true);
@@ -119,6 +122,8 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
119122 return item->focused();
120123 case RoleAlerting:
121124 return item->alerting();
125+ case RoleSurfaceCount:
126+ return item->surfaceCount();
122127 }
123128
124129 return QVariant();
tests/mocks/Unity/Launcher/MockLauncherModel.h+1−1
@@ -38,7 +38,7 @@ public:
3838
3939 QVariant data(const QModelIndex& index, int role) const override;
4040
41− Q_INVOKABLE void setAlerting(const QString &appId, bool alerting) override;
41+ Q_INVOKABLE void setAlerting(const QString &appId, bool alerting); // Only for testing
4242 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface *get(int index) const override;
4343 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
4444 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
tests/plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,5 +1,5 @@
11pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=8)
33
44include_directories(
55 ${CMAKE_CURRENT_SOURCE_DIR}
tests/plugins/Unity/Launcher/launchermodeltest.cpp+22−2
@@ -66,14 +66,17 @@ public:
6666 void setExemptFromLifecycle(bool) override {}
6767 QSize initialSurfaceSize() const override { return QSize(); }
6868 void setInitialSurfaceSize(const QSize &) override {}
69− MirSurfaceListInterface* surfaceList() override { return nullptr; }
70− MirSurfaceListInterface* promptSurfaceList() override { return nullptr; }
69+ MirSurfaceListInterface* surfaceList() const override { return nullptr; }
70+ MirSurfaceListInterface* promptSurfaceList() const override { return nullptr; }
71+ int surfaceCount() const override { return m_surfaceCount; }
72+ void setSurfaceCount(int count) { m_surfaceCount = count; Q_EMIT surfaceCountChanged(count); }
7173
7274 // Methods used for mocking (not in the interface)
7375 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
7476private:
7577 QString m_appId;
7678 bool m_focused;
79+ int m_surfaceCount = 0;
7780};
7881
7982// This is a mock, specifically to test the LauncherModel
@@ -488,6 +491,10 @@ private Q_SLOTS:
488491
489492 // Finally check, that the change to "count" implicitly also set the alerting-state to true
490493 QVERIFY(launcherModel->get(index)->alerting() == true);
494+
495+ // Focus the app, make sure the alert gets cleared
496+ appManager->focusApplication("abs-icon");
497+ QVERIFY(launcherModel->get(index)->alerting() == false);
491498 }
492499
493500 void testCountEmblemAddsRemovesItem_data() {
@@ -559,6 +566,10 @@ private Q_SLOTS:
559566
560567 // Check that the alerting-status is now true
561568 QVERIFY(launcherModel->get(index)->alerting() == true);
569+
570+ // Focus the app, make sure the alert gets cleared
571+ appManager->focusApplication("abs-icon");
572+ QVERIFY(launcherModel->get(index)->alerting() == false);
562573 }
563574
564575 void testRefreshAfterDeletedDesktopFiles_data() {
@@ -692,6 +703,15 @@ private Q_SLOTS:
692703 QCOMPARE(getASConfig().at(index).value("countVisible").toBool(), true);
693704 QCOMPARE(getASConfig().at(index).value("count").toInt(), 55);
694705 }
706+
707+ void testSurfaceCountUpdates() {
708+ QString appId = launcherModel->get(0)->appId();
709+
710+ QCOMPARE(launcherModel->get(0)->surfaceCount(), 0);
711+ MockApp *app = qobject_cast<MockApp*>(appManager->findApplication(appId));
712+ app->setSurfaceCount(1);
713+ QCOMPARE(launcherModel->get(0)->surfaceCount(), 1);
714+ }
695715};
696716
697717QTEST_GUILESS_MAIN(LauncherModelTest)
tests/qmltests/Launcher/tst_Launcher.qml+25−9
@@ -486,25 +486,26 @@ Rectangle {
486486 function test_progressOverlays() {
487487 dragLauncherIntoView();
488488 var launcherListView = findChild(launcher, "launcherListView");
489+ var moveAnimation = findInvisibleChild(launcherListView, "moveAnimation")
489490 for (var i = 0; i < launcherListView.count; ++i) {
490− var delegate = findChild(launcherListView, "launcherDelegate" + i)
491− compare(findChild(delegate, "progressOverlay").visible, LauncherModel.get(i).progress >= 0)
492− }
493− }
491+ launcherListView.moveToIndex(i);
492+ waitForRendering(launcherListView);
493+ tryCompare(moveAnimation, "running", false);
494494
495− function test_runningHighlight() {
496− dragLauncherIntoView();
497− var launcherListView = findChild(launcher, "launcherListView");
498− for (var i = 0; i < launcherListView.count; ++i) {
499495 var delegate = findChild(launcherListView, "launcherDelegate" + i)
500− compare(findChild(delegate, "runningHighlight0").visible, LauncherModel.get(i).running)
496+ compare(findChild(delegate, "progressOverlay").visible, LauncherModel.get(i).progress >= 0)
501497 }
502498 }
503499
504500 function test_focusedHighlight() {
505501 dragLauncherIntoView();
506502 var launcherListView = findChild(launcher, "launcherListView");
503+ var moveAnimation = findInvisibleChild(launcherListView, "moveAnimation")
504+
507505 for (var i = 0; i < launcherListView.count; ++i) {
506+ launcherListView.moveToIndex(i);
507+ waitForRendering(launcherListView);
508+ tryCompare(moveAnimation, "running", false);
508509 var delegate = findChild(launcherListView, "launcherDelegate" + i)
509510 compare(findChild(delegate, "focusedHighlight").visible, LauncherModel.get(i).focused)
510511 }
@@ -1295,5 +1296,20 @@ Rectangle {
12951296
12961297 assertFocusOnIndex(-2);
12971298 }
1299+
1300+ function test_surfaceCountPips() {
1301+ var launcherListView = findChild(launcher, "launcherListView")
1302+ var moveAnimation = findInvisibleChild(launcherListView, "moveAnimation")
1303+
1304+ for (var i = 0; i < launcherListView.count; i++) {
1305+ launcherListView.moveToIndex(i);
1306+ waitForRendering(launcherListView);
1307+ tryCompare(moveAnimation, "running", false);
1308+
1309+ var delegate = findChild(launcher, "launcherDelegate" + i);
1310+ var surfacePipRepeater = findInvisibleChild(delegate, "surfacePipRepeater");
1311+ compare(surfacePipRepeater.model, Math.min(3, LauncherModel.get(i).surfaceCount))
1312+ }
1313+ }
12981314 }
12991315}
tests/qmltests/Stages/ApplicationCheckBox.qml+1−1
@@ -156,7 +156,7 @@ Column {
156156 width: height
157157 height: promptsLabel.height * 0.7
158158 anchors.verticalCenter: parent.verticalCenter
159− onClicked: d.application.promptSurfaceList.get(d.application.promptSurfaceList.count - 1).close()
159+ onClicked: d.application.promptSurfaceList.get(0).close()
160160 enabled: d.application && d.application.promptSurfaceList.count > 0
161161 Label { text: "➖"; anchors.centerIn: parent; enabled: parent.enabled }
162162 }
tests/qmltests/Stages/tst_ApplicationWindow.qml+39−9
@@ -106,7 +106,7 @@ Rectangle {
106106 enabled: parent.promptSurfaceList !== null && parent.promptSurfaceList.count > 0
107107 activeFocusOnPress: false
108108 text: "Remove"
109− onClicked: { parent.promptSurfaceList.get(parent.promptSurfaceList.count - 1).close(); }
109+ onClicked: { parent.promptSurfaceList.get(0).close(); }
110110 }
111111
112112 Button {
@@ -449,20 +449,21 @@ Rectangle {
449449 for (i = 0; i < 3; i++) {
450450 promptSurfaceList.createSurface();
451451 compare(promptSurfaces.count, i+1);
452− waitUntilSurfaceContainerStopsAnimating(promptSurfaces.itemAt(promptSurfaces.count - 1));
452+ waitUntilSurfaceContainerStopsAnimating(promptSurfaces.itemAt(0));
453453 }
454454
455− for (i = 2; i >= 0; --i) {
456− var promptSurface = promptSurfaceList.get(i);
455+ for (i = 3; i > 0; --i) {
456+ var promptSurface = promptSurfaceList.get(0);
457457 compare(promptSurface.activeFocus, true);
458458
459459 promptSurface.close();
460− tryCompareFunction(function() { return promptSurfaces.count; }, i);
460+ promptSurface = null;
461+ tryCompareFunction(function() { return promptSurfaces.count; }, i-1);
461462
462− if (i > 0) {
463− // active focus should have gone to the yongest remaining sibling
464− var previousPromptSurface = promptSurfaceList.get(i-1);
465− tryCompare(previousPromptSurface, "activeFocus", true);
463+ if (promptSurfaces.count > 0) {
464+ // active focus should have gone to the new head of the list
465+ promptSurface = promptSurfaceList.get(0);
466+ tryCompare(promptSurface, "activeFocus", true);
466467 } else {
467468 // active focus should have gone to the application surface
468469 tryCompare(applicationWindow.surface, "activeFocus", true);
@@ -498,5 +499,34 @@ Rectangle {
498499 delegate.surface.close();
499500 tryCompare(promptSurfaces, "count", 0);
500501 }
502+
503+ // Check that the z value of SurfaceContainers for prompt surfaces go from highest
504+ // for index 0 to lowest for the last index in the prompt surface list.
505+ // Regression test for https://bugs.launchpad.net/bugs/1586219
506+ function test_promptSurfacesZOrdering() {
507+ var promptSurfaceList = root.fakeApplication.promptSurfaceList;
508+ var promptSurfaces = testCase.findChild(applicationWindow, "promptSurfacesRepeater");
509+
510+ promptSurfaceList.createSurface();
511+
512+ for (var i = 2; i <= 3; i++) {
513+ promptSurfaceList.createSurface();
514+ tryCompare(promptSurfaces, "count", i);
515+ waitUntilSurfaceContainerStopsAnimating(promptSurfaces.itemAt(0));
516+
517+ for (var j = 1; j < promptSurfaces.count; j++) {
518+ var delegate = promptSurfaces.itemAt(j);
519+ var previousDelegate = promptSurfaces.itemAt(j-1);
520+ verify(previousDelegate.z > delegate.z);
521+ }
522+ }
523+
524+ // clean up
525+ while (promptSurfaceList.count > 0) {
526+ var currentCount = promptSurfaceList.count;
527+ promptSurfaceList.get(0).close();
528+ tryCompare(promptSurfaceList, "count", currentCount - 1);
529+ }
530+ }
501531 }
502532}