on xenial help sign in
merge ../allowClientResize
2a9c520Daniel d'Andrada
CMakeLists.txt+2−2
@@ -70,11 +70,11 @@ find_package(Qt5DBus 5.6 REQUIRED)
70find_package(Qt5Concurrent 5.6 REQUIRED)
70find_package(Qt5Concurrent 5.6 REQUIRED)
71find_package(Qt5Sql 5.6 REQUIRED)
71find_package(Qt5Sql 5.6 REQUIRED)
72
72
73−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=26)
73+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=27)
74pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
74pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
75pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
75pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
76pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
76pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
77−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
77+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=12)
78pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
78pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
79pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0)
79pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0)
80pkg_check_modules(UAL REQUIRED ubuntu-app-launch-3)
80pkg_check_modules(UAL REQUIRED ubuntu-app-launch-3)
debian/control+5−5
@@ -38,7 +38,7 @@ Build-Depends: cmake,
38 libubuntugestures5-private-dev (>= 1.3.2030),
38 libubuntugestures5-private-dev (>= 1.3.2030),
39 libudev-dev,
39 libudev-dev,
40 libudm-common-dev,
40 libudm-common-dev,
41− libunity-api-dev (>= 8.2),
41+ libunity-api-dev (>= 8.6),
42 libusermetricsoutput1-dev,
42 libusermetricsoutput1-dev,
43# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
43# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
44 libx11-dev[!arm64 !armhf],
44 libx11-dev[!arm64 !armhf],
@@ -132,7 +132,7 @@ Depends: dmz-cursor-theme,
132 qtdeclarative5-qtmir-plugin (>= 0.4.8),
132 qtdeclarative5-qtmir-plugin (>= 0.4.8),
133 qtdeclarative5-ubuntu-telephony0.1,
133 qtdeclarative5-ubuntu-telephony0.1,
134 ubuntu-system-settings (>= 0.4),
134 ubuntu-system-settings (>= 0.4),
135− unity-launcher-impl-10,
135+ unity-launcher-impl-12,
136 unity8-common (= ${source:Version}),
136 unity8-common (= ${source:Version}),
137 unity8-private (= ${binary:Version}),
137 unity8-private (= ${binary:Version}),
138 unity8-private | unity-launcher-impl,
138 unity8-private | unity-launcher-impl,
@@ -162,7 +162,7 @@ Depends: qml-module-qtquick-layouts,
162 qttranslations5-l10n,
162 qttranslations5-l10n,
163 ubuntu-thumbnailer-impl-0,
163 ubuntu-thumbnailer-impl-0,
164 ubuntu-wallpapers,
164 ubuntu-wallpapers,
165− unity-application-impl-26,
165+ unity-application-impl-27,
166 unity-notifications-impl-3,
166 unity-notifications-impl-3,
167 unity-plugin-scopes | unity-scopes-impl,
167 unity-plugin-scopes | unity-scopes-impl,
168 unity-scopes-impl-12,
168 unity-scopes-impl-12,
@@ -212,7 +212,7 @@ Depends: dbus-test-runner,
212 ${misc:Depends},
212 ${misc:Depends},
213 ${shlibs:Depends},
213 ${shlibs:Depends},
214Provides: unity-application-impl,
214Provides: unity-application-impl,
215− unity-application-impl-26,
215+ unity-application-impl-27,
216 unity8-fake-env,
216 unity8-fake-env,
217Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1),
217Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1),
218 unity8-fake-env,
218 unity8-fake-env,
@@ -235,7 +235,7 @@ Depends: accountsservice-ubuntu-schemas (>= 0.0.7),
235 ${misc:Depends},
235 ${misc:Depends},
236 ${shlibs:Depends},
236 ${shlibs:Depends},
237Provides: unity-launcher-impl,
237Provides: unity-launcher-impl,
238− unity-launcher-impl-10,
238+ unity-launcher-impl-12,
239Description: Unity 8 private libs
239Description: Unity 8 private libs
240 The Unity 8 shell is the primary user interface for Ubuntu devices.
240 The Unity 8 shell is the primary user interface for Ubuntu devices.
241 .
241 .
plugins/Greeter/Unity/Launcher/quicklistmodel.cpp+2
@@ -65,6 +65,8 @@ QVariant QuickListModel::data(const QModelIndex &index, int role) const
65 return m_list.at(index.row()).icon();
65 return m_list.at(index.row()).icon();
66 case RoleClickable:
66 case RoleClickable:
67 return m_list.at(index.row()).clickable();
67 return m_list.at(index.row()).clickable();
68+ case RoleIsPrivate:
69+ return false; // The greeter plugin would just not add any private entries
68 }
70 }
69 return QVariant();
71 return QVariant();
70}
72}
plugins/Unity/Launcher/CMakeLists.txt+2
@@ -30,6 +30,8 @@ set(QMLLAUNCHERPLUGIN_SRC
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
33+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
34+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
33 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
36 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
37 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
plugins/Unity/Launcher/launcheritem.cpp+30−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);
@@ -48,11 +47,13 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
48 QuickListEntry pinningAction;
47 QuickListEntry pinningAction;
49 pinningAction.setActionId(QStringLiteral("pin_item"));
48 pinningAction.setActionId(QStringLiteral("pin_item"));
50 pinningAction.setText(gettext("Pin shortcut"));
49 pinningAction.setText(gettext("Pin shortcut"));
50+ pinningAction.setIsPrivate(true);
51 m_quickList->appendAction(pinningAction);
51 m_quickList->appendAction(pinningAction);
52
52
53 m_quitAction.setActionId(QStringLiteral("stop_item"));
53 m_quitAction.setActionId(QStringLiteral("stop_item"));
54 m_quitAction.setIcon(QStringLiteral("application-exit"));
54 m_quitAction.setIcon(QStringLiteral("application-exit"));
55 m_quitAction.setText(gettext("Quit"));
55 m_quitAction.setText(gettext("Quit"));
56+ m_quitAction.setIsPrivate(true);
56}
57}
57
58
58QString LauncherItem::appId() const
59QString LauncherItem::appId() const
@@ -120,6 +121,7 @@ void LauncherItem::setPinned(bool pinned)
120 QuickListEntry entry;
121 QuickListEntry entry;
121 entry.setActionId(QStringLiteral("pin_item"));
122 entry.setActionId(QStringLiteral("pin_item"));
122 entry.setText(pinned ? gettext("Unpin shortcut") : gettext("Pin shortcut"));
123 entry.setText(pinned ? gettext("Unpin shortcut") : gettext("Pin shortcut"));
124+ entry.setIsPrivate(true);
123 m_quickList->updateAction(entry);
125 m_quickList->updateAction(entry);
124}
126}
125
127
@@ -221,14 +223,36 @@ void LauncherItem::setAlerting(bool alerting)
221
223
222int LauncherItem::surfaceCount() const
224int LauncherItem::surfaceCount() const
223{
225{
224− return m_surfaceCount;
226+ return m_surfaces.count();
225}
227}
226
228
227−void LauncherItem::setSurfaceCount(int surfaceCount)
229+void LauncherItem::setSurfaces(const QList<QPair<QString, QString> > &surfaces)
228{
230{
229− if (m_surfaceCount != surfaceCount) {
231+ if (m_surfaces != surfaces) {
230− m_surfaceCount = surfaceCount;
232+ m_surfaces = surfaces;
233+
234+ QList<QuickListEntry> removedEntries;
235+ for (int i = 0; i < m_quickList->rowCount(); ++i) {
236+ QuickListEntry entry = m_quickList->get(i);
237+ if (entry.actionId().startsWith(QStringLiteral("surface_"))) {
238+ removedEntries.append(entry);
239+ }
240+ }
241+ Q_FOREACH (const QuickListEntry &entry, removedEntries) {
242+ m_quickList->removeAction(entry);
243+ }
244+ for (int i = 0; i < surfaces.count(); ++i) {
245+ QuickListEntry entry;
246+ entry.setActionId(QStringLiteral("surface_") + surfaces.at(i).first);
247+ entry.setText(surfaces.at(i).second);
248+ entry.setIsPrivate(true);
249+ if (i == surfaces.count() - 1) {
250+ entry.setHasSeparator(true);
251+ }
252+ m_quickList->insertAction(entry, i + 1);
253+ }
254+
231− Q_EMIT surfaceCountChanged(surfaceCount);
255+ Q_EMIT surfaceCountChanged(m_surfaces.count());
232 }
256 }
233}
257}
234
258
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+47−14
@@ -23,6 +23,7 @@
23
23
24#include <unity/shell/application/ApplicationInfoInterface.h>
24#include <unity/shell/application/ApplicationInfoInterface.h>
25#include <unity/shell/application/MirSurfaceListInterface.h>
25#include <unity/shell/application/MirSurfaceListInterface.h>
26+#include <unity/shell/application/MirSurfaceInterface.h>
26
27
27#include <QDesktopServices>
28#include <QDesktopServices>
28#include <QDebug>
29#include <QDebug>
@@ -198,12 +199,25 @@ void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex
198 } else {
199 } else {
199 pin(appId);
200 pin(appId);
200 }
201 }
201− } else if (actionId == QLatin1String("launch_item")) {
202+ } else if (actionId == QStringLiteral("launch_item")) {
202 QDesktopServices::openUrl(getUrlForAppId(appId));
203 QDesktopServices::openUrl(getUrlForAppId(appId));
203− } else if (actionId == QLatin1String("stop_item")) { // Quit
204+ } else if (actionId == QStringLiteral("stop_item")) { // Quit
204 if (m_appManager) {
205 if (m_appManager) {
205 m_appManager->stopApplication(appId);
206 m_appManager->stopApplication(appId);
206 }
207 }
208+ } else if (actionId.startsWith(QStringLiteral("surface_"))){
209+ ApplicationInfoInterface *appInfo = m_appManager->findApplication(appId);
210+ if (!appInfo) {
211+ qWarning() << "App for" << appId << "not found in launcher. Cannot invoke quicklist action";
212+ }
213+ for (int i = 0; i < appInfo->surfaceList()->count(); ++i) {
214+ MirSurfaceInterface *iface = appInfo->surfaceList()->get(i);
215+ QString id = actionId;
216+ id.remove(QRegExp("^surface_"));
217+ if (id == iface->persistentId()) {
218+ iface->activate();
219+ }
220+ }
207 // Nope, we don't know this action, let the backend forward it to the application
221 // Nope, we don't know this action, let the backend forward it to the application
208 } else {
222 } else {
209 // TODO: forward quicklist action to app, possibly via m_dbusIface
223 // TODO: forward quicklist action to app, possibly via m_dbusIface
@@ -517,40 +531,59 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
517 item->setRecent(true);
531 item->setRecent(true);
518 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
532 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
519 }
533 }
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);
534 item->setRunning(true);
526 } else {
535 } else {
527 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
536 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
528 item->setRecent(true);
537 item->setRecent(true);
529 item->setRunning(true);
538 item->setRunning(true);
530 item->setFocused(app->focused());
539 item->setFocused(app->focused());
531− item->setSurfaceCount(app->surfaceCount());
532 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
540 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
533 m_list.append(item);
541 m_list.append(item);
534 endInsertRows();
542 endInsertRows();
535 }
543 }
536− connect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::applicationSurfaceCountChanged);
544+ connect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::updateSurfaceList);
537 m_asAdapter->syncItems(m_list);
545 m_asAdapter->syncItems(m_list);
538 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRunning});
546 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRunning});
539}
547}
540
548
541−void LauncherModel::applicationSurfaceCountChanged(int count)
549+void LauncherModel::updateSurfaceList()
542{
550{
543 ApplicationInfoInterface *app = static_cast<ApplicationInfoInterface*>(sender());
551 ApplicationInfoInterface *app = static_cast<ApplicationInfoInterface*>(sender());
552+ updateSurfaceListForApp(app);
553+}
554+
555+void LauncherModel::updateSurfaceListForSurface()
556+{
557+ MirSurfaceInterface *iface = static_cast<MirSurfaceInterface*>(sender());
558+ ApplicationInfoInterface* app = m_appManager->findApplication(iface->appId());
559+ if (!app) {
560+ return;
561+ }
562+ updateSurfaceListForApp(app);
563+}
564+
565+void LauncherModel::updateSurfaceListForApp(ApplicationInfoInterface* app)
566+{
544 int idx = findApplication(app->appId());
567 int idx = findApplication(app->appId());
545 if (idx < 0) {
568 if (idx < 0) {
546 qWarning() << "Received a surface count changed event from an app that's not in the Launcher model";
569 qWarning() << "Received a surface count changed event from an app that's not in the Launcher model";
547 return;
570 return;
548 }
571 }
549 LauncherItem *item = m_list.at(idx);
572 LauncherItem *item = m_list.at(idx);
550− if (item->surfaceCount() != count) {
573+ QList<QPair<QString, QString> > surfaces;
551− item->setSurfaceCount(count);
574+ for (int i = 0; i < app->surfaceList()->count(); ++i) {
552− Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
575+ MirSurfaceInterface* iface = app->surfaceList()->get(i);
576+ // Avoid duplicate connections, so let's just disconnect first to be sure
577+ disconnect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
578+ connect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
579+ QString name = iface->name();
580+ if (name.isEmpty()) {
581+ name = app->name();
582+ }
583+ surfaces.append({iface->persistentId(), name});
553 }
584 }
585+ item->setSurfaces(surfaces);
586+ Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
554}
587}
555
588
556void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
589void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
@@ -571,7 +604,7 @@ void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
571 return;
604 return;
572 }
605 }
573
606
574− disconnect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::applicationSurfaceCountChanged);
607+ disconnect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::updateSurfaceList);
575
608
576 LauncherItem * item = m_list.at(appIndex);
609 LauncherItem * item = m_list.at(appIndex);
577
610
plugins/Unity/Launcher/launchermodel.h+3−1
@@ -75,7 +75,9 @@ private Q_SLOTS:
75 void applicationAdded(const QModelIndex &parent, int row);
75 void applicationAdded(const QModelIndex &parent, int row);
76 void applicationRemoved(const QModelIndex &parent, int row);
76 void applicationRemoved(const QModelIndex &parent, int row);
77 void focusedAppIdChanged();
77 void focusedAppIdChanged();
78− void applicationSurfaceCountChanged(int);
78+ void updateSurfaceList();
79+ void updateSurfaceListForApp(ApplicationInfoInterface *app);
80+ void updateSurfaceListForSurface();
79
81
80private:
82private:
81 QList<LauncherItem*> m_list;
83 QList<LauncherItem*> m_list;
plugins/Unity/Launcher/quicklistentry.cpp+11
@@ -20,6 +20,7 @@
20
20
21QuickListEntry::QuickListEntry()
21QuickListEntry::QuickListEntry()
22 : m_hasSeparator(false)
22 : m_hasSeparator(false)
23+ , m_isPrivate(false)
23{
24{
24}
25}
25
26
@@ -72,3 +73,13 @@ bool QuickListEntry::operator==(const QuickListEntry &other)
72{
73{
73 return !other.actionId().isEmpty() && other.actionId() == m_actionId;
74 return !other.actionId().isEmpty() && other.actionId() == m_actionId;
74}
75}
76+
77+bool QuickListEntry::isPrivate() const
78+{
79+ return m_isPrivate;
80+}
81+
82+void QuickListEntry::setIsPrivate(bool isPrivate)
83+{
84+ m_isPrivate = isPrivate;
85+}
plugins/Unity/Launcher/quicklistentry.h+4
@@ -42,11 +42,15 @@ public:
42
42
43 bool operator==(const QuickListEntry & other);
43 bool operator==(const QuickListEntry & other);
44
44
45+ bool isPrivate() const;
46+ void setIsPrivate(bool isPrivate);
47+
45private:
48private:
46 QString m_actionId;
49 QString m_actionId;
47 QString m_text;
50 QString m_text;
48 QString m_icon;
51 QString m_icon;
49 bool m_hasSeparator;
52 bool m_hasSeparator;
53+ bool m_isPrivate;
50};
54};
51
55
52#endif // QUICKLISTENTRY
56#endif // QUICKLISTENTRY
plugins/Unity/Launcher/quicklistmodel.cpp+9
@@ -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) {
@@ -81,6 +88,8 @@ QVariant QuickListModel::data(const QModelIndex &index, int role) const
81 return m_list.at(index.row()).clickable();
88 return m_list.at(index.row()).clickable();
82 case RoleHasSeparator:
89 case RoleHasSeparator:
83 return m_list.at(index.row()).hasSeparator();
90 return m_list.at(index.row()).hasSeparator();
91+ case RoleIsPrivate:
92+ return m_list.at(index.row()).isPrivate();
84 }
93 }
85 return QVariant();
94 return QVariant();
86}
95}
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
plugins/Utils/CMakeLists.txt+1
@@ -36,6 +36,7 @@ set(QMLPLUGIN_SRC
36 URLDispatcher.cpp
36 URLDispatcher.cpp
37 tabfocusfence.cpp
37 tabfocusfence.cpp
38 expressionfiltermodel.cpp
38 expressionfiltermodel.cpp
39+ quicklistproxymodel.cpp
39 plugin.cpp
40 plugin.cpp
40 )
41 )
41
42
plugins/Utils/plugin.cpp+2
@@ -42,6 +42,7 @@
42#include "appdrawerproxymodel.h"
42#include "appdrawerproxymodel.h"
43#include "tabfocusfence.h"
43#include "tabfocusfence.h"
44#include "expressionfiltermodel.h"
44#include "expressionfiltermodel.h"
45+#include "quicklistproxymodel.h"
45
46
46static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
47static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
47{
48{
@@ -88,4 +89,5 @@ void UtilsPlugin::registerTypes(const char *uri)
88 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
89 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
89 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");
90 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");
90 qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
91 qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
92+ qmlRegisterType<QuickListProxyModel>(uri, 0, 1, "QuickListProxyModel");
91}
93}
plugins/Utils/quicklistproxymodel.cppnew file+72
@@ -0,0 +1,72 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "quicklistproxymodel.h"
18+
19+#include <QDebug>
20+
21+QuickListProxyModel::QuickListProxyModel(QObject *parent):
22+ QSortFilterProxyModel(parent)
23+{
24+ connect(this, &QAbstractListModel::rowsInserted, this, &QuickListProxyModel::countChanged);
25+ connect(this, &QAbstractListModel::rowsRemoved, this, &QuickListProxyModel::countChanged);
26+ connect(this, &QAbstractListModel::layoutChanged, this, &QuickListProxyModel::countChanged);
27+}
28+
29+QAbstractItemModel *QuickListProxyModel::source() const
30+{
31+ return m_source;
32+}
33+
34+bool QuickListProxyModel::privateMode() const
35+{
36+ return m_privateMode;
37+}
38+
39+void QuickListProxyModel::setPrivateMode(bool privateMode)
40+{
41+ if (m_privateMode != privateMode) {
42+ m_privateMode = privateMode;
43+ invalidateFilter();
44+ Q_EMIT privateModeChanged();
45+ }
46+}
47+
48+void QuickListProxyModel::setSource(QAbstractItemModel *source)
49+{
50+ if (m_source != source) {
51+ m_source = source;
52+ setSourceModel(m_source);
53+ connect(m_source, &QAbstractItemModel::rowsRemoved, this, &QuickListProxyModel::invalidate);
54+ connect(m_source, &QAbstractItemModel::rowsInserted, this, &QuickListProxyModel::invalidate);
55+ Q_EMIT sourceChanged();
56+ }
57+}
58+
59+int QuickListProxyModel::count() const
60+{
61+ return rowCount();
62+}
63+
64+bool QuickListProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
65+{
66+ Q_UNUSED(source_parent)
67+
68+ if (m_privateMode) {
69+ return !m_source->data(m_source->index(source_row, 0), QuickListModelInterface::RoleIsPrivate).toBool();
70+ }
71+ return true;
72+}
plugins/Utils/quicklistproxymodel.hnew file+52
@@ -0,0 +1,52 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QSortFilterProxyModel>
18+
19+#include <unity/shell/launcher/QuickListModelInterface.h>
20+
21+using namespace unity::shell::launcher;
22+
23+class QuickListProxyModel: public QSortFilterProxyModel
24+{
25+ Q_OBJECT
26+ Q_PROPERTY(QAbstractItemModel* source READ source WRITE setSource NOTIFY sourceChanged)
27+ Q_PROPERTY(bool privateMode READ privateMode WRITE setPrivateMode NOTIFY privateModeChanged)
28+ Q_PROPERTY(int count READ count NOTIFY countChanged)
29+
30+public:
31+ QuickListProxyModel(QObject* parent = nullptr);
32+
33+ QAbstractItemModel* source() const;
34+ void setSource(QAbstractItemModel* source);
35+
36+ bool privateMode() const;
37+ void setPrivateMode(bool privateMode);
38+
39+ int count() const;
40+
41+protected:
42+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
43+
44+Q_SIGNALS:
45+ void sourceChanged();
46+ void privateModeChanged();
47+ void countChanged();
48+
49+private:
50+ QAbstractItemModel* m_source = nullptr;
51+ bool m_privateMode;
52+};
plugins/WindowManager/Window.cpp+26−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -67,6 +67,23 @@ void Window::setRequestedPosition(const QPoint &value)
67 }
67 }
68}
68}
69
69
70+bool Window::allowClientResize() const
71+{
72+ return m_allowClientResize;
73+}
74+
75+void Window::setAllowClientResize(bool value)
76+{
77+ if (value != m_allowClientResize) {
78+ DEBUG_MSG << "("<<value<<")";
79+ m_allowClientResize = value;
80+ if (m_surface) {
81+ m_surface->setAllowClientResize(value);
82+ }
83+ Q_EMIT allowClientResizeChanged(m_allowClientResize);
84+ }
85+}
86+
70Mir::State Window::state() const
87Mir::State Window::state() const
71{
88{
72 return m_state;
89 return m_state;
@@ -154,6 +171,13 @@ void Window::setSurface(unityapi::MirSurfaceInterface *surface)
154 updateFocused();
171 updateFocused();
155 });
172 });
156
173
174+ connect(surface, &unityapi::MirSurfaceInterface::allowClientResizeChanged, this, [this]() {
175+ if (m_surface->allowClientResize() != m_allowClientResize) {
176+ m_allowClientResize = m_surface->allowClientResize();
177+ Q_EMIT allowClientResizeChanged(m_allowClientResize);
178+ }
179+ });
180+
157 // bring it up to speed
181 // bring it up to speed
158 if (m_positionRequested) {
182 if (m_positionRequested) {
159 m_surface->setRequestedPosition(m_requestedPosition);
183 m_surface->setRequestedPosition(m_requestedPosition);
@@ -161,6 +185,7 @@ void Window::setSurface(unityapi::MirSurfaceInterface *surface)
161 if (m_stateRequested && m_surface->state() == Mir::RestoredState) {
185 if (m_stateRequested && m_surface->state() == Mir::RestoredState) {
162 m_surface->requestState(m_state);
186 m_surface->requestState(m_state);
163 }
187 }
188+ m_surface->setAllowClientResize(m_allowClientResize);
164
189
165 // and sync with surface
190 // and sync with surface
166 updatePosition();
191 updatePosition();
plugins/WindowManager/Window.h+14−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -89,6 +89,13 @@ class Window : public QObject
89 */
89 */
90 Q_PROPERTY(unity::shell::application::MirSurfaceInterface* surface READ surface NOTIFY surfaceChanged)
90 Q_PROPERTY(unity::shell::application::MirSurfaceInterface* surface READ surface NOTIFY surfaceChanged)
91
91
92+ /**
93+ * @brief Whether to comply to resize requests coming from the client side
94+ *
95+ * It's true by default
96+ */
97+ Q_PROPERTY(bool allowClientResize READ allowClientResize WRITE setAllowClientResize NOTIFY allowClientResizeChanged)
98+
92public:
99public:
93 Window(int id, QObject *parent = nullptr);
100 Window(int id, QObject *parent = nullptr);
94 virtual ~Window();
101 virtual ~Window();
@@ -104,6 +111,9 @@ public:
104 void setSurface(unity::shell::application::MirSurfaceInterface *surface);
111 void setSurface(unity::shell::application::MirSurfaceInterface *surface);
105 void setFocused(bool value);
112 void setFocused(bool value);
106
113
114+ bool allowClientResize() const;
115+ void setAllowClientResize(bool);
116+
107 QString toString() const;
117 QString toString() const;
108
118
109public Q_SLOTS:
119public Q_SLOTS:
@@ -133,6 +143,7 @@ Q_SIGNALS:
133 void focusedChanged(bool value);
143 void focusedChanged(bool value);
134 void confinesMousePointerChanged(bool value);
144 void confinesMousePointerChanged(bool value);
135 void surfaceChanged(unity::shell::application::MirSurfaceInterface *surface);
145 void surfaceChanged(unity::shell::application::MirSurfaceInterface *surface);
146+ void allowClientResizeChanged(bool value);
136
147
137 /**
148 /**
138 * @brief Emitted when focus for this window is requested by an external party
149 * @brief Emitted when focus for this window is requested by an external party
@@ -152,6 +163,8 @@ private:
152 Mir::State m_state{Mir::RestoredState};
163 Mir::State m_state{Mir::RestoredState};
153 bool m_stateRequested{false};
164 bool m_stateRequested{false};
154 unity::shell::application::MirSurfaceInterface *m_surface{nullptr};
165 unity::shell::application::MirSurfaceInterface *m_surface{nullptr};
166+
167+ bool m_allowClientResize{true};
155};
168};
156
169
157QDebug operator<<(QDebug dbg, const Window *window);
170QDebug operator<<(QDebug dbg, const Window *window);
qml/Launcher/Launcher.qml+1
@@ -33,6 +33,7 @@ FocusScope {
33 property Item blurSource: null
33 property Item blurSource: null
34 property int topPanelHeight: 0
34 property int topPanelHeight: 0
35 property bool drawerEnabled: true
35 property bool drawerEnabled: true
36+ property alias privateMode: panel.privateMode
36
37
37 property int panelWidth: units.gu(10)
38 property int panelWidth: units.gu(10)
38 property int dragAreaWidth: units.gu(1)
39 property int dragAreaWidth: units.gu(1)
qml/Launcher/LauncherPanel.qml+8−1
@@ -19,6 +19,7 @@ import QtQml.StateMachine 1.0 as DSM
19import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
20import Unity.Launcher 0.1
20import Unity.Launcher 0.1
21import Ubuntu.Components.Popups 1.3
21import Ubuntu.Components.Popups 1.3
22+import Utils 0.1
22import "../Components"
23import "../Components"
23
24
24Rectangle {
25Rectangle {
@@ -29,6 +30,7 @@ Rectangle {
29
30
30 property var model
31 property var model
31 property bool inverted: false
32 property bool inverted: false
33+ property bool privateMode: false
32 property bool dragging: false
34 property bool dragging: false
33 property bool moving: launcherListView.moving || launcherListView.flicking
35 property bool moving: launcherListView.moving || launcherListView.flicking
34 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
36 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
@@ -811,7 +813,11 @@ Rectangle {
811
813
812 Repeater {
814 Repeater {
813 id: popoverRepeater
815 id: popoverRepeater
816+ objectName: "popoverRepeater"
817+ model: QuickListProxyModel {
814− model: quickList.model
818+ source: quickList.model
819+ privateMode: root.privateMode
820+ }
815
821
816 ListItem {
822 ListItem {
817 objectName: "quickListEntry" + index
823 objectName: "quickListEntry" + index
@@ -835,6 +841,7 @@ Rectangle {
835 fontSize: index == 0 ? "medium" : "small"
841 fontSize: index == 0 ? "medium" : "small"
836 font.weight: index == 0 ? Font.Medium : Font.Light
842 font.weight: index == 0 ? Font.Medium : Font.Light
837 color: model.clickable ? theme.palette.normal.backgroundText : theme.palette.disabled.backgroundText
843 color: model.clickable ? theme.palette.normal.backgroundText : theme.palette.disabled.backgroundText
844+ elide: Text.ElideRight
838 }
845 }
839
846
840 onClicked: {
847 onClicked: {
qml/Shell.qml+1
@@ -559,6 +559,7 @@ StyledItem {
559 blurSource: greeter.shown ? greeter : stages
559 blurSource: greeter.shown ? greeter : stages
560 topPanelHeight: panel.panelHeight
560 topPanelHeight: panel.panelHeight
561 drawerEnabled: !greeter.active
561 drawerEnabled: !greeter.active
562+ privateMode: greeter.active
562
563
563 onShowDashHome: showHome()
564 onShowDashHome: showHome()
564 onLauncherApplicationSelected: {
565 onLauncherApplicationSelected: {
qml/Stage/Stage.qml+8
@@ -1302,6 +1302,10 @@ FocusScope {
1302 target: stageMaths
1302 target: stageMaths
1303 animateX: !focusAnimation.running && itemIndex !== spreadItem.highlightedIndex
1303 animateX: !focusAnimation.running && itemIndex !== spreadItem.highlightedIndex
1304 }
1304 }
1305+ PropertyChanges {
1306+ target: appDelegate.window
1307+ allowClientResize: false
1308+ }
1305 },
1309 },
1306 State {
1310 State {
1307 name: "stagedWithSideStage"; when: root.state == "stagedWithSideStage"
1311 name: "stagedWithSideStage"; when: root.state == "stagedWithSideStage"
@@ -1327,6 +1331,10 @@ FocusScope {
1327 target: resizeArea
1331 target: resizeArea
1328 enabled: false
1332 enabled: false
1329 }
1333 }
1334+ PropertyChanges {
1335+ target: appDelegate.window
1336+ allowClientResize: false
1337+ }
1330 },
1338 },
1331 State {
1339 State {
1332 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
1340 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
tests/mocks/Unity/Application/MirSurface.cpp+4
@@ -127,6 +127,10 @@ QString MirSurface::persistentId() const
127 return m_name+"Id";
127 return m_name+"Id";
128}
128}
129
129
130+QString MirSurface::appId() const
131+{
132+ return m_name+"appId";
133+}
130Mir::Type MirSurface::type() const
134Mir::Type MirSurface::type() const
131{
135{
132 return m_type;
136 return m_type;
tests/mocks/Unity/Application/MirSurface.h+4
@@ -58,6 +58,7 @@ public:
58 QString name() const override;
58 QString name() const override;
59
59
60 QString persistentId() const override;
60 QString persistentId() const override;
61+ QString appId() const override;
61
62
62 QPoint position() const override { return m_position; }
63 QPoint position() const override { return m_position; }
63
64
@@ -92,6 +93,9 @@ public:
92
93
93 bool confinesMousePointer() const override { return false; }
94 bool confinesMousePointer() const override { return false; }
94
95
96+ bool allowClientResize() const override { return true; }
97+ void setAllowClientResize(bool) override {}
98+
95 QPoint requestedPosition() const override { return m_requestedPosition; }
99 QPoint requestedPosition() const override { return m_requestedPosition; }
96 void setRequestedPosition(const QPoint &) override;
100 void setRequestedPosition(const QPoint &) override;
97
101
tests/mocks/Unity/Launcher/MockLauncherModel.h+1−1
@@ -28,7 +28,7 @@ using namespace unity::shell::launcher;
28
28
29class MockLauncherModel: public LauncherModelInterface
29class MockLauncherModel: public LauncherModelInterface
30{
30{
31− Q_OBJECT
31+ Q_OBJECT
32
32
33public:
33public:
34 MockLauncherModel(QObject* parent = 0);
34 MockLauncherModel(QObject* parent = 0);
tests/mocks/Unity/Launcher/MockQuickListModel.cpp+3−1
@@ -39,6 +39,8 @@ QVariant MockQuickListModel::data(const QModelIndex &index, int role) const
39 return index.row() == 1 ? false : true;
39 return index.row() == 1 ? false : true;
40 case RoleHasSeparator:
40 case RoleHasSeparator:
41 return index.row() <= 1 ? true : false;
41 return index.row() <= 1 ? true : false;
42+ case RoleIsPrivate:
43+ return index.row() == 4 ? true : false;
42 }
44 }
43 return QVariant();
45 return QVariant();
44}
46}
@@ -46,5 +48,5 @@ QVariant MockQuickListModel::data(const QModelIndex &index, int role) const
46int MockQuickListModel::rowCount(const QModelIndex &parent) const
48int MockQuickListModel::rowCount(const QModelIndex &parent) const
47{
49{
48 Q_UNUSED(parent)
50 Q_UNUSED(parent)
49− return 4;
51+ return 5;
50}
52}
tests/mocks/Unity/Launcher/MockQuickListModel.h+2
@@ -27,6 +27,8 @@ using namespace unity::shell::launcher;
27class MockQuickListModel: public QuickListModelInterface
27class MockQuickListModel: public QuickListModelInterface
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30+ Q_PROPERTY(int count READ rowCount)
31+
30public:
32public:
31 MockQuickListModel(QObject *parent = 0);
33 MockQuickListModel(QObject *parent = 0);
32
34
tests/mocks/Utils/CMakeLists.txt+2
@@ -27,6 +27,7 @@ set(QMLPLUGIN_SRC
27 ${CMAKE_SOURCE_DIR}/plugins/Utils/appdrawerproxymodel.cpp
27 ${CMAKE_SOURCE_DIR}/plugins/Utils/appdrawerproxymodel.cpp
28 ${CMAKE_SOURCE_DIR}/plugins/Utils/tabfocusfence.cpp
28 ${CMAKE_SOURCE_DIR}/plugins/Utils/tabfocusfence.cpp
29 ${CMAKE_SOURCE_DIR}/plugins/Utils/expressionfiltermodel.cpp
29 ${CMAKE_SOURCE_DIR}/plugins/Utils/expressionfiltermodel.cpp
30+ ${CMAKE_SOURCE_DIR}/plugins/Utils/quicklistproxymodel.cpp
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
33 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
@@ -35,6 +36,7 @@ set(QMLPLUGIN_SRC
35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
36 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
36 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
37 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
37 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
38 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
39+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
38 constants.cpp
40 constants.cpp
39 plugin.cpp
41 plugin.cpp
40 windowstatestorage.cpp
42 windowstatestorage.cpp
tests/mocks/Utils/plugin.cpp+2
@@ -43,6 +43,7 @@
43#include <appdrawerproxymodel.h>
43#include <appdrawerproxymodel.h>
44#include <tabfocusfence.h>
44#include <tabfocusfence.h>
45#include <expressionfiltermodel.h>
45#include <expressionfiltermodel.h>
46+#include <quicklistproxymodel.h>
46
47
47static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
48static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
48{
49{
@@ -88,4 +89,5 @@ void FakeUtilsPlugin::registerTypes(const char *uri)
88 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
89 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
89 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");
90 qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");
90 qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
91 qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
92+ qmlRegisterType<QuickListProxyModel>(uri, 0, 1, "QuickListProxyModel");
91}
93}
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+85−7
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013-2016 Canonical Ltd.
2+ * Copyright 2013-2017 Canonical Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -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,76 @@
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, const QString &appId, QObject* parent): unityapi::MirSurfaceInterface(parent), m_id(id), m_appId(appId) {}
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+ QString appId() const override { return m_appId; }
50+ QPoint position() const override { return QPoint(); }
51+ QSize size() const override { return QSize(); }
52+ void resize(const QSize &size) override { Q_UNUSED(size) }
53+ void resize(int width, int height) override { Q_UNUSED(width); Q_UNUSED(height) }
54+ Mir::State state() const override { return Mir::RestoredState; }
55+ bool live() const override { return true; }
56+ bool visible() const override { return true; }
57+ Mir::OrientationAngle orientationAngle() const override { return Mir::Angle0; }
58+ void setOrientationAngle(Mir::OrientationAngle angle) override { Q_UNUSED(angle); }
59+ int minimumWidth() const override { return 0; }
60+ int minimumHeight() const override { return 0; }
61+ int maximumWidth() const override { return 0; }
62+ int maximumHeight() const override { return 0; }
63+ int widthIncrement() const override { return 0; }
64+ int heightIncrement() const override { return 0; }
65+ void setKeymap(const QString &) override {}
66+ Mir::ShellChrome shellChrome() const override { return Mir::NormalChrome; }
67+ QString keymap() const override { return QStringLiteral("de_DE"); }
68+ bool focused() const override { return true; }
69+ QRect inputBounds() const override { return QRect(); }
70+ bool confinesMousePointer() const override { return false; }
71+ bool allowClientResize() const override { return true; }
72+ void setAllowClientResize(bool) override {}
73+ QPoint requestedPosition() const override { return QPoint(); }
74+ void setRequestedPosition(const QPoint &) override {}
75+ MirSurfaceInterface* parentSurface() const override { return nullptr; }
76+ MirSurfaceListInterface* childSurfaceList() const override { return nullptr; }
77+ void close() override {}
78+ void activate() override {}
79+ void requestState(Mir::State) override {}
80+
81+private:
82+ QString m_id;
83+ QString m_appId;
84+};
85+
86+class MockSurfaceList: public unity::shell::application::MirSurfaceListInterface
87+{
88+ Q_OBJECT
89+public:
90+ MockSurfaceList(QObject *parent): unityapi::MirSurfaceListInterface(parent) {}
91+ int rowCount(const QModelIndex & = QModelIndex()) const override { return m_list.count(); }
92+ QVariant data(const QModelIndex &, int) const override { return QVariant(); }
93+ Q_INVOKABLE MirSurfaceInterface* get(int index) override { return m_list.at(index); }
94+ void append(MirSurfaceInterface* surface) {
95+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
96+ m_list.append(surface);
97+ endInsertRows();
98+ }
99+private:
100+ QList<MirSurfaceInterface*> m_list;
101+
102+};
103+
40class MockApp: public unity::shell::application::ApplicationInfoInterface
104class MockApp: public unity::shell::application::ApplicationInfoInterface
41{
105{
42 Q_OBJECT
106 Q_OBJECT
43public:
107public:
44− MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) { }
108+ MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) {
109+ m_surfaces = new MockSurfaceList(this);
110+ }
45
111
46 RequestedState requestedState() const override { return RequestedRunning; }
112 RequestedState requestedState() const override { return RequestedRunning; }
47 void setRequestedState(RequestedState) override {}
113 void setRequestedState(RequestedState) override {}
@@ -64,10 +130,10 @@ public:
64 void setExemptFromLifecycle(bool) override {}
130 void setExemptFromLifecycle(bool) override {}
65 QSize initialSurfaceSize() const override { return QSize(); }
131 QSize initialSurfaceSize() const override { return QSize(); }
66 void setInitialSurfaceSize(const QSize &) override {}
132 void setInitialSurfaceSize(const QSize &) override {}
67− MirSurfaceListInterface* surfaceList() const override { return nullptr; }
133+ MirSurfaceListInterface* surfaceList() const override { return m_surfaces; }
68 MirSurfaceListInterface* promptSurfaceList() const override { return nullptr; }
134 MirSurfaceListInterface* promptSurfaceList() const override { return nullptr; }
69− int surfaceCount() const override { return m_surfaceCount; }
135+ int surfaceCount() const override { return m_surfaces->count(); }
70− void setSurfaceCount(int count) { m_surfaceCount = count; Q_EMIT surfaceCountChanged(count); }
136+ void setSurfaces(MockSurfaceList* surfaces) { m_surfaces = surfaces; Q_EMIT surfaceCountChanged(m_surfaces->count()); }
71 void close() override {}
137 void close() override {}
72
138
73 // Methods used for mocking (not in the interface)
139 // Methods used for mocking (not in the interface)
@@ -75,7 +141,7 @@ public:
75private:
141private:
76 QString m_appId;
142 QString m_appId;
77 bool m_focused;
143 bool m_focused;
78− int m_surfaceCount = 0;
144+ MockSurfaceList *m_surfaces;
79};
145};
80
146
81// This is a mock, specifically to test the LauncherModel
147// This is a mock, specifically to test the LauncherModel
@@ -748,8 +814,20 @@ private Q_SLOTS:
748
814
749 QCOMPARE(launcherModel->get(0)->surfaceCount(), 0);
815 QCOMPARE(launcherModel->get(0)->surfaceCount(), 0);
750 MockApp *app = qobject_cast<MockApp*>(appManager->findApplication(appId));
816 MockApp *app = qobject_cast<MockApp*>(appManager->findApplication(appId));
751− app->setSurfaceCount(1);
817+ MockSurfaceList* surfaces = new MockSurfaceList(appManager);
818+ surfaces->append(new MockSurface("foobar", "foobar", surfaces));
819+ app->setSurfaces(surfaces);
752 QCOMPARE(launcherModel->get(0)->surfaceCount(), 1);
820 QCOMPARE(launcherModel->get(0)->surfaceCount(), 1);
821+
822+ // Make sure the new surface appears in the quicklist
823+ QuickListModel *quickList = qobject_cast<QuickListModel*>(launcherModel->get(0)->quickList());
824+ bool found = false;
825+ for (int i = 0; i < quickList->rowCount(); ++i) {
826+ if (quickList->get(i).actionId() == "surface_foobar") {
827+ found = true;
828+ }
829+ }
830+ QCOMPARE(found, true);
753 }
831 }
754};
832};
755
833
tests/qmltests/Launcher/tst_Launcher.qml+42
@@ -95,6 +95,11 @@ Rectangle {
95 property: "lockedVisible"
95 property: "lockedVisible"
96 value: lockedVisibleCheckBox.checked
96 value: lockedVisibleCheckBox.checked
97 }
97 }
98+ Binding {
99+ target: launcherLoader.item
100+ property: "privateMode"
101+ value: privateModeCheckBox.checked
102+ }
98 Binding {
103 Binding {
99 target: launcherLoader.item
104 target: launcherLoader.item
100 property: "panelWidth"
105 property: "panelWidth"
@@ -120,6 +125,20 @@ Rectangle {
120 }
125 }
121 }
126 }
122
127
128+ RowLayout {
129+ CheckBox {
130+ id: privateModeCheckBox
131+ checked: false
132+ }
133+ Label {
134+ text: "Private mode (lockscreen locked)"
135+ AbstractButton {
136+ anchors.fill: parent
137+ onClicked: privateModeCheckBox.checked = !privateModeCheckBox.checked
138+ }
139+ }
140+ }
141+
123 Slider {
142 Slider {
124 id: widthSlider
143 id: widthSlider
125 Layout.fillWidth: true
144 Layout.fillWidth: true
@@ -1242,6 +1261,7 @@ Rectangle {
1242 keyClick(Qt.Key_Down);
1261 keyClick(Qt.Key_Down);
1243 keyClick(Qt.Key_Down);
1262 keyClick(Qt.Key_Down);
1244 keyClick(Qt.Key_Down);
1263 keyClick(Qt.Key_Down);
1264+ keyClick(Qt.Key_Down);
1245 tryCompare(quickList, "selectedIndex", 0)
1265 tryCompare(quickList, "selectedIndex", 0)
1246
1266
1247 // Left gets us back to the launcher
1267 // Left gets us back to the launcher
@@ -1493,6 +1513,28 @@ Rectangle {
1493 compare(launcher.state, "visibleTemporary");
1513 compare(launcher.state, "visibleTemporary");
1494 }
1514 }
1495
1515
1516+ function test_hideQuicklistItemsInPrivateModel_data() {
1517+ return [
1518+ { tag: "private mode", private: true },
1519+ { tag: "normal mode", private: false }
1520+ ];
1521+ }
1522+
1523+ function test_hideQuicklistItemsInPrivateModel(data) {
1524+ privateModeCheckBox.checked = data.private;
1525+
1526+ revealByEdgePush();
1527+
1528+ var item = findChild(launcher, "launcherDelegate4");
1529+ var quickListShape = findChild(launcher, "quickListShape")
1530+
1531+ mousePress(item)
1532+ tryCompare(quickListShape, "visible", true)
1533+
1534+ var repeater = findChild(launcher, "popoverRepeater");
1535+ tryCompare(repeater, "count", LauncherModel.get(4).quickList.count - (data.private ? 1 : 0))
1536+ }
1537+
1496 function test_hintOnSizeChange() {
1538 function test_hintOnSizeChange() {
1497 var oldSize = launcher.panelWidth;
1539 var oldSize = launcher.panelWidth;
1498 launcher.maxPanelX = -launcher.panelWidth;
1540 launcher.maxPanelX = -launcher.panelWidth;