on xenial help sign in
Sessions-in-sessions
8183eb1Nick Dedekind
qml/Stages/Animations/BaseSurfaceAnimation.qml+2−2
@@ -37,7 +37,7 @@ import QtQuick 2.0
37 */
37 */
38Item {
38Item {
39 id: base
39 id: base
40− property Item surface: null
40+ property Item session: null
41
41
42 // changes applied when state changes to "in"
42 // changes applied when state changes to "in"
43 property list<QtObject> outChanges
43 property list<QtObject> outChanges
@@ -61,7 +61,7 @@ Item {
61 states: [
61 states: [
62 State {
62 State {
63 name: "baseAnimation"
63 name: "baseAnimation"
64− PropertyChanges { target: base.surface; anchors.fill: undefined }
64+ PropertyChanges { target: base.session; anchors.fill: undefined }
65 },
65 },
66
66
67 State {
67 State {
qml/Stages/Animations/SwipeFromBottomAnimation.qml+4−4
@@ -19,20 +19,20 @@ import QtQuick 2.0
19BaseSurfaceAnimation {
19BaseSurfaceAnimation {
20 id: animation
20 id: animation
21
21
22− outChanges: [ AnchorChanges { target: animation.surface; anchors.top: animation.parent.bottom } ]
22+ outChanges: [ AnchorChanges { target: animation.session; anchors.top: animation.parent.bottom } ]
23 outAnimations: [
23 outAnimations: [
24 SequentialAnimation {
24 SequentialAnimation {
25 PropertyAction { target: animation.parent; property: "clip"; value: true }
25 PropertyAction { target: animation.parent; property: "clip"; value: true }
26 AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
26 AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
27− PropertyAction { target: animation.surface; property: "visible"; value: !animation.parent.removing }
27+ PropertyAction { target: animation.session; property: "visible"; value: !animation.parent.removing }
28 PropertyAction { target: animation.parent; property: "clip"; value: false }
28 PropertyAction { target: animation.parent; property: "clip"; value: false }
29− ScriptAction { script: { if (animation.parent.removing) animation.surface.release(); } }
29+ ScriptAction { script: { if (animation.parent.removing) animation.session.release(); } }
30 }
30 }
31 ]
31 ]
32
32
33 inChanges: [
33 inChanges: [
34 AnchorChanges {
34 AnchorChanges {
35− target: animation.surface;
35+ target: animation.session;
36 anchors.top: animation.parent.top
36 anchors.top: animation.parent.top
37 anchors.right: undefined
37 anchors.right: undefined
38 anchors.bottom: undefined
38 anchors.bottom: undefined
qml/Stages/Animations/SwipeUpAnimation.qml+4−4
@@ -22,16 +22,16 @@ BaseSurfaceAnimation {
22 outAnimations: [
22 outAnimations: [
23 SequentialAnimation {
23 SequentialAnimation {
24 PropertyAction { target: animation.parent; property: "clip"; value: true }
24 PropertyAction { target: animation.parent; property: "clip"; value: true }
25− PropertyAction { target: animation.surface; property: "visible"; value: true }
25+ PropertyAction { target: animation.session; property: "visible"; value: true }
26 AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
26 AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
27 PropertyAction { target: animation.parent; property: "clip"; value: false }
27 PropertyAction { target: animation.parent; property: "clip"; value: false }
28− ScriptAction { script: { if (animation.parent.removing) animation.surface.release(); } }
28+ ScriptAction { script: { if (animation.parent.removing) animation.session.release(); } }
29 }
29 }
30 ]
30 ]
31
31
32 inChanges: [
32 inChanges: [
33 AnchorChanges {
33 AnchorChanges {
34− target: animation.surface;
34+ target: animation.session;
35 anchors.top: undefined
35 anchors.top: undefined
36 anchors.right: undefined
36 anchors.right: undefined
37 anchors.bottom: animation.parent.top
37 anchors.bottom: animation.parent.top
@@ -42,7 +42,7 @@ BaseSurfaceAnimation {
42 SequentialAnimation {
42 SequentialAnimation {
43 PropertyAction { target: animation.parent; property: "clip"; value: true }
43 PropertyAction { target: animation.parent; property: "clip"; value: true }
44 AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
44 AnchorAnimation { easing.type: Easing.InOutQuad; duration: 400 }
45− PropertyAction { target: animation.surface; property: "visible"; value: false}
45+ PropertyAction { target: animation.session; property: "visible"; value: false}
46 PropertyAction { target: animation.parent; property: "clip"; value: false }
46 PropertyAction { target: animation.parent; property: "clip"; value: false }
47 }
47 }
48 ]
48 ]
qml/Stages/AppSurfaceContainer.qml → qml/Stages/ApplicationSessionContainer.qmlrenamed+1−47
@@ -17,10 +17,8 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import "Animations"
18import "Animations"
19
19
20−SurfaceContainer {
20+SessionContainer {
21 id: root
21 id: root
22− property var promptSurfaces
23−
24 property bool appHasCreatedASurface: false
22 property bool appHasCreatedASurface: false
25
23
26 onSurfaceChanged: {
24 onSurfaceChanged: {
@@ -49,50 +47,6 @@ SurfaceContainer {
49 z: 3
47 z: 3
50 }
48 }
51
49
52− Repeater {
53− id: promptRepeater
54− model: root.promptSurfaces
55−
56− delegate: SurfaceContainer {
57− objectName: "promptDelegate" + index
58− id: prompt
59−
60− anchors {
61− fill: root
62− topMargin: root.surface.anchors.topMargin
63− rightMargin: root.surface.anchors.rightMargin
64− bottomMargin: root.surface.anchors.bottomMargin
65− leftMargin: root.surface.anchors.leftMargin
66− }
67− z: 4 + index
68−
69− surface: modelData
70−
71− Component.onCompleted: {
72− prompt.animateIn(swipeFromBottom);
73− }
74−
75− Connections {
76− target: prompt.surface
77− onRemoved: {
78− // remove all prompts after this one.
79− if (index !== promptRepeater.count-1) {
80− var nextSurface = promptRepeater.itemAt(index+1).surface;
81− nextSurface.removed();
82− }
83−
84− prompt.removing = true;
85− prompt.animateOut();
86− }
87− }
88−
89− Component {
90− id: swipeFromBottom
91− SwipeFromBottomAnimation {}
92− }
93− }
94− }
95−
96 StateGroup {
50 StateGroup {
97 id: appSurfaceState
51 id: appSurfaceState
98 states: [
52 states: [
qml/Stages/SessionContainer.qmlnew file+113
@@ -0,0 +1,113 @@
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+Item {
21+ id: root
22+ objectName: "sessionContainer"
23+ property Item session
24+ property var children: session ? session.childSessions : 0
25+ property bool removing: false
26+ property alias surface: surfaceContainer.surface
27+
28+ onSessionChanged: {
29+ if (session) {
30+ session.parent = root;
31+ session.z = 1;
32+ state = "initial"
33+ }
34+ }
35+
36+ SurfaceContainer {
37+ id: surfaceContainer
38+ anchors.fill: session
39+ z: 2;
40+
41+ surface: session ? session.surface : null
42+ onSurfaceChanged: {
43+ root.animateIn(swipeFromBottom);
44+ }
45+ }
46+
47+ Repeater {
48+ model: root.children
49+
50+ delegate: Loader {
51+ objectName: "childDelegate" + index
52+ anchors {
53+ fill: root
54+ topMargin: root.surface.anchors.topMargin
55+ rightMargin: root.surface.anchors.rightMargin
56+ bottomMargin: root.surface.anchors.bottomMargin
57+ leftMargin: root.surface.anchors.leftMargin
58+ }
59+ z: 4
60+
61+ // Only way to do recursive qml items.
62+ source: Qt.resolvedUrl("SessionContainer.qml")
63+ onLoaded: {
64+ item.session = modelData;
65+ }
66+
67+ Connections {
68+ target: modelData
69+ onRemoved: {
70+ item.animateOut();
71+ }
72+ }
73+ }
74+ }
75+
76+ function animateIn(animationComponent) {
77+ var animation = animationComponent.createObject(root, { "session": root.session });
78+ animation.start();
79+
80+ var tmp = d.animations;
81+ tmp.push(animation);
82+ d.animations = tmp;
83+ }
84+
85+ function animateOut() {
86+ if (d.animations.length > 0) {
87+ var tmp = d.animations;
88+ var popped = tmp.pop();
89+ popped.end();
90+ d.animations = tmp;
91+ } else {
92+ root.state = "initial";
93+ }
94+ }
95+
96+ QtObject {
97+ id: d
98+ property var animations: []
99+ property var currentAnimation: animations.length > 0 ? animations[animations.length-1] : undefined
100+ }
101+
102+ Component {
103+ id: swipeFromBottom
104+ SwipeFromBottomAnimation {}
105+ }
106+
107+ states: [
108+ State {
109+ name: "initial"
110+ PropertyChanges { target: session; anchors.fill: root }
111+ }
112+ ]
113+}
qml/Stages/SpreadDelegate.qml+6−6
@@ -29,24 +29,24 @@ Item {
29 property bool dropShadow: true
29 property bool dropShadow: true
30 property real maximizedAppTopMargin
30 property real maximizedAppTopMargin
31 property alias swipeToCloseEnabled: dragArea.enabled
31 property alias swipeToCloseEnabled: dragArea.enabled
32+ property alias surface: surfaceContainer.surface
32
33
33− readonly property bool isFullscreen: surface !== null && surfaceContainer.surface.anchors.topMargin == 0
34+ readonly property bool isFullscreen: surface !== null && session.anchors.topMargin == 0
34
35
35 signal clicked()
36 signal clicked()
36 signal closed()
37 signal closed()
37
38
38− AppSurfaceContainer {
39+ ApplicationSessionContainer {
39 id: surfaceContainer
40 id: surfaceContainer
40 objectName: "surfaceContainer"
41 objectName: "surfaceContainer"
41 anchors.fill: parent
42 anchors.fill: parent
42− surface: model.surface
43+ session: model.session
43− promptSurfaces: model.promptSurfaces
44
44
45 Binding {
45 Binding {
46− target: surfaceContainer.surface
46+ target: surface
47 property: "anchors.topMargin"
47 property: "anchors.topMargin"
48 value: {
48 value: {
49− return surfaceContainer.surface == null ||
49+ return surface == null ||
50 surfaceContainer.surface.state === MirSurfaceItem.Fullscreen ? 0 : maximizedAppTopMargin;
50 surfaceContainer.surface.state === MirSurfaceItem.Fullscreen ? 0 : maximizedAppTopMargin;
51 }
51 }
52 }
52 }
qml/Stages/SurfaceContainer.qml+9−45
@@ -25,6 +25,7 @@ Item {
25 property bool removing: false
25 property bool removing: false
26
26
27 onSurfaceChanged: {
27 onSurfaceChanged: {
28+ console.log("SURFACE " + surface)
28 if (surface) {
29 if (surface) {
29 surface.parent = root;
30 surface.parent = root;
30 surface.z = 1;
31 surface.z = 1;
@@ -32,18 +33,19 @@ Item {
32 }
33 }
33 }
34 }
34
35
36+ Connections {
37+ target: surface
38+ onRemoved: {
39+ surface.release();
40+ }
41+ }
42+
35 Repeater {
43 Repeater {
36 model: root.childSurfaces
44 model: root.childSurfaces
37
45
38 delegate: Loader {
46 delegate: Loader {
39 objectName: "childDelegate" + index
47 objectName: "childDelegate" + index
40− anchors {
41− fill: root
48+ anchors.fill: root
42− topMargin: root.surface.anchors.topMargin
43− rightMargin: root.surface.anchors.rightMargin
44− bottomMargin: root.surface.anchors.bottomMargin
45− leftMargin: root.surface.anchors.leftMargin
46− }
47 z: 2
49 z: 2
48
50
49 // Only way to do recursive qml items.
51 // Only way to do recursive qml items.
@@ -51,47 +53,9 @@ Item {
51 onLoaded: {
53 onLoaded: {
52 item.surface = modelData;
54 item.surface = modelData;
53 }
55 }
54−
55− Connections {
56− target: modelData
57− onRemoved: {
58− modelData.release()
59− }
60− }
61− }
62− }
63−
64− function animateIn(animationComponent) {
65− var animation = animationComponent.createObject(root, { "surface": root.surface });
66− animation.start();
67−
68− var tmp = d.animations;
69− tmp.push(animation);
70− d.animations = tmp;
71− }
72−
73− function animateOut() {
74− if (d.animations.length > 0) {
75− var tmp = d.animations;
76− var popped = tmp.pop();
77− popped.end();
78− d.animations = tmp;
79− } else {
80− root.state = "initial";
81 }
56 }
82 }
57 }
83
58
84− QtObject {
85− id: d
86− property var animations: []
87− property var currentAnimation: animations.length > 0 ? animations[animations.length-1] : undefined
88− }
89−
90− Component {
91− id: swipeFromBottom
92− SwipeFromBottomAnimation {}
93− }
94−
95 states: [
59 states: [
96 State {
60 State {
97 name: "initial"
61 name: "initial"
tests/mocks/Unity/Application/ApplicationInfo.cpp+24−73
@@ -15,14 +15,13 @@
15 */
15 */
16
16
17#include "ApplicationInfo.h"
17#include "ApplicationInfo.h"
18−#include "MirSurfaceItem.h"
18+#include "MirSessionItem.h"
19−#include "MirSurfaceItemModel.h"
19+#include "SessionManager.h"
20
20
21#include <QGuiApplication>
21#include <QGuiApplication>
22#include <QQuickItem>
22#include <QQuickItem>
23#include <QQuickView>
23#include <QQuickView>
24#include <QQmlComponent>
24#include <QQmlComponent>
25−#include <QTimer>
26
25
27ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
26ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
28 : ApplicationInfoInterface(appId, parent)
27 : ApplicationInfoInterface(appId, parent)
@@ -32,10 +31,9 @@ ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
32 , m_focused(false)
31 , m_focused(false)
33 , m_fullscreen(false)
32 , m_fullscreen(false)
34 , m_parentItem(0)
33 , m_parentItem(0)
35− , m_surface(0)
34+ , m_session(0)
36− , m_promptSurfaces(new MirSurfaceItemModel(this))
37{
35{
38− connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged);
36+ createSession();
39}
37}
40
38
41ApplicationInfo::ApplicationInfo(QObject *parent)
39ApplicationInfo::ApplicationInfo(QObject *parent)
@@ -45,89 +43,42 @@ ApplicationInfo::ApplicationInfo(QObject *parent)
45 , m_focused(false)
43 , m_focused(false)
46 , m_fullscreen(false)
44 , m_fullscreen(false)
47 , m_parentItem(0)
45 , m_parentItem(0)
48− , m_surface(0)
46+ , m_session(0)
49− , m_promptSurfaces(new MirSurfaceItemModel(this))
50{
47{
51− connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged);
48+ createSession();
52}
49}
53
50
54ApplicationInfo::~ApplicationInfo()
51ApplicationInfo::~ApplicationInfo()
55{
52{
56− QList<MirSurfaceItem*> promptSurfaces(m_promptSurfaces->list());
53+ delete m_session;
57− for (MirSurfaceItem* promptSurface : promptSurfaces) {
58− delete promptSurface;
59− }
60−
61− delete m_surface;
62− delete m_promptSurfaces;
63}
54}
64
55
65−void ApplicationInfo::onStateChanged(State state)
56+void ApplicationInfo::createSession()
66{
57{
67− if (state == ApplicationInfo::Running) {
58+ setSession(SessionManager::singleton()->createSession(name(), screenshot()));
68− QTimer::singleShot(1000, this, SLOT(createSurface()));
69− } else if (state == ApplicationInfo::Stopped) {
70− setSurface(nullptr);
71− }
72}
59}
73
60
74−void ApplicationInfo::createSurface()
61+void ApplicationInfo::setSession(MirSessionItem* session)
75{
62{
76− if (m_surface || state() == ApplicationInfo::Stopped) return;
77−
78− setSurface(SurfaceManager::singleton()->createSurface(name(),
79− MirSurfaceItem::Normal,
80− fullscreen() ? MirSurfaceItem::Fullscreen : MirSurfaceItem::Maximized,
81− screenshot()));
82−}
83−
84−void ApplicationInfo::setSurface(MirSurfaceItem* surface)
85−{
86− qDebug() << "Application::setSurface - appId=" << appId() << "surface=" << surface;
63+ qDebug() << "Application::setSession - appId=" << appId() << "session=" << session;
87− if (m_surface == surface)
64+ if (m_session == session)
88 return;
65 return;
89
66
90− if (m_surface) {
67+ if (m_session) {
68+ disconnect(this, 0, m_session, 0);
91− m_surface->setApplication(nullptr);
69+ m_session->setApplication(nullptr);
92− m_surface->setParent(nullptr);
70+ m_session->setParent(nullptr);
93 }
71 }
94
72
95− m_surface = surface;
73+ m_session = session;
96−
97− if (m_surface) {
98− m_surface->setApplication(this);
99− m_surface->setParent(this);
100− }
101−
102− Q_EMIT surfaceChanged(m_surface);
103−}
104−
105−void ApplicationInfo::addPromptSurface(MirSurfaceItem* surface)
106−{
107− insertPromptSurface(m_promptSurfaces->count(), surface);
108−}
109−
110−void ApplicationInfo::insertPromptSurface(uint index, MirSurfaceItem* surface)
111−{
112− qDebug() << "ApplicationInfo::insertPromptSurface - " << surface->name() << " to " << name() << " @ " << index;
113
74
75+ if (m_session) {
114− surface->setApplication(this);
76+ m_session->setApplication(this);
115− m_promptSurfaces->insertSurface(index, surface);
77+ m_session->setParent(this);
116−}
78+ connect(this, &ApplicationInfo::screenshotChanged, m_session, [this](const QUrl& screenshot) {
117−
79+ m_session->setScreenshot(screenshot);
118−void ApplicationInfo::removeSurface(MirSurfaceItem* surface)
80+ });
119−{
120− qDebug() << "Application::removeSurface - " << surface->name() << " from " << name();
121−
122− if (m_surface == surface) {
123− setSurface(nullptr);
124− } else {
125− m_promptSurfaces->removeSurface(surface);
126− surface->setApplication(nullptr);
127 }
81 }
128−}
129
82
130−MirSurfaceItemModel* ApplicationInfo::promptSurfaces() const
83+ Q_EMIT sessionChanged(m_session);
131−{
132− return m_promptSurfaces;
133}
84}
tests/mocks/Unity/Application/ApplicationInfo.h+8−20
@@ -18,13 +18,13 @@
18#define APPLICATION_H
18#define APPLICATION_H
19
19
20#include "SurfaceManager.h"
20#include "SurfaceManager.h"
21+#include "MirSurfaceItemModel.h"
21
22
22#include <QObject>
23#include <QObject>
23#include <QQmlComponent>
24#include <QQmlComponent>
24
25
25class QQuickItem;
26class QQuickItem;
26class MirSurfaceItem;
27class MirSurfaceItem;
27−class MirSurfaceItemModel;
28
28
29// unity-api
29// unity-api
30#include <unity/shell/application/ApplicationInfoInterface.h>
30#include <unity/shell/application/ApplicationInfoInterface.h>
@@ -40,8 +40,7 @@ class ApplicationInfo : public ApplicationInfoInterface {
40
40
41 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
41 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
42 Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
42 Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
43− Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
43+ Q_PROPERTY(MirSessionItem* session READ session NOTIFY sessionChanged)
44− Q_PROPERTY(MirSurfaceItemModel* promptSurfaces READ promptSurfaces DESIGNABLE false CONSTANT)
45
44
46 // Only exists in this fake implementation
45 // Only exists in this fake implementation
47
46
@@ -86,30 +85,19 @@ public:
86 #undef IMPLEMENT_PROPERTY
85 #undef IMPLEMENT_PROPERTY
87
86
88public:
87public:
89− void setSurface(MirSurfaceItem* surface);
88+ void setSession(MirSessionItem* session);
90− MirSurfaceItem* surface() const { return m_surface; }
89+ MirSessionItem* session() const { return m_session; }
91−
92− void removeSurface(MirSurfaceItem* surface);
93−
94− void addPromptSurface(MirSurfaceItem* surface);
95− void insertPromptSurface(uint index, MirSurfaceItem* surface);
96− MirSurfaceItemModel* promptSurfaces() const;
97
90
98Q_SIGNALS:
91Q_SIGNALS:
99− void surfaceChanged(MirSurfaceItem*);
92+ void sessionChanged(MirSessionItem*);
100−
101−private Q_SLOTS:
102− void onStateChanged(State state);
103−
104− void createSurface();
105
93
106private:
94private:
95+ void createSession();
96+
107 QQuickItem *m_parentItem;
97 QQuickItem *m_parentItem;
108− MirSurfaceItem* m_surface;
98+ MirSessionItem* m_session;
109− MirSurfaceItemModel* m_promptSurfaces;
110};
99};
111
100
112Q_DECLARE_METATYPE(ApplicationInfo*)
101Q_DECLARE_METATYPE(ApplicationInfo*)
113−Q_DECLARE_METATYPE(QQmlListProperty<MirSurfaceItem>)
114
102
115#endif // APPLICATION_H
103#endif // APPLICATION_H
tests/mocks/Unity/Application/ApplicationManager.cpp+7−11
@@ -16,8 +16,7 @@
16
16
17#include "ApplicationManager.h"
17#include "ApplicationManager.h"
18#include "ApplicationInfo.h"
18#include "ApplicationInfo.h"
19−#include "MirSurfaceItem.h"
19+#include "MirSessionItem.h"
20−#include "MirSurfaceItemModel.h"
21#include "ApplicationTestInterface.h"
20#include "ApplicationTestInterface.h"
22
21
23#include <paths.h>
22#include <paths.h>
@@ -45,9 +44,8 @@ ApplicationManager::ApplicationManager(QObject *parent)
45 : ApplicationManagerInterface(parent)
44 : ApplicationManagerInterface(parent)
46 , m_suspended(false)
45 , m_suspended(false)
47{
46{
48− m_roleNames.insert(RoleSurface, "surface");
47+ m_roleNames.insert(RoleSession, "session");
49 m_roleNames.insert(RoleFullscreen, "fullscreen");
48 m_roleNames.insert(RoleFullscreen, "fullscreen");
50− m_roleNames.insert(RolePromptSurfaces, "promptSurfaces");
51
49
52 buildListOfAvailableApplications();
50 buildListOfAvailableApplications();
53
51
@@ -85,12 +83,10 @@ QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
85 return app->focused();
83 return app->focused();
86 case RoleScreenshot:
84 case RoleScreenshot:
87 return app->screenshot();
85 return app->screenshot();
88− case RoleSurface:
86+ case RoleSession:
89− return QVariant::fromValue(app->surface());
87+ return QVariant::fromValue(app->session());
90 case RoleFullscreen:
88 case RoleFullscreen:
91 return app->fullscreen();
89 return app->fullscreen();
92− case RolePromptSurfaces:
93− return QVariant::fromValue(app->promptSurfaces());
94 default:
90 default:
95 return QVariant();
91 return QVariant();
96 }
92 }
@@ -134,10 +130,10 @@ void ApplicationManager::add(ApplicationInfo *application) {
134 Q_EMIT countChanged();
130 Q_EMIT countChanged();
135 if (count() == 1) Q_EMIT emptyChanged(isEmpty()); // was empty but not anymore
131 if (count() == 1) Q_EMIT emptyChanged(isEmpty()); // was empty but not anymore
136
132
137− connect(application, &ApplicationInfo::surfaceChanged, this, [application, this]() {
133+ connect(application, &ApplicationInfo::sessionChanged, this, [application, this]() {
138 QModelIndex appIndex = findIndex(application);
134 QModelIndex appIndex = findIndex(application);
139 if (!appIndex.isValid()) return;
135 if (!appIndex.isValid()) return;
140− Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleSurface);
136+ Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleSession);
141 });
137 });
142}
138}
143
139
@@ -151,7 +147,7 @@ void ApplicationManager::remove(ApplicationInfo *application) {
151 Q_EMIT countChanged();
147 Q_EMIT countChanged();
152 if (isEmpty()) Q_EMIT emptyChanged(isEmpty());
148 if (isEmpty()) Q_EMIT emptyChanged(isEmpty());
153 }
149 }
154− disconnect(application, &ApplicationInfo::surfaceChanged, this, 0);
150+ disconnect(application, &ApplicationInfo::sessionChanged, this, 0);
155}
151}
156
152
157void ApplicationManager::move(int from, int to) {
153void ApplicationManager::move(int from, int to) {
tests/mocks/Unity/Application/ApplicationManager.h+1−2
@@ -51,9 +51,8 @@ class ApplicationManager : public ApplicationManagerInterface {
51 static ApplicationManager *singleton();
51 static ApplicationManager *singleton();
52
52
53 enum MoreRoles {
53 enum MoreRoles {
54− RoleSurface = RoleScreenshot+1,
54+ RoleSession = RoleScreenshot+1,
55 RoleFullscreen,
55 RoleFullscreen,
56− RolePromptSurfaces,
57 };
56 };
58 enum Role {
57 enum Role {
59 Dash, Default, Indicators, Notifications, Greeter, Launcher, OnScreenKeyboard,
58 Dash, Default, Indicators, Notifications, Greeter, Launcher, OnScreenKeyboard,
tests/mocks/Unity/Application/ApplicationTestInterface.cpp+47−22
@@ -17,9 +17,10 @@
17#include "ApplicationInfo.h"
17#include "ApplicationInfo.h"
18#include "ApplicationTestInterface.h"
18#include "ApplicationTestInterface.h"
19#include "ApplicationManager.h"
19#include "ApplicationManager.h"
20+#include "SessionManager.h"
20#include "SurfaceManager.h"
21#include "SurfaceManager.h"
22+#include "MirSessionItem.h"
21#include "MirSurfaceItem.h"
23#include "MirSurfaceItem.h"
22−#include "MirSurfaceItemModel.h"
23
24
24quint32 nextId = 0;
25quint32 nextId = 0;
25
26
@@ -31,29 +32,51 @@ ApplicationTestInterface::ApplicationTestInterface(QObject* parent)
31 connection.registerObject("/com/canonical/Unity8/Mocks", parent);
32 connection.registerObject("/com/canonical/Unity8/Mocks", parent);
32}
33}
33
34
34−quint32 ApplicationTestInterface::addPromptSurface(const QString &appId, const QString &surfaceImage)
35+quint32 ApplicationTestInterface::addChildSession(const QString& appId, quint32 existingSessionId, const QString& surfaceImage)
35{
36{
36− qDebug() << "ApplicationTestInterface::addPromptSurface to " << appId;
37+ qDebug() << "ApplicationTestInterface::addChildSession to " << appId;
37
38
38 ApplicationInfo* application = ApplicationManager::singleton()->findApplication(appId);
39 ApplicationInfo* application = ApplicationManager::singleton()->findApplication(appId);
39 if (!application) {
40 if (!application) {
40− qDebug() << "ApplicationTestInterface::addPromptSurface - No application found for " << appId;
41+ qDebug() << "ApplicationTestInterface::addChildSession - No application found for " << appId;
41 return 0;
42 return 0;
42 }
43 }
44+
45+ MirSessionItem* parentSession = nullptr;
46+ if (m_childSessions.contains(existingSessionId)) {
47+ parentSession = m_childSessions[existingSessionId];
48+ } else if (application->session()) {
49+ parentSession = application->session();
50+ } else {
51+ qDebug() << "ApplicationTestInterface::addChildSession - No session for " << appId << ":" << existingSessionId;
52+ return 0;
53+ }
54+
43− quint32 surfaceId = ++nextId;
55+ quint32 sessionId = ++nextId;
44− MirSurfaceItem* surface = SurfaceManager::singleton()->createSurface(
56+ MirSessionItem* session = SessionManager::singleton()->createSession(
45− QString("%1-Prompt%2").arg(appId)
57+ QString("%1-Child%2").arg(parentSession->name())
46− .arg(surfaceId),
58+ .arg(sessionId),
47− MirSurfaceItem::Normal,
48− MirSurfaceItem::Maximized,
49 QUrl(surfaceImage));
59 QUrl(surfaceImage));
50− m_childItems[surfaceId] = surface;
60+ parentSession->addChildSession(session);
51− application->addPromptSurface(surface);
61+ session->createSurface();
62+ m_childSessions[sessionId] = session;
52
63
53− return surfaceId;
64+ return sessionId;
65+}
66+
67+void ApplicationTestInterface::removeSession(quint32 sessionId)
68+{
69+ qDebug() << "ApplicationTestInterface::removeSession - " << sessionId;
70+
71+ if (!m_childSessions.contains(sessionId)) {
72+ qDebug() << "ApplicationTestInterface::removeSession - No added session for " << sessionId;
73+ return;
74+ }
75+ MirSessionItem* session = m_childSessions.take(sessionId);
76+ Q_EMIT session->removed();
54}
77}
55
78
56−quint32 ApplicationTestInterface::addChildSurface(const QString& appId, const quint32 existingSurfaceId, const QString& surfaceImage)
79+quint32 ApplicationTestInterface::addChildSurface(const QString& appId, quint32 existingSessionId, quint32 existingSurfaceId, const QString& surfaceImage)
57{
80{
58 qDebug() << "ApplicationTestInterface::addChildSurface to " << appId;
81 qDebug() << "ApplicationTestInterface::addChildSurface to " << appId;
59
82
@@ -64,10 +87,12 @@ quint32 ApplicationTestInterface::addChildSurface(const QString& appId, const qu
64 }
87 }
65
88
66 MirSurfaceItem* parentSurface = nullptr;
89 MirSurfaceItem* parentSurface = nullptr;
90+ if (m_childSessions.contains(existingSessionId) && m_childSessions[existingSessionId]->surface()) {
91+ parentSurface = m_childSessions[existingSessionId]->surface();
67− if (m_childItems.contains(existingSurfaceId)) {
92+ } else if (m_childSurfaces.contains(existingSurfaceId)) {
68− parentSurface = m_childItems[existingSurfaceId];
93+ parentSurface = m_childSurfaces[existingSurfaceId];
69− } else if (application->surface()) {
94+ } else if (application->session() && application->session()->surface()) {
70− parentSurface = application->surface();
95+ parentSurface = application->session()->surface();
71 } else {
96 } else {
72 qDebug() << "ApplicationTestInterface::addChildSurface - No surface for " << appId << ":" << existingSurfaceId;
97 qDebug() << "ApplicationTestInterface::addChildSurface - No surface for " << appId << ":" << existingSurfaceId;
73 return 0;
98 return 0;
@@ -81,19 +106,19 @@ quint32 ApplicationTestInterface::addChildSurface(const QString& appId, const qu
81 MirSurfaceItem::Maximized,
106 MirSurfaceItem::Maximized,
82 QUrl(surfaceImage));
107 QUrl(surfaceImage));
83 parentSurface->addChildSurface(surface);
108 parentSurface->addChildSurface(surface);
84− m_childItems[surfaceId] = surface;
109+ m_childSurfaces[surfaceId] = surface;
85
110
86 return surfaceId;
111 return surfaceId;
87}
112}
88
113
89−void ApplicationTestInterface::removeSurface(int surfaceId)
114+void ApplicationTestInterface::removeSurface(quint32 surfaceId)
90{
115{
91 qDebug() << "ApplicationTestInterface::removeSurface - " << surfaceId;
116 qDebug() << "ApplicationTestInterface::removeSurface - " << surfaceId;
92
117
93− if (!m_childItems.contains(surfaceId)) {
118+ if (!m_childSurfaces.contains(surfaceId)) {
94 qDebug() << "ApplicationTestInterface::removeSurface - No added surface for " << surfaceId;
119 qDebug() << "ApplicationTestInterface::removeSurface - No added surface for " << surfaceId;
95 return;
120 return;
96 }
121 }
97− MirSurfaceItem* surface = m_childItems.take(surfaceId);
122+ MirSurfaceItem* surface = m_childSurfaces.take(surfaceId);
98 Q_EMIT surface->removed();
123 Q_EMIT surface->removed();
99}
124}
tests/mocks/Unity/Application/ApplicationTestInterface.h+7−5
@@ -20,7 +20,7 @@
20#include <QtDBus/QtDBus>
20#include <QtDBus/QtDBus>
21
21
22class ApplicationManager;
22class ApplicationManager;
23−class SurfaceManager;
23+class MirSessionItem;
24class MirSurfaceItem;
24class MirSurfaceItem;
25
25
26class ApplicationTestInterface : public QDBusAbstractAdaptor
26class ApplicationTestInterface : public QDBusAbstractAdaptor
@@ -31,12 +31,14 @@ public:
31 ApplicationTestInterface(QObject* parent = 0);
31 ApplicationTestInterface(QObject* parent = 0);
32
32
33public Q_SLOTS:
33public Q_SLOTS:
34− Q_INVOKABLE quint32 addPromptSurface(const QString& appId, const QString& surfaceImage);
34+ Q_INVOKABLE quint32 addChildSession(const QString& appId, quint32 existingSessionId, const QString& surfaceImage);
35− Q_INVOKABLE quint32 addChildSurface(const QString& appId, const quint32 existingSurfaceId, const QString& surfaceImage);
35+ Q_INVOKABLE quint32 addChildSurface(const QString& appId, quint32 existingSessionId, quint32 existingSurfaceId, const QString& surfaceImage);
36+ Q_INVOKABLE void removeSession(quint32 sessionId);
36− Q_INVOKABLE void removeSurface(int surfaceId);
37+ Q_INVOKABLE void removeSurface(quint32 surfaceId);
37
38
38private:
39private:
39− QHash<quint32, MirSurfaceItem*> m_childItems;
40+ QHash<quint32, MirSessionItem*> m_childSessions;
41+ QHash<quint32, MirSurfaceItem*> m_childSurfaces;
40};
42};
41
43
42#endif // APPLICATIONTESTINTERFACE_H
44#endif // APPLICATIONTESTINTERFACE_H
tests/mocks/Unity/Application/CMakeLists.txt+2−1
@@ -7,8 +7,9 @@ set(FakeUnityApplicationQml_SOURCES
7 ApplicationManager.cpp
7 ApplicationManager.cpp
8 ApplicationScreenshotProvider.cpp
8 ApplicationScreenshotProvider.cpp
9 ApplicationTestInterface.cpp
9 ApplicationTestInterface.cpp
10+ MirSessionItem.cpp
10 MirSurfaceItem.cpp
11 MirSurfaceItem.cpp
11− MirSurfaceItemModel.cpp
12+ SessionManager.cpp
12 SurfaceManager.cpp
13 SurfaceManager.cpp
13 VirtualKeyboard.cpp
14 VirtualKeyboard.cpp
14 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
15 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
tests/mocks/Unity/Application/MirItemModel.hnew file+108
@@ -0,0 +1,108 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * 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+#ifndef MIRITEMMODEL_H
18+#define MIRITEMMODEL_H
19+
20+// Qt
21+#include <QAbstractListModel>
22+
23+class MirSurfaceItem;
24+
25+template<class TYPE>
26+class MirItemModel : public QAbstractListModel
27+{
28+public:
29+ MirItemModel(QObject *parent = 0)
30+ : QAbstractListModel(parent)
31+ {}
32+
33+ enum Roles {
34+ RoleModelData = Qt::UserRole,
35+ };
36+
37+ const QList<TYPE*>& list() const { return m_items; }
38+ bool contains(TYPE* item) const { return m_items.contains(item); }
39+
40+ void insert(uint index, TYPE* item)
41+ {
42+ index = qMin(index, (uint)m_items.count());
43+
44+ int existingIndex = m_items.indexOf(item);
45+ if (existingIndex != -1) {
46+ move(existingIndex, index);
47+ } else {
48+ beginInsertRows(QModelIndex(), index, index);
49+ m_items.insert(index, item);
50+ endInsertRows();
51+ }
52+ }
53+
54+ void remove(TYPE* item)
55+ {
56+ int existingIndex = m_items.indexOf(item);
57+ if (existingIndex != -1) {
58+ beginRemoveRows(QModelIndex(), existingIndex, existingIndex);
59+ m_items.removeAt(existingIndex);
60+ endRemoveRows();
61+ }
62+ }
63+
64+ // from QAbstractItemModel
65+ int rowCount(const QModelIndex& = QModelIndex()) const override
66+ {
67+ return m_items.count();
68+ }
69+
70+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override
71+ {
72+ if (index.row() >= 0 && index.row() < m_items.count()) {
73+ if (role == RoleModelData) {
74+ TYPE *item = m_items.at(index.row());
75+ return QVariant::fromValue(item);
76+ }
77+ }
78+ return QVariant();
79+ }
80+
81+ QHash<int, QByteArray> roleNames() const
82+ {
83+ QHash<int, QByteArray> roleNames;
84+ roleNames.insert(RoleModelData, "modelData");
85+ return roleNames;
86+ }
87+
88+private:
89+ void move(int from, int to)
90+ {
91+ if (from == to) return;
92+
93+ if (from >= 0 && from < m_items.size() && to >= 0 && to < m_items.size()) {
94+ QModelIndex parent;
95+ /* When moving an item down, the destination index needs to be incremented
96+ by one, as explained in the documentation:
97+ http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
98+
99+ beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
100+ m_items.move(from, to);
101+ endMoveRows();
102+ }
103+ }
104+
105+ QList<TYPE*> m_items;
106+};
107+
108+#endif // MIRITEMMODEL_H
tests/mocks/Unity/Application/MirSessionItem.cppnew file+172
@@ -0,0 +1,172 @@
1+/*
2+ * Copyright (C) 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 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 "MirSessionItem.h"
18+#include "ApplicationInfo.h"
19+#include "SurfaceManager.h"
20+
21+#include <QPainter>
22+#include <QQmlEngine>
23+#include <QTimer>
24+
25+MirSessionItem::MirSessionItem(const QString &name,
26+ const QUrl& screenshot,
27+ QQuickItem *parent)
28+ : QQuickItem(parent)
29+ , m_name(name)
30+ , m_screenshot(screenshot)
31+ , m_application(nullptr)
32+ , m_surface(nullptr)
33+ , m_parentSession(nullptr)
34+ , m_children(new MirSessionItemModel(this))
35+{
36+ qDebug() << "MirSessionItem::MirSessionItem() " << this->name();
37+
38+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
39+}
40+
41+MirSessionItem::~MirSessionItem()
42+{
43+ qDebug() << "MirSessionItem::~MirSessionItem() " << name();
44+
45+ QList<MirSessionItem*> children(m_children->list());
46+ for (MirSessionItem* child : children) {
47+ delete child;
48+ }
49+ if (m_parentSession) {
50+ m_parentSession->removeChildSession(this);
51+ }
52+ if (m_application) {
53+ m_application->setSession(nullptr);
54+ }
55+ delete m_surface;
56+ delete m_children;
57+}
58+
59+void MirSessionItem::release()
60+{
61+ qDebug() << "MirSessionItem::release " << name();
62+
63+ if (m_parentSession) {
64+ m_parentSession->removeChildSession(this);
65+ }
66+ if (m_application) {
67+ m_application->setSession(nullptr);
68+ }
69+ if (!parent()) {
70+ deleteLater();
71+ }
72+}
73+
74+void MirSessionItem::setApplication(ApplicationInfo* application)
75+{
76+ if (m_application == application)
77+ return;
78+
79+ if (m_application) {
80+ disconnect(m_application, 0, this, 0);
81+ }
82+
83+ m_application = application;
84+
85+ if (m_application) {
86+ connect(m_application, &ApplicationInfo::stateChanged, this, [this](ApplicationInfo::State state) {
87+ if (state == ApplicationInfo::Running) {
88+ QTimer::singleShot(500, this, SLOT(createSurface()));
89+ } else if (state == ApplicationInfo::Stopped) {
90+ setSurface(nullptr);
91+ }
92+ });
93+ }
94+}
95+
96+void MirSessionItem::setSurface(MirSurfaceItem* surface)
97+{
98+ qDebug() << "MirSessionItem::setSurface - session=" << name() << "surface=" << surface;
99+ if (m_surface == surface)
100+ return;
101+
102+ if (m_surface) {
103+ m_surface->setSession(nullptr);
104+ m_surface->setParent(nullptr);
105+ }
106+
107+ m_surface = surface;
108+
109+ if (m_surface) {
110+ m_surface->setSession(this);
111+ m_surface->setParent(this);
112+ }
113+
114+ Q_EMIT surfaceChanged(m_surface);
115+}
116+
117+void MirSessionItem::setScreenshot(const QUrl& screenshot)
118+{
119+ if (screenshot != m_screenshot) {
120+ m_screenshot = screenshot;
121+ if (m_surface) {
122+ m_surface->setScreenshot(m_screenshot);
123+ }
124+ }
125+}
126+
127+void MirSessionItem::setParentSession(MirSessionItem* session)
128+{
129+ if (m_parentSession == session || session == this)
130+ return;
131+
132+ m_parentSession = session;
133+ Q_EMIT parentSessionChanged(session);
134+}
135+
136+void MirSessionItem::createSurface()
137+{
138+ if (m_surface) return;
139+
140+ setSurface(SurfaceManager::singleton()->createSurface(name(),
141+ MirSurfaceItem::Normal,
142+ m_application && m_application->fullscreen() ? MirSurfaceItem::Fullscreen : MirSurfaceItem::Maximized,
143+ m_screenshot));
144+}
145+
146+void MirSessionItem::addChildSession(MirSessionItem* session)
147+{
148+ insertChildSession(m_children->rowCount(), session);
149+}
150+
151+void MirSessionItem::insertChildSession(uint index, MirSessionItem* session)
152+{
153+ qDebug() << "MirSessionItem::insertChildSession - " << session->name() << " to " << name() << " @ " << index;
154+
155+ session->setParentSession(this);
156+ m_children->insert(index, session);
157+}
158+
159+void MirSessionItem::removeChildSession(MirSessionItem* session)
160+{
161+ qDebug() << "MirSessionItem::removeChildSession - " << session->name() << " from " << name();
162+
163+ if (m_children->contains(session)) {
164+ m_children->remove(session);
165+ session->setParentSession(nullptr);
166+ }
167+}
168+
169+MirSessionItemModel* MirSessionItem::childSessions() const
170+{
171+ return m_children;
172+}
tests/mocks/Unity/Application/MirSessionItem.hnew file+77
@@ -0,0 +1,77 @@
1+/*
2+ * Copyright (C) 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 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+#ifndef MIRSESSIONITEM_H
18+#define MIRSESSIONITEM_H
19+
20+#include "MirSessionItemModel.h"
21+
22+#include <QQuickItem>
23+
24+class ApplicationInfo;
25+
26+class MirSessionItem : public QQuickItem
27+{
28+ Q_OBJECT
29+ Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
30+ Q_PROPERTY(MirSessionItem* parentSession READ parentSession NOTIFY parentSessionChanged DESIGNABLE false)
31+ Q_PROPERTY(MirSessionItemModel* childSessions READ childSessions DESIGNABLE false CONSTANT)
32+
33+public:
34+ explicit MirSessionItem(const QString &name,
35+ const QUrl& screenshot,
36+ QQuickItem *parent = 0);
37+ ~MirSessionItem();
38+
39+ Q_INVOKABLE void release();
40+
41+ //getters
42+ QString name() const { return m_name; }
43+ ApplicationInfo* application() const { return m_application; }
44+ MirSurfaceItem* surface() const { return m_surface; }
45+ MirSessionItem* parentSession() const { return m_parentSession; }
46+
47+ void setApplication(ApplicationInfo* item);
48+ void setSurface(MirSurfaceItem* surface);
49+ void setScreenshot(const QUrl& m_screenshot);
50+
51+ void addChildSession(MirSessionItem* session);
52+ void insertChildSession(uint index, MirSessionItem* session);
53+ void removeChildSession(MirSessionItem* session);
54+
55+Q_SIGNALS:
56+ void surfaceChanged(MirSurfaceItem*);
57+ void parentSessionChanged(MirSessionItem*);
58+ void removed();
59+
60+public Q_SLOTS:
61+ void createSurface();
62+
63+private:
64+ MirSessionItemModel* childSessions() const;
65+ void setParentSession(MirSessionItem* session);
66+
67+ QString m_name;
68+ QUrl m_screenshot;
69+ ApplicationInfo* m_application;
70+ MirSurfaceItem* m_surface;
71+ MirSessionItem* m_parentSession;
72+ MirSessionItemModel* m_children;
73+};
74+
75+Q_DECLARE_METATYPE(MirSessionItem*)
76+
77+#endif // MIRSESSIONITEM_H
tests/mocks/Unity/Application/MirSessionItemModel.hnew file+28
@@ -0,0 +1,28 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * 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+#ifndef MIRSESSIONITEMMODEL_H
18+#define MIRSESSIONITEMMODEL_H
19+
20+// Local
21+#include "MirItemModel.h"
22+
23+class MirSessionItem;
24+typedef MirItemModel<MirSessionItem> MirSessionItemModel;
25+
26+Q_DECLARE_METATYPE(MirSessionItemModel*)
27+
28+#endif // MIRSESSIONITEMMODEL_H
tests/mocks/Unity/Application/MirSurfaceItem.cpp+17−13
@@ -15,8 +15,7 @@
15 */
15 */
16
16
17#include "MirSurfaceItem.h"
17#include "MirSurfaceItem.h"
18−#include "MirSurfaceItemModel.h"
18+#include "MirSessionItem.h"
19−#include "ApplicationInfo.h"
20
19
21#include <QPainter>
20#include <QPainter>
22#include <QQmlEngine>
21#include <QQmlEngine>
@@ -27,7 +26,7 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
27 const QUrl& screenshot,
26 const QUrl& screenshot,
28 QQuickItem *parent)
27 QQuickItem *parent)
29 : QQuickPaintedItem(parent)
28 : QQuickPaintedItem(parent)
30− , m_application(nullptr)
29+ , m_session(nullptr)
31 , m_name(name)
30 , m_name(name)
32 , m_type(type)
31 , m_type(type)
33 , m_state(state)
32 , m_state(state)
@@ -60,8 +59,8 @@ MirSurfaceItem::~MirSurfaceItem()
60 if (m_parentSurface) {
59 if (m_parentSurface) {
61 m_parentSurface->removeChildSurface(this);
60 m_parentSurface->removeChildSurface(this);
62 }
61 }
63− if (m_application) {
62+ if (m_session) {
64− m_application->removeSurface(this);
63+ m_session->setSurface(nullptr);
65 }
64 }
66 delete m_children;
65 delete m_children;
67}
66}
@@ -80,18 +79,23 @@ void MirSurfaceItem::release()
80 if (m_parentSurface) {
79 if (m_parentSurface) {
81 m_parentSurface->removeChildSurface(this);
80 m_parentSurface->removeChildSurface(this);
82 }
81 }
83−
82+ if (m_session) {
84− if (m_application) {
83+ m_session->setSurface(nullptr);
85− m_application->removeSurface(this);
86 }
84 }
87 if (!parent()) {
85 if (!parent()) {
88 deleteLater();
86 deleteLater();
89 }
87 }
90}
88}
91
89
92−void MirSurfaceItem::setApplication(ApplicationInfo* application)
90+void MirSurfaceItem::setSession(MirSessionItem* session)
91+{
92+ m_session = session;
93+}
94+
95+void MirSurfaceItem::setScreenshot(const QUrl& screenshot)
93{
96{
94− m_application = application;
97+ m_img.load(screenshot.isLocalFile() ? screenshot.toLocalFile() : screenshot.toString());
98+ update();
95}
99}
96
100
97void MirSurfaceItem::setParentSurface(MirSurfaceItem* surface)
101void MirSurfaceItem::setParentSurface(MirSurfaceItem* surface)
@@ -105,7 +109,7 @@ void MirSurfaceItem::setParentSurface(MirSurfaceItem* surface)
105
109
106void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
110void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
107{
111{
108− insertChildSurface(m_children->count(), surface);
112+ insertChildSurface(m_children->rowCount(), surface);
109}
113}
110
114
111void MirSurfaceItem::insertChildSurface(uint index, MirSurfaceItem* surface)
115void MirSurfaceItem::insertChildSurface(uint index, MirSurfaceItem* surface)
@@ -113,7 +117,7 @@ void MirSurfaceItem::insertChildSurface(uint index, MirSurfaceItem* surface)
113 qDebug() << "MirSurfaceItem::insertChildSurface - " << surface->name() << " to " << name() << " @ " << index;
117 qDebug() << "MirSurfaceItem::insertChildSurface - " << surface->name() << " to " << name() << " @ " << index;
114
118
115 surface->setParentSurface(this);
119 surface->setParentSurface(this);
116− m_children->insertSurface(index, surface);
120+ m_children->insert(index, surface);
117}
121}
118
122
119void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
123void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
@@ -121,7 +125,7 @@ void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
121 qDebug() << "MirSurfaceItem::removeChildSurface - " << surface->name() << " from " << name();
125 qDebug() << "MirSurfaceItem::removeChildSurface - " << surface->name() << " from " << name();
122
126
123 if (m_children->contains(surface)) {
127 if (m_children->contains(surface)) {
124− m_children->removeSurface(surface);
128+ m_children->remove(surface);
125 surface->setParentSurface(nullptr);
129 surface->setParentSurface(nullptr);
126 }
130 }
127}
131}
tests/mocks/Unity/Application/MirSurfaceItem.h+8−6
@@ -17,11 +17,12 @@
17#ifndef MIRSURFACEITEM_H
17#ifndef MIRSURFACEITEM_H
18#define MIRSURFACEITEM_H
18#define MIRSURFACEITEM_H
19
19
20+#include "MirSurfaceItemModel.h"
21+
20#include <QQuickPaintedItem>
22#include <QQuickPaintedItem>
21#include <QImage>
23#include <QImage>
22
24
23−class ApplicationInfo;
25+class MirSessionItem;
24−class MirSurfaceItemModel;
25
26
26class MirSurfaceItem : public QQuickPaintedItem
27class MirSurfaceItem : public QQuickPaintedItem
27{
28{
@@ -59,13 +60,14 @@ public:
59 ~MirSurfaceItem();
60 ~MirSurfaceItem();
60
61
61 //getters
62 //getters
62− ApplicationInfo* application() const { return m_application; }
63+ MirSessionItem* session() const { return m_session; }
63 Type type() const { return m_type; }
64 Type type() const { return m_type; }
64 State state() const { return m_state; }
65 State state() const { return m_state; }
65 QString name() const { return m_name; }
66 QString name() const { return m_name; }
66 MirSurfaceItem* parentSurface() const { return m_parentSurface; }
67 MirSurfaceItem* parentSurface() const { return m_parentSurface; }
67
68
68− void setApplication(ApplicationInfo* item);
69+ void setSession(MirSessionItem* item);
70+ void setScreenshot(const QUrl& screenshot);
69
71
70 Q_INVOKABLE void setState(State newState);
72 Q_INVOKABLE void setState(State newState);
71 Q_INVOKABLE void release();
73 Q_INVOKABLE void release();
@@ -106,11 +108,11 @@ protected:
106 void setParentSurface(MirSurfaceItem* surface);
108 void setParentSurface(MirSurfaceItem* surface);
107
109
108private:
110private:
109− ApplicationInfo* m_application;
111+ MirSessionItem* m_session;
110 const QString m_name;
112 const QString m_name;
111 const Type m_type;
113 const Type m_type;
112 State m_state;
114 State m_state;
113− const QImage m_img;
115+ QImage m_img;
114
116
115 MirSurfaceItem* m_parentSurface;
117 MirSurfaceItem* m_parentSurface;
116 MirSurfaceItemModel* m_children;
118 MirSurfaceItemModel* m_children;
tests/mocks/Unity/Application/MirSurfaceItemModel.cppdeleted−102
@@ -1,102 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software: you can redistribute it and/or modify it under
5− * the terms of the GNU Lesser General Public License version 3, as published by
6− * the Free Software Foundation.
7− *
8− * This program is distributed in the hope that it will be useful, but WITHOUT
9− * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10− * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11− * 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−#include <QQmlEngine>
18−
19−// local
20−#include "MirSurfaceItemModel.h"
21−#include "MirSurfaceItem.h"
22−
23−MirSurfaceItemModel::MirSurfaceItemModel(
24− QObject *parent)
25− : QAbstractListModel(parent)
26−{
27− QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
28−}
29−
30−void MirSurfaceItemModel::insertSurface(uint index, MirSurfaceItem* surface)
31−{
32− index = qMin(index, (uint)count());
33−
34− int existingSurfaceIndex = m_surfaceItems.indexOf(surface);
35− if (existingSurfaceIndex != -1) {
36− move(existingSurfaceIndex, index);
37− } else {
38− beginInsertRows(QModelIndex(), index, index);
39− m_surfaceItems.insert(index, surface);
40− endInsertRows();
41− Q_EMIT countChanged();
42− }
43−}
44−
45−void MirSurfaceItemModel::removeSurface(MirSurfaceItem* surface)
46−{
47− int existingSurfaceIndex = m_surfaceItems.indexOf(surface);
48− if (existingSurfaceIndex != -1) {
49− beginRemoveRows(QModelIndex(), existingSurfaceIndex, existingSurfaceIndex);
50− m_surfaceItems.removeAt(existingSurfaceIndex);
51− endRemoveRows();
52− Q_EMIT countChanged();
53− }
54−}
55−
56−void MirSurfaceItemModel::move(int from, int to)
57−{
58− if (from == to) return;
59−
60− if (from >= 0 && from < m_surfaceItems.size() && to >= 0 && to < m_surfaceItems.size()) {
61− QModelIndex parent;
62− /* When moving an item down, the destination index needs to be incremented
63− by one, as explained in the documentation:
64− http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
65−
66− beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
67− m_surfaceItems.move(from, to);
68− endMoveRows();
69− }
70−}
71−
72−QHash<int, QByteArray> MirSurfaceItemModel::roleNames() const
73−{
74− QHash<int, QByteArray> roleNames;
75− roleNames.insert(RoleSurface, "surface");
76− return roleNames;
77−}
78−
79−int MirSurfaceItemModel::rowCount(const QModelIndex & /*parent*/) const
80−{
81− return m_surfaceItems.count();
82−}
83−
84−QVariant MirSurfaceItemModel::data(const QModelIndex & index, int role) const
85−{
86− if (index.row() >= 0 && index.row() < m_surfaceItems.count()) {
87− MirSurfaceItem *surfaceItem = m_surfaceItems.at(index.row());
88− switch (role) {
89− case RoleSurface:
90− return QVariant::fromValue(surfaceItem);
91− default:
92− return QVariant();
93− }
94− } else {
95− return QVariant();
96− }
97−}
98−
99−MirSurfaceItem* MirSurfaceItemModel::getSurface(int index)
100−{
101− return m_surfaceItems[index];
102−}
tests/mocks/Unity/Application/MirSurfaceItemModel.h+3−37
@@ -17,45 +17,11 @@
17#ifndef MIRSURFACEITEMMODEL_H
17#ifndef MIRSURFACEITEMMODEL_H
18#define MIRSURFACEITEMMODEL_H
18#define MIRSURFACEITEMMODEL_H
19
19
20−// Qt
20+// Llocal
21−#include <QAbstractListModel>
21+#include "MirItemModel.h"
22
22
23class MirSurfaceItem;
23class MirSurfaceItem;
24−
24+typedef MirItemModel<MirSurfaceItem> MirSurfaceItemModel;
25−class MirSurfaceItemModel : public QAbstractListModel
26−{
27− Q_OBJECT
28− Q_ENUMS(Roles)
29− Q_PROPERTY(int count READ count NOTIFY countChanged)
30−
31−public:
32− enum Roles {
33− RoleSurface = Qt::UserRole,
34− };
35−
36− explicit MirSurfaceItemModel(QObject *parent = 0);
37−
38− const QList<MirSurfaceItem*>& list() const { return m_surfaceItems; }
39− bool contains(MirSurfaceItem* surface) const { return m_surfaceItems.contains(surface); }
40− int count() const { return rowCount(); }
41−
42− void insertSurface(uint index, MirSurfaceItem* surface);
43− void removeSurface(MirSurfaceItem* surface);
44−
45− // from QAbstractItemModel
46− int rowCount(const QModelIndex & parent = QModelIndex()) const override;
47− QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
48− QHash<int, QByteArray> roleNames() const override;
49−
50− Q_INVOKABLE MirSurfaceItem* getSurface(int index);
51−
52−Q_SIGNALS:
53− void countChanged();
54−
55−private:
56− void move(int from, int to);
57− QList<MirSurfaceItem*> m_surfaceItems;
58−};
59
25
60Q_DECLARE_METATYPE(MirSurfaceItemModel*)
26Q_DECLARE_METATYPE(MirSurfaceItemModel*)
61
27
tests/mocks/Unity/Application/SessionManager.cppnew file+45
@@ -0,0 +1,45 @@
1+/*
2+ * Copyright (C) 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 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 "SessionManager.h"
18+
19+#include "MirSurfaceItem.h"
20+#include "VirtualKeyboard.h"
21+
22+SessionManager *SessionManager::the_session_manager = nullptr;
23+
24+SessionManager *SessionManager::singleton()
25+{
26+ if (!the_session_manager) {
27+ the_session_manager = new SessionManager();
28+ }
29+ return the_session_manager;
30+}
31+
32+SessionManager::SessionManager(QObject *parent) :
33+ QObject(parent)
34+{
35+}
36+
37+
38+MirSessionItem *SessionManager::createSession(const QString& name,
39+ const QUrl& screenshot)
40+{
41+ MirSessionItem* session = new MirSessionItem(name, screenshot);
42+ connect(session, &MirSessionItem::destroyed, this, [&](QObject*) {
43+ });
44+ return session;
45+}
tests/mocks/Unity/Application/SessionManager.hnew file+38
@@ -0,0 +1,38 @@
1+/*
2+ * Copyright (C) 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 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+#ifndef SESSIONMANAGER_
18+#define SESSIONMANAGER_
19+
20+#include <QObject>
21+
22+#include "MirSessionItem.h"
23+
24+class SessionManager : public QObject
25+{
26+ Q_OBJECT
27+public:
28+ explicit SessionManager(QObject *parent = 0);
29+
30+ static SessionManager *singleton();
31+
32+ MirSessionItem* createSession(const QString& name, const QUrl& screenshot);
33+
34+private:
35+ static SessionManager *the_session_manager;
36+};
37+
38+#endif // SESSIONMANAGER_
tests/mocks/Unity/Application/plugin.cpp+4
@@ -19,6 +19,7 @@
19#include "ApplicationImage.h"
19#include "ApplicationImage.h"
20#include "ApplicationManager.h"
20#include "ApplicationManager.h"
21#include "ApplicationScreenshotProvider.h"
21#include "ApplicationScreenshotProvider.h"
22+#include "MirSessionItem.h"
22#include "MirSurfaceItem.h"
23#include "MirSurfaceItem.h"
23#include "MirSurfaceItemModel.h"
24#include "MirSurfaceItemModel.h"
24#include "SurfaceManager.h"
25#include "SurfaceManager.h"
@@ -52,11 +53,14 @@ static QObject* applicationTestInterface(QQmlEngine* engine, QJSEngine* scriptEn
52
53
53void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
54void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
54{
55{
56+ qRegisterMetaType<MirSessionItem*>("MirSessionItem*");
55 qRegisterMetaType<MirSurfaceItem*>("MirSurfaceItem*");
57 qRegisterMetaType<MirSurfaceItem*>("MirSurfaceItem*");
58+ qRegisterMetaType<MirSurfaceItemModel*>("MirSessionItemModel*");
56 qRegisterMetaType<MirSurfaceItemModel*>("MirSurfaceItemModel*");
59 qRegisterMetaType<MirSurfaceItemModel*>("MirSurfaceItemModel*");
57
60
58 qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(uri, 0, 1, "ApplicationManagerInterface", "Abstract interface. Cannot be created in QML");
61 qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(uri, 0, 1, "ApplicationManagerInterface", "Abstract interface. Cannot be created in QML");
59 qmlRegisterUncreatableType<unity::shell::application::ApplicationInfoInterface>(uri, 0, 1, "ApplicationInfoInterface", "Abstract interface. Cannot be created in QML");
62 qmlRegisterUncreatableType<unity::shell::application::ApplicationInfoInterface>(uri, 0, 1, "ApplicationInfoInterface", "Abstract interface. Cannot be created in QML");
63+ qmlRegisterUncreatableType<MirSessionItem>(uri, 0, 1, "MirSessionItem", "MirSessionItem can't be instantiated from QML");
60 qmlRegisterUncreatableType<MirSurfaceItem>(uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML");
64 qmlRegisterUncreatableType<MirSurfaceItem>(uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML");
61
65
62 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
66 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");