Merge lp:~nick-dedekind/unity8/lp1352977 into lp:unity8

Proposed by Nick Dedekind on 2014-08-07
Status: Merged
Approved by: Gerry Boland on 2014-08-08
Approved revision: 1137
Merged at revision: 1136
Proposed branch: lp:~nick-dedekind/unity8/lp1352977
Merge into: lp:unity8
Diff against target: 538 lines (+202/-88)
12 files modified
debian/control (+1/-1)
qml/Stages/AppSurfaceContainer.qml (+96/-0)
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/-0)
tests/mocks/Unity/Application/ApplicationInfo.h (+13/-0)
tests/mocks/Unity/Application/ApplicationManager.cpp (+3/-0)
tests/mocks/Unity/Application/ApplicationManager.h (+1/-0)
tests/mocks/Unity/Application/MirSurfaceItem.cpp (+16/-8)
tests/mocks/Unity/Application/MirSurfaceItem.h (+1/-0)
To merge this branch: bzr merge lp:~nick-dedekind/unity8/lp1352977
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration 2014-08-07 Needs Fixing on 2014-08-09
Gerry Boland (community) code Approve on 2014-08-08
Daniel d'Andrada (community) 2014-08-07 Needs Fixing on 2014-08-08
Review via email: mp+229945@code.launchpad.net

This proposal supersedes a proposal from 2014-08-07.

Commit message

Added application prompt surfaces to allow prompting application which have not yet created a surface.

Description of the change

Added application prompt surfaces to allow prompting application which have not yet created a surface.

 * Are there any related MPs required for this MP to build/function as expected? Please list.
https://code.launchpad.net/~nick-dedekind/qtmir/lp1352977/+merge/229942

 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

 * Did you make sure that your branch does not contain spurious tags?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
No

 * If you changed the UI, has there been a design review?
No

To post a comment you must log in.
lp:~nick-dedekind/unity8/lp1352977 updated on 2014-08-07
1134. By PS Jenkins bot on 2014-08-07

Resync trunk

1135. By Nick Dedekind on 2014-08-07

added prompt surfaces

lp:~nick-dedekind/unity8/lp1352977 updated on 2014-08-08
1136. By Nick Dedekind on 2014-08-08

Fixed promptSurface over app splash

1137. By Nick Dedekind on 2014-08-08

better mock logging

Daniel d'Andrada (dandrader) wrote :

