on xenial help sign in
Added application prompt surfaces to allow prompting application which have not yet created a surface.
commit9f5177ef9b88f8fde6ad76aebfec44bc2de2cbc0 authorNick Dedekind <nicholas.dedekind@gmail.com> dateFri 8 Aug 2014, 12:14 (12 years ago) parent870563138eaad1
12 files changed+202−88
debian/control+1−1 qml/Stages/AppSurfaceContainer.qml+96 qml/Stages/SpreadDelegate.qml+2−52 qml/Stages/SurfaceContainer.qml+5−22 tests/mocks/Unity/Application/ApplicationDBusAdaptor.cpp+10−4 tests/mocks/Unity/Application/ApplicationDBusAdaptor.h+1−1 tests/mocks/Unity/Application/ApplicationInfo.cpp+53 tests/mocks/Unity/Application/ApplicationInfo.h+13 tests/mocks/Unity/Application/ApplicationManager.cpp+3 tests/mocks/Unity/Application/ApplicationManager.h+1 tests/mocks/Unity/Application/MirSurfaceItem.cpp+16−8 tests/mocks/Unity/Application/MirSurfaceItem.h+1
debian/control+1−1
@@ -83,7 +83,7 @@ Depends: gsettings-desktop-schemas,
8383 qmenumodel-qml (>= 0.2.8),
8484 qml-module-qtquick-xmllistmodel,
8585 qtdeclarative5-gsettings1.0,
86− qtdeclarative5-qtmir-plugin (>= 0.4),
86+ qtdeclarative5-qtmir-plugin (>= 0.4.1),
8787 qtdeclarative5-ubuntu-settings-components (>= 0.3),
8888 qtdeclarative5-ubuntu-telephony0.1,
8989 unity-launcher-impl-3,
qml/Stages/AppSurfaceContainer.qmlnew file+96
@@ -0,0 +1,96 @@
1+/*
2+ * Copyright 2014 Canonical Ltd.
3+ *
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
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 Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+*/
16+
17+import QtQuick 2.0
18+import "Animations"
19+
20+SurfaceContainer {
21+ id: container
22+ property var promptSurfaces
23+
24+ property bool appHasCreatedASurface: false
25+
26+ onSurfaceChanged: {
27+ if (surface) {
28+ if (!appHasCreatedASurface) {
29+ surface.visible = false; // hide until splash screen removed
30+ appHasCreatedASurface = true;
31+ }
32+ }
33+ }
34+
35+ function revealSurface() {
36+ surface.visible = true;
37+ splashLoader.source = "";
38+ }
39+
40+ Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
41+ id: surfaceRevealDelay
42+ interval: 100
43+ onTriggered: surfaceContainer.revealSurface()
44+ }
45+
46+ Loader {
47+ z: 3
48+ id: splashLoader
49+ anchors.fill: parent
50+ }
51+
52+ Repeater {
53+ model: container.promptSurfaces
54+
55+ delegate: SurfaceContainer {
56+ anchors {
57+ fill: container
58+ topMargin: container.surface.anchors.topMargin
59+ rightMargin: container.surface.anchors.rightMargin
60+ bottomMargin: container.surface.anchors.bottomMargin
61+ leftMargin: container.surface.anchors.leftMargin
62+ }
63+
64+ z: 4 + index
65+ surface: modelData
66+
67+ Component.onCompleted: {
68+ animateIn();
69+ }
70+ }
71+ }
72+
73+ StateGroup {
74+ id: appSurfaceState
75+ states: [
76+ State {
77+ name: "noSurfaceYet"
78+ when: !surfaceContainer.appHasCreatedASurface
79+ StateChangeScript {
80+ script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
81+ }
82+ },
83+ State {
84+ name: "hasSurface"
85+ when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null)
86+ StateChangeScript { script: { surfaceRevealDelay.start(); } }
87+ },
88+ State {
89+ name: "surfaceLostButAppStillAlive"
90+ when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null)
91+ // TODO - use app snapshot
92+ }
93+ ]
94+ state: "noSurfaceYet"
95+ }
96+}
qml/Stages/SpreadDelegate.qml+2−52
@@ -35,26 +35,12 @@ Item {
3535 signal clicked()
3636 signal closed()
3737
38− SurfaceContainer {
38+ AppSurfaceContainer {
3939 id: surfaceContainer
4040 objectName: "surfaceContainer"
4141 anchors.fill: parent
4242 surface: model.surface
43− property bool appHasCreatedASurface: false
44−
45− onSurfaceChanged: {
46− if (surface) {
47− if (!appHasCreatedASurface) {
48− surface.visible = false; // hide until splash screen removed
49− appHasCreatedASurface = true;
50− }
51− }
52− }
53−
54− function revealSurface() {
55− surface.visible = true;
56− splashLoader.source = "";
57− }
43+ promptSurfaces: model.application.promptSurfaces
5844
5945 Binding {
6046 target: surfaceContainer.surface
@@ -75,12 +61,6 @@ Item {
7561 value: root.interactive
7662 }
7763
78− Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
79− id: surfaceRevealDelay
80− interval: 100
81− onTriggered: surfaceContainer.revealSurface()
82− }
83−
8464 Connections {
8565 target: surface
8666 // FIXME: I would rather not need to do this, but currently it doesn't get
@@ -115,36 +95,6 @@ Item {
11595 }
11696 }
11797
118−
119− StateGroup {
120− id: appSurfaceState
121− states: [
122− State {
123− name: "noSurfaceYet"
124− when: !surfaceContainer.appHasCreatedASurface
125− StateChangeScript {
126− script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
127− }
128− },
129− State {
130− name: "hasSurface"
131− when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null)
132− StateChangeScript { script: { surfaceRevealDelay.start(); } }
133− },
134− State {
135− name: "surfaceLostButAppStillAlive"
136− when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null)
137− // TODO - use app snapshot
138− }
139− ]
140− state: "noSurfaceYet"
141− }
142−
143− Loader {
144− id: splashLoader
145− anchors.fill: surfaceContainer
146− }
147−
14898 DraggingArea {
14999 id: dragArea
150100 anchors.fill: parent
qml/Stages/SurfaceContainer.qml+5−22
@@ -40,19 +40,12 @@ Item {
4040 childSurfaces[i].removed();
4141 }
4242
43− //if we don't have children, nothing will tell us to animate out, so do it.
44− if (childSurfaces.length === 0) {
45− animateOut();
46− }
47− // tell our parent to animate out.
48− if (surface.parentSurface) {
49− surface.parentSurface.parent.animateOut();
50− }
43+ animateOut();
5144 }
5245 }
5346
5447 Repeater {
55− model: container.surface ? container.surface.childSurfaces : 0
48+ model: surface.childSurfaces
5649
5750 delegate: Loader {
5851 z: 2
@@ -68,14 +61,13 @@ Item {
6861 source: Qt.resolvedUrl("SurfaceContainer.qml")
6962 onLoaded: {
7063 item.surface = modelData;
71− item.animateIn(swipeFromBottom);
72− container.animateIn(swipeUp);
64+ item.animateIn();
7365 }
7466 }
7567 }
7668
77− function animateIn(component) {
78− var animation = component.createObject(container, { "surface": container.surface });
69+ function animateIn() {
70+ var animation = swipeFromBottom.createObject(container, { "surface": container.surface });
7971 animation.start();
8072
8173 var tmp = d.animations;
@@ -104,20 +96,11 @@ Item {
10496 id: swipeFromBottom
10597 SwipeFromBottomAnimation {}
10698 }
107− Component {
108− id: swipeUp
109− SwipeUpAnimation {}
110− }
111− Component {
112− id: darkenFade
113− DarkenAndFadeInAnimation {}
114− }
11599
116100 states: [
117101 State {
118102 name: "initial"
119103 PropertyChanges { target: surface; anchors.fill: container }
120104 }
121− // TODO: more animations!
122105 ]
123106}
tests/mocks/Unity/Application/ApplicationDBusAdaptor.cpp+10−4
@@ -43,9 +43,9 @@ MirSurfaceItem* topSurface(MirSurfaceItem* surface)
4343 return child ? child : surface;
4444}
4545
46−quint32 ApplicationDBusAdaptor::addChildSurface(const QString &appId, const QString &surfaceImage)
46+quint32 ApplicationDBusAdaptor::addPromptSurface(const QString &appId, const QString &surfaceImage)
4747{
48− qDebug() << "ApplicationDBusAdaptor::addChildSurface - " << appId;
48+ qDebug() << "ApplicationDBusAdaptor::addPromptSurface to " << appId;
4949
5050 ApplicationInfo* application = m_applicationManager->findApplication(appId);
5151 if (!application) {
@@ -53,12 +53,18 @@ quint32 ApplicationDBusAdaptor::addChildSurface(const QString &appId, const QStr
5353 return 0;
5454 }
5555 quint32 surfaceId = ++nextId;
56− MirSurfaceItem* surface = new MirSurfaceItem(QString("ChildSurface%1").arg(surfaceId),
56+ MirSurfaceItem* surface = new MirSurfaceItem(QString("%1-ChildSurface%2").arg(appId).arg(surfaceId),
5757 MirSurfaceItem::Normal,
5858 MirSurfaceItem::Maximized,
5959 QUrl(surfaceImage));
6060 m_childItems[surfaceId] = surface;
61− surface->setParentSurface(topSurface(application->surface()));
61+
62+ if (application->promptSurfaceList().count() > 0) {
63+ surface->setParentSurface(topSurface(application->promptSurfaceList()[0]));
64+ } else {
65+ application->addPromptSurface(surface);
66+ }
67+
6268 return surfaceId;
6369}
6470
tests/mocks/Unity/Application/ApplicationDBusAdaptor.h+1−1
@@ -31,7 +31,7 @@ public:
3131 ApplicationDBusAdaptor(ApplicationManager* applicationManager);
3232
3333public Q_SLOTS:
34− quint32 addChildSurface(const QString& appId, const QString& surfaceImage);
34+ quint32 addPromptSurface(const QString& appId, const QString& surfaceImage);
3535 void removeChildSurface(int surfaceId);
3636
3737private:
tests/mocks/Unity/Application/ApplicationInfo.cpp+53
@@ -78,6 +78,7 @@ void ApplicationInfo::createSurface()
7878
7979void ApplicationInfo::setSurface(MirSurfaceItem* surface)
8080{
81+ qDebug() << "Application::setSurface - appId=" << appId() << "surface=" << surface;
8182 if (m_surface == surface)
8283 return;
8384
@@ -98,3 +99,55 @@ void ApplicationInfo::setSurface(MirSurfaceItem* surface)
9899 Q_EMIT surfaceChanged(m_surface);
99100 SurfaceManager::singleton()->registerSurface(m_surface);
100101}
102+
103+void ApplicationInfo::addPromptSurface(MirSurfaceItem* surface)
104+{
105+ qDebug() << "ApplicationInfo::addPromptSurface " << surface->name() << " to " << name();
106+ if (surface == m_surface || m_promptSurfaces.contains(surface)) return;
107+
108+ surface->setApplication(this);
109+ m_promptSurfaces.append(surface);
110+ Q_EMIT promptSurfacesChanged();
111+}
112+
113+void ApplicationInfo::removeSurface(MirSurfaceItem* surface)
114+{
115+ if (m_surface == surface) {
116+ setSurface(nullptr);
117+ } else if (m_promptSurfaces.contains(surface)) {
118+ qDebug() << "Application::removeSurface " << surface->name() << " from " << name();
119+
120+ m_promptSurfaces.removeAll(surface);
121+ surface->setApplication(nullptr);
122+
123+ Q_EMIT promptSurfacesChanged();
124+ }
125+}
126+
127+QList<MirSurfaceItem*> ApplicationInfo::promptSurfaceList() const
128+{
129+ return m_promptSurfaces;
130+}
131+
132+QQmlListProperty<MirSurfaceItem> ApplicationInfo::promptSurfaces()
133+{
134+ return QQmlListProperty<MirSurfaceItem>(this,
135+ 0,
136+ ApplicationInfo::promptSurfaceCount,
137+ ApplicationInfo::promptSurfaceAt);
138+}
139+
140+int ApplicationInfo::promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop)
141+{
142+ ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
143+ return p->m_promptSurfaces.count();
144+}
145+
146+MirSurfaceItem* ApplicationInfo::promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index)
147+{
148+ ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
149+
150+ if (index < 0 || index >= p->m_promptSurfaces.count())
151+ return nullptr;
152+ return p->m_promptSurfaces[index];
153+}
tests/mocks/Unity/Application/ApplicationInfo.h+13
@@ -38,6 +38,7 @@ class ApplicationInfo : public ApplicationInfoInterface {
3838 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
3939 Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
4040 Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
41+ Q_PROPERTY(QQmlListProperty<MirSurfaceItem> promptSurfaces READ promptSurfaces NOTIFY promptSurfacesChanged DESIGNABLE false)
4142
4243 // Only exists in this fake implementation
4344
@@ -85,8 +86,15 @@ public:
8586 void setSurface(MirSurfaceItem* surface);
8687 MirSurfaceItem* surface() const { return m_surface; }
8788
89+ void removeSurface(MirSurfaceItem* surface);
90+
91+ void addPromptSurface(MirSurfaceItem* surface);
92+ QList<MirSurfaceItem*> promptSurfaceList() const;
93+ QQmlListProperty<MirSurfaceItem> promptSurfaces();
94+
8895Q_SIGNALS:
8996 void surfaceChanged(MirSurfaceItem*);
97+ void promptSurfacesChanged();
9098
9199private Q_SLOTS:
92100 void onStateChanged(State state);
@@ -94,10 +102,15 @@ private Q_SLOTS:
94102 void createSurface();
95103
96104private:
105+ static int promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop);
106+ static MirSurfaceItem* promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index);
107+
97108 QQuickItem *m_parentItem;
98109 MirSurfaceItem* m_surface;
110+ QList<MirSurfaceItem*> m_promptSurfaces;
99111};
100112
101113Q_DECLARE_METATYPE(ApplicationInfo*)
114+Q_DECLARE_METATYPE(QQmlListProperty<MirSurfaceItem>)
102115
103116#endif // APPLICATION_H
tests/mocks/Unity/Application/ApplicationManager.cpp+3
@@ -51,6 +51,7 @@ ApplicationManager::ApplicationManager(QObject *parent)
5151{
5252 m_roleNames.insert(RoleSurface, "surface");
5353 m_roleNames.insert(RoleFullscreen, "fullscreen");
54+ m_roleNames.insert(RoleApplication, "application");
5455
5556 buildListOfAvailableApplications();
5657
@@ -92,6 +93,8 @@ QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
9293 return QVariant::fromValue(app->surface());
9394 case RoleFullscreen:
9495 return app->fullscreen();
96+ case RoleApplication:
97+ return QVariant::fromValue(app);
9598 default:
9699 return QVariant();
97100 }
tests/mocks/Unity/Application/ApplicationManager.h+1
@@ -53,6 +53,7 @@ class ApplicationManager : public ApplicationManagerInterface {
5353 enum MoreRoles {
5454 RoleSurface = RoleScreenshot+1,
5555 RoleFullscreen,
56+ RoleApplication,
5657 };
5758 enum Role {
5859 Dash, Default, Indicators, Notifications, Greeter, Launcher, OnScreenKeyboard,
tests/mocks/Unity/Application/MirSurfaceItem.cpp+16−8
@@ -34,6 +34,8 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
3434 , m_parentSurface(nullptr)
3535 , m_haveInputMethod(false)
3636{
37+ qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
38+
3739 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
3840
3941 // The virtual keyboard (input method) has a big transparent area so that
@@ -46,6 +48,8 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
4648
4749MirSurfaceItem::~MirSurfaceItem()
4850{
51+ qDebug() << "MirSurfaceItem::~MirSurfaceItem() " << name();
52+
4953 QList<MirSurfaceItem*> children(m_children);
5054 for (MirSurfaceItem* child : children) {
5155 child->setParentSurface(nullptr);
@@ -54,7 +58,7 @@ MirSurfaceItem::~MirSurfaceItem()
5458 m_parentSurface->removeChildSurface(this);
5559
5660 if (m_application)
57− m_application->setSurface(nullptr);
61+ m_application->removeSurface(this);
5862}
5963
6064void MirSurfaceItem::paint(QPainter * painter)
@@ -75,7 +79,7 @@ void MirSurfaceItem::release()
7579 }
7680
7781 if (m_application) {
78− m_application->setSurface(nullptr);
82+ m_application->removeSurface(this);
7983 }
8084 if (!parent()) {
8185 deleteLater();
@@ -104,20 +108,24 @@ void MirSurfaceItem::setParentSurface(MirSurfaceItem* surface)
104108 Q_EMIT parentSurfaceChanged(surface);
105109}
106110
111+void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
112+{
113+ qDebug() << "MirSurfaceItem::addChildSurface " << surface->name() << " to " << name();
114+
115+ m_children.append(surface);
116+ Q_EMIT childSurfacesChanged();
117+}
118+
107119void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
108120{
121+ qDebug() << "MirSurfaceItem::removeChildSurface " << surface->name() << " from " << name();
122+
109123 if (m_children.contains(surface)) {
110124 m_children.removeOne(surface);
111125 Q_EMIT childSurfacesChanged();
112126 }
113127}
114128
115−void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
116−{
117− m_children.append(surface);
118− Q_EMIT childSurfacesChanged();
119−}
120−
121129QList<MirSurfaceItem*> MirSurfaceItem::childSurfaceList()
122130{
123131 return m_children;
tests/mocks/Unity/Application/MirSurfaceItem.h+1
@@ -117,5 +117,6 @@ private:
117117};
118118
119119Q_DECLARE_METATYPE(MirSurfaceItem*)
120+Q_DECLARE_METATYPE(QList<MirSurfaceItem*>)
120121
121122#endif // MIRSURFACEITEM_H