on xenial help sign in
add support for launcher surface pips reflecting the proper number of surfaces
a1b1033Michael Zanetti
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=8)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
3
3
4add_definitions(-DSM_BUSNAME=systemBus)
4add_definitions(-DSM_BUSNAME=systemBus)
plugins/Greeter/Unity/Launcher/launcheritem.cpp+13
@@ -179,6 +179,19 @@ void LauncherItem::setAlerting(bool alerting)
179 }
179 }
180}
180}
181
181
182+int LauncherItem::surfaceCount() const
183+{
184+ return m_surfaceCount;
185+}
186+
187+void LauncherItem::setSurfaceCount(int surfaceCount)
188+{
189+ if (m_surfaceCount != surfaceCount) {
190+ m_surfaceCount = surfaceCount;
191+ Q_EMIT surfaceCountChanged(surfaceCount);
192+ }
193+}
194+
182unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
195unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
183{
196{
184 return m_quickList;
197 return m_quickList;
plugins/Greeter/Unity/Launcher/launcheritem.h+3−1
@@ -42,6 +42,7 @@ public:
42 bool countVisible() const override;
42 bool countVisible() const override;
43 bool focused() const override;
43 bool focused() const override;
44 bool alerting() const override;
44 bool alerting() const override;
45+ int surfaceCount() const override;
45
46
46 unity::shell::launcher::QuickListModelInterface *quickList() const override;
47 unity::shell::launcher::QuickListModelInterface *quickList() const override;
47
48
@@ -56,7 +57,7 @@ private:
56 void setCountVisible(bool countVisible);
57 void setCountVisible(bool countVisible);
57 void setFocused(bool focused);
58 void setFocused(bool focused);
58 void setAlerting(bool alerting);
59 void setAlerting(bool alerting);
59−
60+ void setSurfaceCount(int surfaceCount);
60
61
61private:
62private:
62 QString m_appId;
63 QString m_appId;
@@ -70,6 +71,7 @@ private:
70 bool m_countVisible;
71 bool m_countVisible;
71 bool m_focused;
72 bool m_focused;
72 bool m_alerting;
73 bool m_alerting;
74+ int m_surfaceCount;
73 QuickListModel *m_quickList;
75 QuickListModel *m_quickList;
74
76
75 friend class LauncherModel;
77 friend class LauncherModel;
plugins/Greeter/Unity/Launcher/launchermodelas.cpp+2
@@ -69,6 +69,8 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
69 return item->focused();
69 return item->focused();
70 case RoleRunning:
70 case RoleRunning:
71 return item->running();
71 return item->running();
72+ case RoleSurfaceCount:
73+ return item->surfaceCount();
72 }
74 }
73
75
74 return QVariant();
76 return QVariant();
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=8)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
3
3
4add_definitions(-DSM_BUSNAME=systemBus)
4add_definitions(-DSM_BUSNAME=systemBus)
@@ -23,6 +23,8 @@ set(QMLLAUNCHERPLUGIN_SRC
23 asadapter.cpp
23 asadapter.cpp
24 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
24 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
25 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
25 ${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
26 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
28 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
27 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
29 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
28 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
30 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
plugins/Unity/Launcher/launcheritem.cpp+14
@@ -35,6 +35,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
35 m_countVisible(false),
35 m_countVisible(false),
36 m_focused(false),
36 m_focused(false),
37 m_alerting(false),
37 m_alerting(false),
38+ m_surfaceCount(0),
38 m_quickList(new QuickListModel(this))
39 m_quickList(new QuickListModel(this))
39{
40{
40 Q_ASSERT(parent != nullptr);
41 Q_ASSERT(parent != nullptr);
@@ -213,6 +214,19 @@ void LauncherItem::setAlerting(bool alerting)
213 }
214 }
214}
215}
215
216
217+int LauncherItem::surfaceCount() const
218+{
219+ return m_surfaceCount;
220+}
221+
222+void LauncherItem::setSurfaceCount(int surfaceCount)
223+{
224+ if (m_surfaceCount != surfaceCount) {
225+ m_surfaceCount = surfaceCount;
226+ Q_EMIT surfaceCountChanged(surfaceCount);
227+ }
228+}
229+
216unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
230unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
217{
231{
218 return m_quickList;
232 return m_quickList;
plugins/Unity/Launcher/launcheritem.h+3
@@ -45,6 +45,7 @@ public:
45 bool countVisible() const override;
45 bool countVisible() const override;
46 bool focused() const override;
46 bool focused() const override;
47 bool alerting() const override;
47 bool alerting() const override;
48+ int surfaceCount() const override;
48
49
49 unity::shell::launcher::QuickListModelInterface *quickList() const override;
50 unity::shell::launcher::QuickListModelInterface *quickList() const override;
50
51
@@ -59,6 +60,7 @@ private:
59 void setCountVisible(bool countVisible);
60 void setCountVisible(bool countVisible);
60 void setFocused(bool focused);
61 void setFocused(bool focused);
61 void setAlerting(bool alerting);
62 void setAlerting(bool alerting);
63+ void setSurfaceCount(int surfaceCount);
62
64
63private:
65private:
64 QString m_appId;
66 QString m_appId;
@@ -72,6 +74,7 @@ private:
72 bool m_countVisible;
74 bool m_countVisible;
73 bool m_focused;
75 bool m_focused;
74 bool m_alerting;
76 bool m_alerting;
77+ int m_surfaceCount;
75 QuickListModel *m_quickList;
78 QuickListModel *m_quickList;
76 QuickListEntry m_quitAction;
79 QuickListEntry m_quitAction;
77
80
plugins/Unity/Launcher/launchermodel.cpp+25−1
@@ -25,6 +25,7 @@
25#include "asadapter.h"
25#include "asadapter.h"
26
26
27#include <unity/shell/application/ApplicationInfoInterface.h>
27#include <unity/shell/application/ApplicationInfoInterface.h>
28+#include <unity/shell/application/MirSurfaceListInterface.h>
28
29
29#include <QDesktopServices>
30#include <QDesktopServices>
30#include <QDebug>
31#include <QDebug>
@@ -88,6 +89,8 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
88 return item->alerting();
89 return item->alerting();
89 case RoleRunning:
90 case RoleRunning:
90 return item->running();
91 return item->running();
92+ case RoleSurfaceCount:
93+ return item->surfaceCount();
91 default:
94 default:
92 qWarning() << Q_FUNC_INFO << "missing role, implement me";
95 qWarning() << Q_FUNC_INFO << "missing role, implement me";
93 return QVariant();
96 return QVariant();
@@ -525,21 +528,42 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
525 item->setRecent(true);
528 item->setRecent(true);
526 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
529 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
527 }
530 }
531+ if (item->surfaceCount() != app->surfaceCount()) {
532+ item->setSurfaceCount(app->surfaceList()->count());
533+ Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleSurfaceCount});
534+ }
535+
528 item->setRunning(true);
536 item->setRunning(true);
529 } else {
537 } else {
530 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
538 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
531 item->setRecent(true);
539 item->setRecent(true);
532 item->setRunning(true);
540 item->setRunning(true);
533 item->setFocused(app->focused());
541 item->setFocused(app->focused());
534−
542+ item->setSurfaceCount(app->surfaceCount());
535 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
543 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
536 m_list.append(item);
544 m_list.append(item);
537 endInsertRows();
545 endInsertRows();
538 }
546 }
547+ connect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::applicationSurfaceCountChanged);
539 m_asAdapter->syncItems(m_list);
548 m_asAdapter->syncItems(m_list);
540 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRunning});
549 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRunning});
541}
550}
542
551
552+void LauncherModel::applicationSurfaceCountChanged(int count)
553+{
554+ ApplicationInfoInterface *app = static_cast<ApplicationInfoInterface*>(sender());
555+ int idx = findApplication(app->appId());
556+ if (idx < 0) {
557+ qWarning() << "Received a surface count changed event from an app that's not in the Launcher model";
558+ return;
559+ }
560+ LauncherItem *item = m_list.at(idx);
561+ if (item->surfaceCount() != count) {
562+ item->setSurfaceCount(count);
563+ Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
564+ }
565+}
566+
543void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
567void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
544{
568{
545 Q_UNUSED(parent)
569 Q_UNUSED(parent)
plugins/Unity/Launcher/launchermodel.h+1
@@ -79,6 +79,7 @@ private Q_SLOTS:
79 void applicationAdded(const QModelIndex &parent, int row);
79 void applicationAdded(const QModelIndex &parent, int row);
80 void applicationRemoved(const QModelIndex &parent, int row);
80 void applicationRemoved(const QModelIndex &parent, int row);
81 void focusedAppIdChanged();
81 void focusedAppIdChanged();
82+ void applicationSurfaceCountChanged(int);
82
83
83private:
84private:
84 QList<LauncherItem*> m_list;
85 QList<LauncherItem*> m_list;
qml/Launcher/LauncherDelegate.qml+4−2
@@ -32,6 +32,7 @@ Item {
32 property bool alerting: false
32 property bool alerting: false
33 property bool highlighted: false
33 property bool highlighted: false
34 property bool shortcutHintShown: false
34 property bool shortcutHintShown: false
35+ property int surfaceCount: 1
35
36
36 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
37 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
37 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
38 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
@@ -171,7 +172,7 @@ Item {
171 Label {
172 Label {
172 id: countLabel
173 id: countLabel
173 objectName: "countLabel"
174 objectName: "countLabel"
174− text: root.count
175+ text: root.surfaceCount//root.count
175 anchors.centerIn: parent
176 anchors.centerIn: parent
176 width: root.itemWidth - units.gu(1)
177 width: root.itemWidth - units.gu(1)
177 horizontalAlignment: Text.AlignHCenter
178 horizontalAlignment: Text.AlignHCenter
@@ -221,7 +222,8 @@ Item {
221 }
222 }
222 spacing: units.gu(.5)
223 spacing: units.gu(.5)
223 Repeater {
224 Repeater {
225+ objectName: "surfacePipRepeater"
224− model: 1 // TODO: This should be "Math.min(3, app.surfaceCount)" once we have multiple surfaces
226+ model: Math.min(3, root.surfaceCount)
225 Rectangle {
227 Rectangle {
226 objectName: "runningHighlight" + index
228 objectName: "runningHighlight" + index
227 width: units.gu(0.25)
229 width: units.gu(0.25)
qml/Launcher/LauncherPanel.qml+1
@@ -239,6 +239,7 @@ Rectangle {
239 alerting: model.alerting
239 alerting: model.alerting
240 highlighted: root.highlightIndex == index
240 highlighted: root.highlightIndex == index
241 shortcutHintShown: root.shortcutHintsShown && index <= 9
241 shortcutHintShown: root.shortcutHintsShown && index <= 9
242+ surfaceCount: model.surfaceCount
242 z: -Math.abs(offset)
243 z: -Math.abs(offset)
243 maxAngle: 55
244 maxAngle: 55
244 property bool dragging: false
245 property bool dragging: false
tests/mocks/Unity/Application/ApplicationInfo.cpp+26−25
@@ -55,8 +55,9 @@ QString stateToStr(ApplicationInfo::State state)
55ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
55ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
56 : ApplicationInfoInterface(appId, parent)
56 : ApplicationInfoInterface(appId, parent)
57 , m_appId(appId)
57 , m_appId(appId)
58+ , m_surfaceList(new MirSurfaceListModel(this))
58{
59{
59− connect(&m_surfaceList, &MirSurfaceListModel::countChanged,
60+ connect(m_surfaceList, &MirSurfaceListModel::countChanged,
60 this, &ApplicationInfo::onSurfaceCountChanged, Qt::QueuedConnection);
61 this, &ApplicationInfo::onSurfaceCountChanged, Qt::QueuedConnection);
61
62
62 m_surfaceCreationTimer.setSingleShot(true);
63 m_surfaceCreationTimer.setSingleShot(true);
@@ -78,8 +79,8 @@ void ApplicationInfo::createSurface()
78 if (state() == ApplicationInfo::Stopped) { return; }
79 if (state() == ApplicationInfo::Stopped) { return; }
79
80
80 QString surfaceName = name();
81 QString surfaceName = name();
81− if (m_surfaceList.count() > 0) {
82+ if (m_surfaceList->count() > 0) {
82− surfaceName.append(QString(" %1").arg(m_surfaceList.count()+1));
83+ surfaceName.append(QString(" %1").arg(m_surfaceList->count()+1));
83 }
84 }
84
85
85 auto surfaceManager = SurfaceManager::instance();
86 auto surfaceManager = SurfaceManager::instance();
@@ -95,7 +96,7 @@ void ApplicationInfo::createSurface()
95
96
96 surface->setShellChrome(m_shellChrome);
97 surface->setShellChrome(m_shellChrome);
97
98
98− m_surfaceList.appendSurface(surface);
99+ m_surfaceList->appendSurface(surface);
99
100
100 ++m_liveSurfaceCount;
101 ++m_liveSurfaceCount;
101 connect(surface, &MirSurface::liveChanged, this, [this, surface](){
102 connect(surface, &MirSurface::liveChanged, this, [this, surface](){
@@ -186,12 +187,12 @@ void ApplicationInfo::setState(State value)
186 if (value != m_state) {
187 if (value != m_state) {
187 DEBUG_MSG(qPrintable(stateToStr(value)));
188 DEBUG_MSG(qPrintable(stateToStr(value)));
188 if (!m_manualSurfaceCreation && value == ApplicationInfo::Starting) {
189 if (!m_manualSurfaceCreation && value == ApplicationInfo::Starting) {
189− Q_ASSERT(m_surfaceList.count() == 0);
190+ Q_ASSERT(m_surfaceList->count() == 0);
190 m_surfaceCreationTimer.start();
191 m_surfaceCreationTimer.start();
191 } else if (value == ApplicationInfo::Stopped) {
192 } else if (value == ApplicationInfo::Stopped) {
192 m_surfaceCreationTimer.stop();
193 m_surfaceCreationTimer.stop();
193− for (int i = 0; i < m_surfaceList.count(); ++i) {
194+ for (int i = 0; i < m_surfaceList->count(); ++i) {
194− MirSurface *surface = static_cast<MirSurface*>(m_surfaceList.get(i));
195+ MirSurface *surface = static_cast<MirSurface*>(m_surfaceList->get(i));
195 surface->setLive(false);
196 surface->setLive(false);
196 }
197 }
197 }
198 }
@@ -205,9 +206,9 @@ void ApplicationInfo::close()
205{
206{
206 DEBUG_MSG("");
207 DEBUG_MSG("");
207
208
208− if (m_surfaceList.count() > 0) {
209+ if (m_surfaceList->count() > 0) {
209− for (int i = 0; i < m_surfaceList.count(); ++i) {
210+ for (int i = 0; i < m_surfaceList->count(); ++i) {
210− MirSurface *surface = static_cast<MirSurface*>(m_surfaceList.get(i));
211+ MirSurface *surface = static_cast<MirSurface*>(m_surfaceList->get(i));
211 surface->close();
212 surface->close();
212 }
213 }
213 } else {
214 } else {
@@ -219,15 +220,15 @@ void ApplicationInfo::close()
219void ApplicationInfo::setFullscreen(bool value)
220void ApplicationInfo::setFullscreen(bool value)
220{
221{
221 m_fullscreen = value;
222 m_fullscreen = value;
222− if (m_surfaceList.rowCount() > 0) {
223+ if (m_surfaceList->rowCount() > 0) {
223− m_surfaceList.get(0)->setState(Mir::FullscreenState);
224+ m_surfaceList->get(0)->setState(Mir::FullscreenState);
224 }
225 }
225}
226}
226
227
227bool ApplicationInfo::fullscreen() const
228bool ApplicationInfo::fullscreen() const
228{
229{
229− if (m_surfaceList.rowCount() > 0) {
230+ if (m_surfaceList->rowCount() > 0) {
230− return m_surfaceList.get(0)->state() == Mir::FullscreenState;
231+ return m_surfaceList->get(0)->state() == Mir::FullscreenState;
231 } else {
232 } else {
232 return m_fullscreen;
233 return m_fullscreen;
233 }
234 }
@@ -333,16 +334,16 @@ void ApplicationInfo::setInitialSurfaceSize(const QSize &size)
333void ApplicationInfo::setShellChrome(Mir::ShellChrome shellChrome)
334void ApplicationInfo::setShellChrome(Mir::ShellChrome shellChrome)
334{
335{
335 m_shellChrome = shellChrome;
336 m_shellChrome = shellChrome;
336− if (m_surfaceList.rowCount() > 0) {
337+ if (m_surfaceList->rowCount() > 0) {
337− static_cast<MirSurface*>(m_surfaceList.get(0))->setShellChrome(shellChrome);
338+ static_cast<MirSurface*>(m_surfaceList->get(0))->setShellChrome(shellChrome);
338 }
339 }
339}
340}
340
341
341bool ApplicationInfo::focused() const
342bool ApplicationInfo::focused() const
342{
343{
343 bool someSurfaceHasFocus = false; // to be proven wrong
344 bool someSurfaceHasFocus = false; // to be proven wrong
344− for (int i = 0; i < m_surfaceList.count() && !someSurfaceHasFocus; ++i) {
345+ for (int i = 0; i < m_surfaceList->count() && !someSurfaceHasFocus; ++i) {
345− someSurfaceHasFocus = m_surfaceList.get(i)->focused();
346+ someSurfaceHasFocus = m_surfaceList->get(i)->focused();
346 }
347 }
347 return someSurfaceHasFocus;
348 return someSurfaceHasFocus;
348}
349}
@@ -354,12 +355,12 @@ void ApplicationInfo::setFocused(bool value)
354 }
355 }
355
356
356 if (value) {
357 if (value) {
357− if (m_surfaceList.count() > 0) {
358+ if (m_surfaceList->count() > 0) {
358− m_surfaceList.get(0)->requestFocus();
359+ m_surfaceList->get(0)->requestFocus();
359 }
360 }
360 } else {
361 } else {
361− for (int i = 0; i < m_surfaceList.count(); ++i) {
362+ for (int i = 0; i < m_surfaceList->count(); ++i) {
362− MirSurface *surface = static_cast<MirSurface*>(m_surfaceList.get(i));
363+ MirSurface *surface = static_cast<MirSurface*>(m_surfaceList->get(i));
363 if (surface->focused()) {
364 if (surface->focused()) {
364 surface->setFocused(false);
365 surface->setFocused(false);
365 }
366 }
@@ -369,16 +370,16 @@ void ApplicationInfo::setFocused(bool value)
369
370
370void ApplicationInfo::onSurfaceCountChanged()
371void ApplicationInfo::onSurfaceCountChanged()
371{
372{
372− if (m_surfaceList.count() == 0 && m_state == Running) {
373+ if (m_surfaceList->count() == 0 && m_state == Running) {
373 setState(Stopped);
374 setState(Stopped);
374 }
375 }
375}
376}
376
377
377void ApplicationInfo::requestFocus()
378void ApplicationInfo::requestFocus()
378{
379{
379− if (m_surfaceList.count() == 0) {
380+ if (m_surfaceList->count() == 0) {
380 Q_EMIT focusRequested();
381 Q_EMIT focusRequested();
381 } else {
382 } else {
382− m_surfaceList.get(0)->requestFocus();
383+ m_surfaceList->get(0)->requestFocus();
383 }
384 }
384}
385}
tests/mocks/Unity/Application/ApplicationInfo.h+3−2
@@ -107,7 +107,8 @@ public:
107
107
108 Q_INVOKABLE void setShellChrome(Mir::ShellChrome shellChrome);
108 Q_INVOKABLE void setShellChrome(Mir::ShellChrome shellChrome);
109
109
110− MirSurfaceListInterface* surfaceList() override { return &m_surfaceList; }
110+ MirSurfaceListInterface* surfaceList() const override { return m_surfaceList; }
111+ int surfaceCount() const override { return m_surfaceList->count(); }
111
112
112 void setFocused(bool value);
113 void setFocused(bool value);
113
114
@@ -147,7 +148,7 @@ private:
147 bool m_isTouchApp{true};
148 bool m_isTouchApp{true};
148 bool m_exemptFromLifecycle{false};
149 bool m_exemptFromLifecycle{false};
149 QSize m_initialSurfaceSize;
150 QSize m_initialSurfaceSize;
150− MirSurfaceListModel m_surfaceList;
151+ MirSurfaceListModel *m_surfaceList;
151 int m_liveSurfaceCount{0};
152 int m_liveSurfaceCount{0};
152 QTimer m_surfaceCreationTimer;
153 QTimer m_surfaceCreationTimer;
153 QList<MirSurface*> m_closingSurfaces;
154 QList<MirSurface*> m_closingSurfaces;
tests/mocks/Unity/Application/MirSurfaceListModel.cpp+2−2
@@ -66,7 +66,7 @@ void MirSurfaceListModel::appendSurface(MirSurface *surface)
66 m_surfaceList.append(surface);
66 m_surfaceList.append(surface);
67 connectSurface(surface);
67 connectSurface(surface);
68 endInsertRows();
68 endInsertRows();
69− Q_EMIT countChanged();
69+ Q_EMIT countChanged(m_surfaceList.count());
70}
70}
71
71
72void MirSurfaceListModel::connectSurface(MirSurface *surface)
72void MirSurfaceListModel::connectSurface(MirSurface *surface)
@@ -82,7 +82,7 @@ void MirSurfaceListModel::removeSurface(MirSurface *surface)
82 beginRemoveRows(QModelIndex(), i, i);
82 beginRemoveRows(QModelIndex(), i, i);
83 m_surfaceList.removeAt(i);
83 m_surfaceList.removeAt(i);
84 endRemoveRows();
84 endRemoveRows();
85− Q_EMIT countChanged();
85+ Q_EMIT countChanged(m_surfaceList.count());
86 }
86 }
87}
87}
88
88
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=8)
2
2
3include_directories(
3include_directories(
4 ${CMAKE_CURRENT_SOURCE_DIR}
4 ${CMAKE_CURRENT_SOURCE_DIR}
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+14
@@ -38,6 +38,7 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
38 m_countVisible(false),
38 m_countVisible(false),
39 m_focused(false),
39 m_focused(false),
40 m_alerting(false),
40 m_alerting(false),
41+ m_surfaceCount(0),
41 m_quickList(new MockQuickListModel(this))
42 m_quickList(new MockQuickListModel(this))
42{
43{
43}
44}
@@ -182,6 +183,19 @@ void MockLauncherItem::setAlerting(bool alerting)
182 }
183 }
183}
184}
184
185
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+
185unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
199unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
186{
200{
187 return m_quickList;
201 return m_quickList;
tests/mocks/Unity/Launcher/MockLauncherItem.h+3
@@ -46,6 +46,7 @@ public:
46 bool countVisible() const override;
46 bool countVisible() const override;
47 bool focused() const override;
47 bool focused() const override;
48 bool alerting() const override;
48 bool alerting() const override;
49+ int surfaceCount() const override;
49
50
50 unity::shell::launcher::QuickListModelInterface *quickList() const override;
51 unity::shell::launcher::QuickListModelInterface *quickList() const override;
51
52
@@ -58,6 +59,7 @@ private:
58 void setCountVisible(bool countVisible);
59 void setCountVisible(bool countVisible);
59 void setFocused(bool focused);
60 void setFocused(bool focused);
60 void setAlerting(bool alerting);
61 void setAlerting(bool alerting);
62+ void setSurfaceCount(int surfaceCount);
61
63
62 QString m_appId;
64 QString m_appId;
63 QString m_desktopFile;
65 QString m_desktopFile;
@@ -71,6 +73,7 @@ private:
71 bool m_countVisible;
73 bool m_countVisible;
72 bool m_focused;
74 bool m_focused;
73 bool m_alerting;
75 bool m_alerting;
76+ int m_surfaceCount;
74 MockQuickListModel *m_quickList;
77 MockQuickListModel *m_quickList;
75
78
76 friend class MockLauncherModel;
79 friend class MockLauncherModel;
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+5
@@ -25,6 +25,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
25 MockLauncherItem *item = new MockLauncherItem("dialer-app", "/usr/share/applications/dialer-app.desktop", "Dialer", "dialer-app", this);
25 MockLauncherItem *item = new MockLauncherItem("dialer-app", "/usr/share/applications/dialer-app.desktop", "Dialer", "dialer-app", this);
26 item->setProgress(0);
26 item->setProgress(0);
27 item->setPinned(true);
27 item->setPinned(true);
28+ item->setSurfaceCount(1);
28 item->setRunning(true);
29 item->setRunning(true);
29 item->setFocused(true);
30 item->setFocused(true);
30 m_list.append(item);
31 m_list.append(item);
@@ -36,6 +37,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
36 item->setProgress(50);
37 item->setProgress(50);
37 item->setCountVisible(true);
38 item->setCountVisible(true);
38 item->setRunning(true);
39 item->setRunning(true);
40+ item->setSurfaceCount(2);
39 item->setAlerting(false);
41 item->setAlerting(false);
40 m_list.append(item);
42 m_list.append(item);
41 item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
43 item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
@@ -44,6 +46,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
44 item->setProgress(150);
46 item->setProgress(150);
45 m_list.append(item);
47 m_list.append(item);
46 item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this);
48 item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this);
49+ item->setSurfaceCount(5);
47 item->setCount(1);
50 item->setCount(1);
48 item->setCountVisible(true);
51 item->setCountVisible(true);
49 item->setRunning(true);
52 item->setRunning(true);
@@ -119,6 +122,8 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
119 return item->focused();
122 return item->focused();
120 case RoleAlerting:
123 case RoleAlerting:
121 return item->alerting();
124 return item->alerting();
125+ case RoleSurfaceCount:
126+ return item->surfaceCount();
122 }
127 }
123
128
124 return QVariant();
129 return QVariant();
tests/plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,5 +1,5 @@
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1pkg_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)
3
3
4include_directories(
4include_directories(
5 ${CMAKE_CURRENT_SOURCE_DIR}
5 ${CMAKE_CURRENT_SOURCE_DIR}
tests/plugins/Unity/Launcher/launchermodeltest.cpp+13−1
@@ -66,13 +66,16 @@ public:
66 void setExemptFromLifecycle(bool) override {}
66 void setExemptFromLifecycle(bool) override {}
67 QSize initialSurfaceSize() const override { return QSize(); }
67 QSize initialSurfaceSize() const override { return QSize(); }
68 void setInitialSurfaceSize(const QSize &) override {}
68 void setInitialSurfaceSize(const QSize &) override {}
69− MirSurfaceListInterface* surfaceList() override { return nullptr; }
69+ MirSurfaceListInterface* surfaceList() const override { return nullptr; }
70+ int surfaceCount() const override { return m_surfaceCount; }
71+ void setSurfaceCount(int count) { m_surfaceCount = count; Q_EMIT surfaceCountChanged(count); }
70
72
71 // Methods used for mocking (not in the interface)
73 // Methods used for mocking (not in the interface)
72 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
74 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
73private:
75private:
74 QString m_appId;
76 QString m_appId;
75 bool m_focused;
77 bool m_focused;
78+ int m_surfaceCount = 0;
76};
79};
77
80
78// This is a mock, specifically to test the LauncherModel
81// This is a mock, specifically to test the LauncherModel
@@ -691,6 +694,15 @@ private Q_SLOTS:
691 QCOMPARE(getASConfig().at(index).value("countVisible").toBool(), true);
694 QCOMPARE(getASConfig().at(index).value("countVisible").toBool(), true);
692 QCOMPARE(getASConfig().at(index).value("count").toInt(), 55);
695 QCOMPARE(getASConfig().at(index).value("count").toInt(), 55);
693 }
696 }
697+
698+ void testSurfaceCountUpdates() {
699+ QString appId = launcherModel->get(0)->appId();
700+
701+ QCOMPARE(launcherModel->get(0)->surfaceCount(), 0);
702+ MockApp *app = qobject_cast<MockApp*>(appManager->findApplication(appId));
703+ app->setSurfaceCount(1);
704+ QCOMPARE(launcherModel->get(0)->surfaceCount(), 1);
705+ }
694};
706};
695
707
696QTEST_GUILESS_MAIN(LauncherModelTest)
708QTEST_GUILESS_MAIN(LauncherModelTest)
tests/qmltests/Launcher/tst_Launcher.qml+15
@@ -1283,5 +1283,20 @@ Rectangle {
1283
1283
1284 assertFocusOnIndex(-2);
1284 assertFocusOnIndex(-2);
1285 }
1285 }
1286+
1287+ function test_surfaceCountPips() {
1288+ var launcherListView = findChild(launcher, "launcherListView")
1289+ var moveAnimation = findInvisibleChild(launcherListView, "moveAnimation")
1290+
1291+ for (var i = 0; i < launcherListView.count; i++) {
1292+ launcherListView.moveToIndex(i);
1293+ waitForRendering(launcherListView);
1294+ tryCompare(moveAnimation, "running", false);
1295+
1296+ var delegate = findChild(launcher, "launcherDelegate" + i);
1297+ var surfacePipRepeater = findInvisibleChild(delegate, "surfacePipRepeater");
1298+ compare(surfacePipRepeater.model, Math.min(3, LauncherModel.get(i).surfaceCount))
1299+ }
1300+ }
1286 }
1301 }
1287}
1302}