> This gonna clash big time with https://code.launchpad.net/~nick-
> dedekind/unity8/lp1352977/+merge/229945 :(

I meant https://code.launchpad.net/~dandrader/unity8/lifecycle/+merge/230090

Daniel d'Andrada (dandrader) wrote :

It's time to have qmltests for the prompt sessions stuff. We overlooked them during the rush to get qtcomp landed but now we're past that.

review: Needs Fixing
Gerry Boland (gerboland) wrote :

I can't fault your approach, considering the changes to qtmir.

nitpick:
+ Loader {
+ z: 3
+ id: splashLoader

id should be first

But not worth blocking on.

review: Approve (code)
Gerry Boland (gerboland) wrote :

<sil2100> greyback: I think tvoss did a functional review ;)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2014-08-06 19:38:57 +0000
3+++ debian/control 2014-08-08 09:41:06 +0000
4@@ -83,7 +83,7 @@
5 qmenumodel-qml (>= 0.2.8),
6 qml-module-qtquick-xmllistmodel,
7 qtdeclarative5-gsettings1.0,
8- qtdeclarative5-qtmir-plugin (>= 0.4),
9+ qtdeclarative5-qtmir-plugin (>= 0.4.1),
10 qtdeclarative5-ubuntu-settings-components (>= 0.3),
11 qtdeclarative5-ubuntu-telephony0.1,
12 unity-launcher-impl-3,
13
14=== added file 'qml/Stages/AppSurfaceContainer.qml'
15--- qml/Stages/AppSurfaceContainer.qml 1970-01-01 00:00:00 +0000
16+++ qml/Stages/AppSurfaceContainer.qml 2014-08-08 09:41:06 +0000
17@@ -0,0 +1,96 @@
18+/*
19+ * Copyright 2014 Canonical Ltd.
20+ *
21+ * This program is free software; you can redistribute it and/or modify
22+ * it under the terms of the GNU Lesser General Public License as published by
23+ * the Free Software Foundation; version 3.
24+ *
25+ * This program is distributed in the hope that it will be useful,
26+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
27+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28+ * GNU Lesser General Public License for more details.
29+ *
30+ * You should have received a copy of the GNU Lesser General Public License
31+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
32+*/
33+
34+import QtQuick 2.0
35+import "Animations"
36+
37+SurfaceContainer {
38+ id: container
39+ property var promptSurfaces
40+
41+ property bool appHasCreatedASurface: false
42+
43+ onSurfaceChanged: {
44+ if (surface) {
45+ if (!appHasCreatedASurface) {
46+ surface.visible = false; // hide until splash screen removed
47+ appHasCreatedASurface = true;
48+ }
49+ }
50+ }
51+
52+ function revealSurface() {
53+ surface.visible = true;
54+ splashLoader.source = "";
55+ }
56+
57+ Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
58+ id: surfaceRevealDelay
59+ interval: 100
60+ onTriggered: surfaceContainer.revealSurface()
61+ }
62+
63+ Loader {
64+ z: 3
65+ id: splashLoader
66+ anchors.fill: parent
67+ }
68+
69+ Repeater {
70+ model: container.promptSurfaces
71+
72+ delegate: SurfaceContainer {
73+ anchors {
74+ fill: container
75+ topMargin: container.surface.anchors.topMargin
76+ rightMargin: container.surface.anchors.rightMargin
77+ bottomMargin: container.surface.anchors.bottomMargin
78+ leftMargin: container.surface.anchors.leftMargin
79+ }
80+
81+ z: 4 + index
82+ surface: modelData
83+
84+ Component.onCompleted: {
85+ animateIn();
86+ }
87+ }
88+ }
89+
90+ StateGroup {
91+ id: appSurfaceState
92+ states: [
93+ State {
94+ name: "noSurfaceYet"
95+ when: !surfaceContainer.appHasCreatedASurface
96+ StateChangeScript {
97+ script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
98+ }
99+ },
100+ State {
101+ name: "hasSurface"
102+ when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null)
103+ StateChangeScript { script: { surfaceRevealDelay.start(); } }
104+ },
105+ State {
106+ name: "surfaceLostButAppStillAlive"
107+ when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null)
108+ // TODO - use app snapshot
109+ }
110+ ]
111+ state: "noSurfaceYet"
112+ }
113+}
114
115=== modified file 'qml/Stages/SpreadDelegate.qml'
116--- qml/Stages/SpreadDelegate.qml 2014-07-29 11:35:10 +0000
117+++ qml/Stages/SpreadDelegate.qml 2014-08-08 09:41:06 +0000
118@@ -35,26 +35,12 @@
119 signal clicked()
120 signal closed()
121
122- SurfaceContainer {
123+ AppSurfaceContainer {
124 id: surfaceContainer
125 objectName: "surfaceContainer"
126 anchors.fill: parent
127 surface: model.surface
128- property bool appHasCreatedASurface: false
129-
130- onSurfaceChanged: {
131- if (surface) {
132- if (!appHasCreatedASurface) {
133- surface.visible = false; // hide until splash screen removed
134- appHasCreatedASurface = true;
135- }
136- }
137- }
138-
139- function revealSurface() {
140- surface.visible = true;
141- splashLoader.source = "";
142- }
143+ promptSurfaces: model.application.promptSurfaces
144
145 Binding {
146 target: surfaceContainer.surface
147@@ -75,12 +61,6 @@
148 value: root.interactive
149 }
150
151- Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
152- id: surfaceRevealDelay
153- interval: 100
154- onTriggered: surfaceContainer.revealSurface()
155- }
156-
157 Connections {
158 target: surface
159 // FIXME: I would rather not need to do this, but currently it doesn't get
160@@ -115,36 +95,6 @@
161 }
162 }
163
164-
165- StateGroup {
166- id: appSurfaceState
167- states: [
168- State {
169- name: "noSurfaceYet"
170- when: !surfaceContainer.appHasCreatedASurface
171- StateChangeScript {
172- script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
173- }
174- },
175- State {
176- name: "hasSurface"
177- when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null)
178- StateChangeScript { script: { surfaceRevealDelay.start(); } }
179- },
180- State {
181- name: "surfaceLostButAppStillAlive"
182- when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null)
183- // TODO - use app snapshot
184- }
185- ]
186- state: "noSurfaceYet"
187- }
188-
189- Loader {
190- id: splashLoader
191- anchors.fill: surfaceContainer
192- }
193-
194 DraggingArea {
195 id: dragArea
196 anchors.fill: parent
197
198=== modified file 'qml/Stages/SurfaceContainer.qml'
199--- qml/Stages/SurfaceContainer.qml 2014-07-23 12:23:10 +0000
200+++ qml/Stages/SurfaceContainer.qml 2014-08-08 09:41:06 +0000
201@@ -40,19 +40,12 @@
202 childSurfaces[i].removed();
203 }
204
205- //if we don't have children, nothing will tell us to animate out, so do it.
206- if (childSurfaces.length === 0) {
207- animateOut();
208- }
209- // tell our parent to animate out.
210- if (surface.parentSurface) {
211- surface.parentSurface.parent.animateOut();
212- }
213+ animateOut();
214 }
215 }
216
217 Repeater {
218- model: container.surface ? container.surface.childSurfaces : 0
219+ model: surface.childSurfaces
220
221 delegate: Loader {
222 z: 2
223@@ -68,14 +61,13 @@
224 source: Qt.resolvedUrl("SurfaceContainer.qml")
225 onLoaded: {
226 item.surface = modelData;
227- item.animateIn(swipeFromBottom);
228- container.animateIn(swipeUp);
229+ item.animateIn();
230 }
231 }
232 }
233
234- function animateIn(component) {
235- var animation = component.createObject(container, { "surface": container.surface });
236+ function animateIn() {
237+ var animation = swipeFromBottom.createObject(container, { "surface": container.surface });
238 animation.start();
239
240 var tmp = d.animations;
241@@ -104,20 +96,11 @@
242 id: swipeFromBottom
243 SwipeFromBottomAnimation {}
244 }
245- Component {
246- id: swipeUp
247- SwipeUpAnimation {}
248- }
249- Component {
250- id: darkenFade
251- DarkenAndFadeInAnimation {}
252- }
253
254 states: [
255 State {
256 name: "initial"
257 PropertyChanges { target: surface; anchors.fill: container }
258 }
259- // TODO: more animations!
260 ]
261 }
262
263=== modified file 'tests/mocks/Unity/Application/ApplicationDBusAdaptor.cpp'
264--- tests/mocks/Unity/Application/ApplicationDBusAdaptor.cpp 2014-07-25 05:39:21 +0000
265+++ tests/mocks/Unity/Application/ApplicationDBusAdaptor.cpp 2014-08-08 09:41:06 +0000
266@@ -43,9 +43,9 @@
267 return child ? child : surface;
268 }
269
270-quint32 ApplicationDBusAdaptor::addChildSurface(const QString &appId, const QString &surfaceImage)
271+quint32 ApplicationDBusAdaptor::addPromptSurface(const QString &appId, const QString &surfaceImage)
272 {
273- qDebug() << "ApplicationDBusAdaptor::addChildSurface - " << appId;
274+ qDebug() << "ApplicationDBusAdaptor::addPromptSurface to " << appId;
275
276 ApplicationInfo* application = m_applicationManager->findApplication(appId);
277 if (!application) {
278@@ -53,12 +53,18 @@
279 return 0;
280 }
281 quint32 surfaceId = ++nextId;
282- MirSurfaceItem* surface = new MirSurfaceItem(QString("ChildSurface%1").arg(surfaceId),
283+ MirSurfaceItem* surface = new MirSurfaceItem(QString("%1-ChildSurface%2").arg(appId).arg(surfaceId),
284 MirSurfaceItem::Normal,
285 MirSurfaceItem::Maximized,
286 QUrl(surfaceImage));
287 m_childItems[surfaceId] = surface;
288- surface->setParentSurface(topSurface(application->surface()));
289+
290+ if (application->promptSurfaceList().count() > 0) {
291+ surface->setParentSurface(topSurface(application->promptSurfaceList()[0]));
292+ } else {
293+ application->addPromptSurface(surface);
294+ }
295+
296 return surfaceId;
297 }
298
299
300=== modified file 'tests/mocks/Unity/Application/ApplicationDBusAdaptor.h'
301--- tests/mocks/Unity/Application/ApplicationDBusAdaptor.h 2014-07-19 12:06:55 +0000
302+++ tests/mocks/Unity/Application/ApplicationDBusAdaptor.h 2014-08-08 09:41:06 +0000
303@@ -31,7 +31,7 @@
304 ApplicationDBusAdaptor(ApplicationManager* applicationManager);
305
306 public Q_SLOTS:
307- quint32 addChildSurface(const QString& appId, const QString& surfaceImage);
308+ quint32 addPromptSurface(const QString& appId, const QString& surfaceImage);
309 void removeChildSurface(int surfaceId);
310
311 private:
312
313=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp'
314--- tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-07-25 00:10:11 +0000
315+++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-08-08 09:41:06 +0000
316@@ -78,6 +78,7 @@
317
318 void ApplicationInfo::setSurface(MirSurfaceItem* surface)
319 {
320+ qDebug() << "Application::setSurface - appId=" << appId() << "surface=" << surface;
321 if (m_surface == surface)
322 return;
323
324@@ -98,3 +99,55 @@
325 Q_EMIT surfaceChanged(m_surface);
326 SurfaceManager::singleton()->registerSurface(m_surface);
327 }
328+
329+void ApplicationInfo::addPromptSurface(MirSurfaceItem* surface)
330+{
331+ qDebug() << "ApplicationInfo::addPromptSurface " << surface->name() << " to " << name();
332+ if (surface == m_surface || m_promptSurfaces.contains(surface)) return;
333+
334+ surface->setApplication(this);
335+ m_promptSurfaces.append(surface);
336+ Q_EMIT promptSurfacesChanged();
337+}
338+
339+void ApplicationInfo::removeSurface(MirSurfaceItem* surface)
340+{
341+ if (m_surface == surface) {
342+ setSurface(nullptr);
343+ } else if (m_promptSurfaces.contains(surface)) {
344+ qDebug() << "Application::removeSurface " << surface->name() << " from " << name();
345+
346+ m_promptSurfaces.removeAll(surface);
347+ surface->setApplication(nullptr);
348+
349+ Q_EMIT promptSurfacesChanged();
350+ }
351+}
352+
353+QList<MirSurfaceItem*> ApplicationInfo::promptSurfaceList() const
354+{
355+ return m_promptSurfaces;
356+}
357+
358+QQmlListProperty<MirSurfaceItem> ApplicationInfo::promptSurfaces()
359+{
360+ return QQmlListProperty<MirSurfaceItem>(this,
361+ 0,
362+ ApplicationInfo::promptSurfaceCount,
363+ ApplicationInfo::promptSurfaceAt);
364+}
365+
366+int ApplicationInfo::promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop)
367+{
368+ ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
369+ return p->m_promptSurfaces.count();
370+}
371+
372+MirSurfaceItem* ApplicationInfo::promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index)
373+{
374+ ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
375+
376+ if (index < 0 || index >= p->m_promptSurfaces.count())
377+ return nullptr;
378+ return p->m_promptSurfaces[index];
379+}
380
381=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.h'
382--- tests/mocks/Unity/Application/ApplicationInfo.h 2014-07-25 00:10:11 +0000
383+++ tests/mocks/Unity/Application/ApplicationInfo.h 2014-08-08 09:41:06 +0000
384@@ -38,6 +38,7 @@
385 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
386 Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
387 Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
388+ Q_PROPERTY(QQmlListProperty<MirSurfaceItem> promptSurfaces READ promptSurfaces NOTIFY promptSurfacesChanged DESIGNABLE false)
389
390 // Only exists in this fake implementation
391
392@@ -85,8 +86,15 @@
393 void setSurface(MirSurfaceItem* surface);
394 MirSurfaceItem* surface() const { return m_surface; }
395
396+ void removeSurface(MirSurfaceItem* surface);
397+
398+ void addPromptSurface(MirSurfaceItem* surface);
399+ QList<MirSurfaceItem*> promptSurfaceList() const;
400+ QQmlListProperty<MirSurfaceItem> promptSurfaces();
401+
402 Q_SIGNALS:
403 void surfaceChanged(MirSurfaceItem*);
404+ void promptSurfacesChanged();
405
406 private Q_SLOTS:
407 void onStateChanged(State state);
408@@ -94,10 +102,15 @@
409 void createSurface();
410
411 private:
412+ static int promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop);
413+ static MirSurfaceItem* promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index);
414+
415 QQuickItem *m_parentItem;
416 MirSurfaceItem* m_surface;
417+ QList<MirSurfaceItem*> m_promptSurfaces;
418 };
419
420 Q_DECLARE_METATYPE(ApplicationInfo*)
421+Q_DECLARE_METATYPE(QQmlListProperty<MirSurfaceItem>)
422
423 #endif // APPLICATION_H
424
425=== modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp'
426--- tests/mocks/Unity/Application/ApplicationManager.cpp 2014-07-29 11:41:39 +0000
427+++ tests/mocks/Unity/Application/ApplicationManager.cpp 2014-08-08 09:41:06 +0000
428@@ -51,6 +51,7 @@
429 {
430 m_roleNames.insert(RoleSurface, "surface");
431 m_roleNames.insert(RoleFullscreen, "fullscreen");
432+ m_roleNames.insert(RoleApplication, "application");
433
434 buildListOfAvailableApplications();
435
436@@ -92,6 +93,8 @@
437 return QVariant::fromValue(app->surface());
438 case RoleFullscreen:
439 return app->fullscreen();
440+ case RoleApplication:
441+ return QVariant::fromValue(app);
442 default:
443 return QVariant();
444 }
445
446=== modified file 'tests/mocks/Unity/Application/ApplicationManager.h'
447--- tests/mocks/Unity/Application/ApplicationManager.h 2014-07-25 00:10:11 +0000
448+++ tests/mocks/Unity/Application/ApplicationManager.h 2014-08-08 09:41:06 +0000
449@@ -53,6 +53,7 @@
450 enum MoreRoles {
451 RoleSurface = RoleScreenshot+1,
452 RoleFullscreen,
453+ RoleApplication,
454 };
455 enum Role {
456 Dash, Default, Indicators, Notifications, Greeter, Launcher, OnScreenKeyboard,
457
458=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp'
459--- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-07-25 05:39:21 +0000
460+++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-08-08 09:41:06 +0000
461@@ -34,6 +34,8 @@
462 , m_parentSurface(nullptr)
463 , m_haveInputMethod(false)
464 {
465+ qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
466+
467 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
468
469 // The virtual keyboard (input method) has a big transparent area so that
470@@ -46,6 +48,8 @@
471
472 MirSurfaceItem::~MirSurfaceItem()
473 {
474+ qDebug() << "MirSurfaceItem::~MirSurfaceItem() " << name();
475+
476 QList<MirSurfaceItem*> children(m_children);
477 for (MirSurfaceItem* child : children) {
478 child->setParentSurface(nullptr);
479@@ -54,7 +58,7 @@
480 m_parentSurface->removeChildSurface(this);
481
482 if (m_application)
483- m_application->setSurface(nullptr);
484+ m_application->removeSurface(this);
485 }
486
487 void MirSurfaceItem::paint(QPainter * painter)
488@@ -75,7 +79,7 @@
489 }
490
491 if (m_application) {
492- m_application->setSurface(nullptr);
493+ m_application->removeSurface(this);
494 }
495 if (!parent()) {
496 deleteLater();
497@@ -104,20 +108,24 @@
498 Q_EMIT parentSurfaceChanged(surface);
499 }
500
501+void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
502+{
503+ qDebug() << "MirSurfaceItem::addChildSurface " << surface->name() << " to " << name();
504+
505+ m_children.append(surface);
506+ Q_EMIT childSurfacesChanged();
507+}
508+
509 void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
510 {
511+ qDebug() << "MirSurfaceItem::removeChildSurface " << surface->name() << " from " << name();
512+
513 if (m_children.contains(surface)) {
514 m_children.removeOne(surface);
515 Q_EMIT childSurfacesChanged();
516 }
517 }
518
519-void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
520-{
521- m_children.append(surface);
522- Q_EMIT childSurfacesChanged();
523-}
524-
525 QList<MirSurfaceItem*> MirSurfaceItem::childSurfaceList()
526 {
527 return m_children;
528
529=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.h'
530--- tests/mocks/Unity/Application/MirSurfaceItem.h 2014-07-25 06:50:09 +0000
531+++ tests/mocks/Unity/Application/MirSurfaceItem.h 2014-08-08 09:41:06 +0000
532@@ -117,5 +117,6 @@
533 };
534
535 Q_DECLARE_METATYPE(MirSurfaceItem*)
536+Q_DECLARE_METATYPE(QList<MirSurfaceItem*>)
537
538 #endif // MIRSURFACEITEM_H

Subscribers

People subscribed via source and target branches