on xenial help sign in
add surface titles to launcher's quicklist
ae9bc90Michael Zanetti
plugins/Unity/Launcher/launcheritem.cpp+27−6
@@ -35,7 +35,6 @@ 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),
39 m_quickList(new QuickListModel(this))
38 m_quickList(new QuickListModel(this))
40{
39{
41 Q_ASSERT(parent != nullptr);
40 Q_ASSERT(parent != nullptr);
@@ -223,14 +222,36 @@ void LauncherItem::setAlerting(bool alerting)
223
222
224int LauncherItem::surfaceCount() const
223int LauncherItem::surfaceCount() const
225{
224{
226− return m_surfaceCount;
225+ return m_surfaces.count();
227}
226}
228
227
229−void LauncherItem::setSurfaceCount(int surfaceCount)
228+void LauncherItem::setSurfaces(const QList<QPair<QString, QString> > &surfaces)
230{
229{
231− if (m_surfaceCount != surfaceCount) {
230+ if (m_surfaces != surfaces) {
232− m_surfaceCount = surfaceCount;
231+ m_surfaces = surfaces;
232+
233+ QList<QuickListEntry> removedEntries;
234+ for (int i = 0; i < m_quickList->rowCount(); ++i) {
235+ QuickListEntry entry = m_quickList->get(i);
236+ if (entry.actionId().startsWith(QStringLiteral("surface_"))) {
237+ removedEntries.append(entry);
238+ }
239+ }
240+ Q_FOREACH (const QuickListEntry &entry, removedEntries) {
241+ m_quickList->removeAction(entry);
242+ }
243+ for (int i = 0; i < surfaces.count(); ++i) {
244+ QuickListEntry entry;
245+ entry.setActionId(QStringLiteral("surface_") + surfaces.at(i).first);
246+ entry.setText(surfaces.at(i).second);
247+ entry.setIsPrivate(true);
248+ if (i == surfaces.count() - 1) {
249+ entry.setHasSeparator(true);
250+ }
251+ m_quickList->insertAction(entry, i + 1);
252+ }
253+
233− Q_EMIT surfaceCountChanged(surfaceCount);
254+ Q_EMIT surfaceCountChanged(m_surfaces.count());
234 }
255 }
235}
256}
236
257
plugins/Unity/Launcher/launcheritem.h+3−2
@@ -23,6 +23,7 @@
23#include "quicklistmodel.h"
23#include "quicklistmodel.h"
24
24
25#include <unity/shell/launcher/LauncherItemInterface.h>
25#include <unity/shell/launcher/LauncherItemInterface.h>
26+#include <unity/shell/application/MirSurfaceInterface.h>
26
27
27class QuickListModel;
28class QuickListModel;
28
29
@@ -62,7 +63,7 @@ private:
62 void setCountVisible(bool countVisible);
63 void setCountVisible(bool countVisible);
63 void setFocused(bool focused);
64 void setFocused(bool focused);
64 void setAlerting(bool alerting);
65 void setAlerting(bool alerting);
65− void setSurfaceCount(int surfaceCount);
66+ void setSurfaces(const QList<QPair<QString, QString >> &surfaces);
66
67
67private:
68private:
68 QString m_appId;
69 QString m_appId;
@@ -77,7 +78,7 @@ private:
77 bool m_countVisible;
78 bool m_countVisible;
78 bool m_focused;
79 bool m_focused;
79 bool m_alerting;
80 bool m_alerting;
80− int m_surfaceCount;
81+ QList<QPair<QString, QString> > m_surfaces;
81 QuickListModel *m_quickList;
82 QuickListModel *m_quickList;
82 QuickListEntry m_quitAction;
83 QuickListEntry m_quitAction;
83
84
plugins/Unity/Launcher/launchermodel.cpp+20−9
@@ -204,6 +204,19 @@ void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex
204 if (m_appManager) {
204 if (m_appManager) {
205 m_appManager->stopApplication(appId);
205 m_appManager->stopApplication(appId);
206 }
206 }
207+ } else if (actionId.startsWith("surface_")){
208+ ApplicationInfoInterface *appInfo = m_appManager->findApplication(appId);
209+ if (!appInfo) {
210+ qWarning() << "App for" << appId << "not found in launcher. Cannot invoke quicklist action";
211+ }
212+ for (int i = 0; i < appInfo->surfaceList()->count(); ++i) {
213+ MirSurfaceInterface *iface = appInfo->surfaceList()->get(i);
214+ QString id = actionId;
215+ id.remove(QRegExp("^surface_"));
216+ if (id == iface->persistentId()) {
217+ iface->activate();
218+ }
219+ }
207 // Nope, we don't know this action, let the backend forward it to the application
220 // Nope, we don't know this action, let the backend forward it to the application
208 } else {
221 } else {
209 // TODO: forward quicklist action to app, possibly via m_dbusIface
222 // TODO: forward quicklist action to app, possibly via m_dbusIface
@@ -517,18 +530,12 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
517 item->setRecent(true);
530 item->setRecent(true);
518 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
531 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
519 }
532 }
520− if (item->surfaceCount() != app->surfaceCount()) {
521− item->setSurfaceCount(app->surfaceCount());
522− Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleSurfaceCount});
523− }
524−
525 item->setRunning(true);
533 item->setRunning(true);
526 } else {
534 } else {
527 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
535 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
528 item->setRecent(true);
536 item->setRecent(true);
529 item->setRunning(true);
537 item->setRunning(true);
530 item->setFocused(app->focused());
538 item->setFocused(app->focused());
531− item->setSurfaceCount(app->surfaceCount());
532 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
539 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
533 m_list.append(item);
540 m_list.append(item);
534 endInsertRows();
541 endInsertRows();
@@ -540,6 +547,7 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
540
547
541void LauncherModel::applicationSurfaceCountChanged(int count)
548void LauncherModel::applicationSurfaceCountChanged(int count)
542{
549{
550+ Q_UNUSED(count)
543 ApplicationInfoInterface *app = static_cast<ApplicationInfoInterface*>(sender());
551 ApplicationInfoInterface *app = static_cast<ApplicationInfoInterface*>(sender());
544 int idx = findApplication(app->appId());
552 int idx = findApplication(app->appId());
545 if (idx < 0) {
553 if (idx < 0) {
@@ -547,10 +555,13 @@ void LauncherModel::applicationSurfaceCountChanged(int count)
547 return;
555 return;
548 }
556 }
549 LauncherItem *item = m_list.at(idx);
557 LauncherItem *item = m_list.at(idx);
550− if (item->surfaceCount() != count) {
558+ QList<QPair<QString, QString> > surfaces;
551− item->setSurfaceCount(count);
559+ for (int i = 0; i < app->surfaceList()->count(); ++i) {
552− Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
560+ MirSurfaceInterface* iface = app->surfaceList()->get(i);
561+ surfaces.append(qMakePair<QString, QString>(iface->persistentId(), iface->name()));
553 }
562 }
563+ item->setSurfaces(surfaces);
564+ Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
554}
565}
555
566
556void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
567void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
plugins/Unity/Launcher/quicklistmodel.cpp+7
@@ -37,6 +37,13 @@ void QuickListModel::appendAction(const QuickListEntry &entry)
37 endInsertRows();
37 endInsertRows();
38}
38}
39
39
40+void QuickListModel::insertAction(const QuickListEntry &entry, int index)
41+{
42+ beginInsertRows(QModelIndex(), index, index);
43+ m_list.insert(index, entry);
44+ endInsertRows();
45+}
46+
40void QuickListModel::updateAction(const QuickListEntry &entry)
47void QuickListModel::updateAction(const QuickListEntry &entry)
41{
48{
42 for (int i = 0; i < m_list.count(); ++i) {
49 for (int i = 0; i < m_list.count(); ++i) {
plugins/Unity/Launcher/quicklistmodel.h+1
@@ -36,6 +36,7 @@ public:
36 ~QuickListModel();
36 ~QuickListModel();
37
37
38 void appendAction(const QuickListEntry &entry);
38 void appendAction(const QuickListEntry &entry);
39+ void insertAction(const QuickListEntry &entry, int index);
39
40
40 /**
41 /**
41 * @brief Update an existing action
42 * @brief Update an existing action
tests/plugins/Unity/Launcher/CMakeLists.txt+3
@@ -34,6 +34,9 @@ add_executable(launchermodeltestExec
34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
36 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
36 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
37+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
38+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
39+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
37 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
40 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
38 )
41 )
39target_link_libraries(launchermodeltestExec
42target_link_libraries(launchermodeltestExec
tests/plugins/Unity/Launcher/launchermodeltest.cpp+80−6
@@ -17,6 +17,7 @@
17// unity-api
17// unity-api
18#include <unity/shell/launcher/LauncherModelInterface.h>
18#include <unity/shell/launcher/LauncherModelInterface.h>
19#include <unity/shell/application/ApplicationInfoInterface.h>
19#include <unity/shell/application/ApplicationInfoInterface.h>
20+#include <unity/shell/application/MirSurfaceListInterface.h>
20
21
21#include "launcheritem.h"
22#include "launcheritem.h"
22#include "launchermodel.h"
23#include "launchermodel.h"
@@ -37,11 +38,72 @@
37namespace unityapi = unity::shell::application;
38namespace unityapi = unity::shell::application;
38
39
39// This is a mock, specifically to test the LauncherModel
40// This is a mock, specifically to test the LauncherModel
41+class MockSurface: public unity::shell::application::MirSurfaceInterface
42+{
43+ Q_OBJECT
44+public:
45+ MockSurface(const QString &id, QObject* parent): unityapi::MirSurfaceInterface(parent), m_id(id) {}
46+ Mir::Type type() const override { return Mir::NormalType;}
47+ QString name() const override { return QStringLiteral("mock surface"); }
48+ QString persistentId() const override { return m_id; }
49+ QPoint position() const override { return QPoint(); }
50+ QSize size() const override { return QSize(); }
51+ void resize(const QSize &size) override { Q_UNUSED(size) }
52+ void resize(int width, int height) override { Q_UNUSED(width); Q_UNUSED(height) }
53+ Mir::State state() const override { return Mir::RestoredState; }
54+ bool live() const override { return true; }
55+ bool visible() const override { return true; }
56+ Mir::OrientationAngle orientationAngle() const override { return Mir::Angle0; }
57+ void setOrientationAngle(Mir::OrientationAngle angle) override { Q_UNUSED(angle); }
58+ int minimumWidth() const override { return 0; }
59+ int minimumHeight() const override { return 0; }
60+ int maximumWidth() const override { return 0; }
61+ int maximumHeight() const override { return 0; }
62+ int widthIncrement() const override { return 0; }
63+ int heightIncrement() const override { return 0; }
64+ void setKeymap(const QString &) override {}
65+ Mir::ShellChrome shellChrome() const override { return Mir::NormalChrome; }
66+ QString keymap() const override { return QStringLiteral("de_DE"); }
67+ bool focused() const override { return true; }
68+ QRect inputBounds() const override { return QRect(); }
69+ bool confinesMousePointer() const override { return false; }
70+ QPoint requestedPosition() const override { return QPoint(); }
71+ void setRequestedPosition(const QPoint &) override {}
72+ MirSurfaceInterface* parentSurface() const override { return nullptr; }
73+ MirSurfaceListInterface* childSurfaceList() const override { return nullptr; }
74+ void close() override {}
75+ void activate() override {}
76+ void requestState(Mir::State) override {}
77+
78+private:
79+ QString m_id;
80+};
81+
82+class MockSurfaceList: public unity::shell::application::MirSurfaceListInterface
83+{
84+ Q_OBJECT
85+public:
86+ MockSurfaceList(QObject *parent): unityapi::MirSurfaceListInterface(parent) {}
87+ int rowCount(const QModelIndex & = QModelIndex()) const override { return m_list.count(); }
88+ QVariant data(const QModelIndex &, int) const override { return QVariant(); }
89+ Q_INVOKABLE MirSurfaceInterface* get(int index) override { return m_list.at(index); }
90+ void append(MirSurfaceInterface* surface) {
91+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
92+ m_list.append(surface);
93+ endInsertRows();
94+ }
95+private:
96+ QList<MirSurfaceInterface*> m_list;
97+
98+};
99+
40class MockApp: public unity::shell::application::ApplicationInfoInterface
100class MockApp: public unity::shell::application::ApplicationInfoInterface
41{
101{
42 Q_OBJECT
102 Q_OBJECT
43public:
103public:
44− MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) { }
104+ MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) {
105+ m_surfaces = new MockSurfaceList(this);
106+ }
45
107
46 RequestedState requestedState() const override { return RequestedRunning; }
108 RequestedState requestedState() const override { return RequestedRunning; }
47 void setRequestedState(RequestedState) override {}
109 void setRequestedState(RequestedState) override {}
@@ -64,10 +126,10 @@ public:
64 void setExemptFromLifecycle(bool) override {}
126 void setExemptFromLifecycle(bool) override {}
65 QSize initialSurfaceSize() const override { return QSize(); }
127 QSize initialSurfaceSize() const override { return QSize(); }
66 void setInitialSurfaceSize(const QSize &) override {}
128 void setInitialSurfaceSize(const QSize &) override {}
67− MirSurfaceListInterface* surfaceList() const override { return nullptr; }
129+ MirSurfaceListInterface* surfaceList() const override { return m_surfaces; }
68 MirSurfaceListInterface* promptSurfaceList() const override { return nullptr; }
130 MirSurfaceListInterface* promptSurfaceList() const override { return nullptr; }
69− int surfaceCount() const override { return m_surfaceCount; }
131+ int surfaceCount() const override { return m_surfaces->count(); }
70− void setSurfaceCount(int count) { m_surfaceCount = count; Q_EMIT surfaceCountChanged(count); }
132+ void setSurfaces(MockSurfaceList* surfaces) { m_surfaces = surfaces; Q_EMIT surfaceCountChanged(m_surfaces->count()); }
71 void close() override {}
133 void close() override {}
72
134
73 // Methods used for mocking (not in the interface)
135 // Methods used for mocking (not in the interface)
@@ -75,7 +137,7 @@ public:
75private:
137private:
76 QString m_appId;
138 QString m_appId;
77 bool m_focused;
139 bool m_focused;
78− int m_surfaceCount = 0;
140+ MockSurfaceList *m_surfaces;
79};
141};
80
142
81// This is a mock, specifically to test the LauncherModel
143// This is a mock, specifically to test the LauncherModel
@@ -748,8 +810,20 @@ private Q_SLOTS:
748
810
749 QCOMPARE(launcherModel->get(0)->surfaceCount(), 0);
811 QCOMPARE(launcherModel->get(0)->surfaceCount(), 0);
750 MockApp *app = qobject_cast<MockApp*>(appManager->findApplication(appId));
812 MockApp *app = qobject_cast<MockApp*>(appManager->findApplication(appId));
751− app->setSurfaceCount(1);
813+ MockSurfaceList* surfaces = new MockSurfaceList(appManager);
814+ surfaces->append(new MockSurface("foobar", surfaces));
815+ app->setSurfaces(surfaces);
752 QCOMPARE(launcherModel->get(0)->surfaceCount(), 1);
816 QCOMPARE(launcherModel->get(0)->surfaceCount(), 1);
817+
818+ // Make sure the new surface appears in the quicklist
819+ QuickListModel *quickList = qobject_cast<QuickListModel*>(launcherModel->get(0)->quickList());
820+ bool found = false;
821+ for (int i = 0; i < quickList->rowCount(); ++i) {
822+ if (quickList->get(i).actionId() == "surface_foobar") {
823+ found = true;
824+ }
825+ }
826+ QCOMPARE(found, true);
753 }
827 }
754};
828};
755
829