on xenial help sign in
Workspaces revisited
a0ca0a0Nick Dedekind
plugins/WindowManager/Screen.cpp+40−1
@@ -15,7 +15,6 @@
15 */
15 */
16
16
17#include "Screen.h"
17#include "Screen.h"
18−#include "WorkspaceModel.h"
19#include "WorkspaceManager.h"
18#include "WorkspaceManager.h"
20#include "Workspace.h"
19#include "Workspace.h"
21
20
@@ -49,6 +48,23 @@ Screen::Screen(qtmir::Screen* screen)
49 WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
48 WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
50}
49}
51
50
51+Screen::Screen(const Screen &other)
52+ : qtmir::Screen(nullptr)
53+ , m_wrapped(other.m_wrapped)
54+ , m_workspaces(new WorkspaceModelProxy(other.m_workspaces.data()))
55+{
56+ connect(m_wrapped, &qtmir::Screen::usedChanged, this, &Screen::usedChanged);
57+ connect(m_wrapped, &qtmir::Screen::nameChanged, this, &Screen::nameChanged);
58+ connect(m_wrapped, &qtmir::Screen::outputTypeChanged, this, &Screen::outputTypeChanged);
59+ connect(m_wrapped, &qtmir::Screen::scaleChanged, this, &Screen::scaleChanged);
60+ connect(m_wrapped, &qtmir::Screen::formFactorChanged, this, &Screen::formFactorChanged);
61+ connect(m_wrapped, &qtmir::Screen::physicalSizeChanged, this, &Screen::physicalSizeChanged);
62+ connect(m_wrapped, &qtmir::Screen::positionChanged, this, &Screen::positionChanged);
63+ connect(m_wrapped, &qtmir::Screen::activeChanged, this, &Screen::activeChanged);
64+ connect(m_wrapped, &qtmir::Screen::currentModeIndexChanged, this, &Screen::currentModeIndexChanged);
65+ connect(m_wrapped, &qtmir::Screen::availableModesChanged, this, &Screen::availableModesChanged);
66+}
67+
52qtmir::OutputId Screen::outputId() const
68qtmir::OutputId Screen::outputId() const
53{
69{
54 return m_wrapped->outputId();
70 return m_wrapped->outputId();
@@ -124,6 +140,18 @@ bool Screen::applyConfiguration(qtmir::ScreenConfiguration *configuration)
124 return m_wrapped->applyConfiguration(configuration);
140 return m_wrapped->applyConfiguration(configuration);
125}
141}
126
142
143+WorkspaceModel *Screen::workspaces() const
144+{
145+ return m_workspaces.data();
146+}
147+
148+void Screen::sync(Screen *proxy)
149+{
150+ if (!proxy) return;
151+
152+ workspaces()->sync(proxy->workspaces());
153+}
154+
127void Screen::activate()
155void Screen::activate()
128{
156{
129 setActive(true);
157 setActive(true);
@@ -138,3 +166,14 @@ QScreen *Screen::qscreen() const
138{
166{
139 return m_wrapped->qscreen();
167 return m_wrapped->qscreen();
140}
168}
169+
170+ScreenProxy::ScreenProxy(ScreenProxy::Screen *const screen)
171+ : Screen(*screen)
172+ , m_original(screen)
173+{
174+}
175+
176+void ScreenProxy::addWorkspace()
177+{
178+ (new WorkspaceProxy(WorkspaceManager::instance()->createWorkspace()))->assign(workspaces());
179+}
plugins/WindowManager/Screen.h+25−3
@@ -3,8 +3,11 @@
3
3
4#include <qtmir/screen.h>
4#include <qtmir/screen.h>
5#include <QScopedPointer>
5#include <QScopedPointer>
6+#include <QPointer>
6
7
7−class WorkspaceModel;
8+#include "WorkspaceModel.h"
9+
10+class ScreenProxy;
8
11
9class Screen : public qtmir::Screen
12class Screen : public qtmir::Screen
10{
13{
@@ -36,14 +39,33 @@ public:
36
39
37 qtmir::Screen* wrapped() const { return m_wrapped; }
40 qtmir::Screen* wrapped() const { return m_wrapped; }
38
41
39− WorkspaceModel* workspaces() const { return m_workspaces.data(); }
42+ WorkspaceModel* workspaces() const;
43+
44+ void sync(Screen* proxy);
40
45
41public Q_SLOTS:
46public Q_SLOTS:
42 void activate();
47 void activate();
43
48
44−private:
49+protected:
50+ Screen(Screen const& other);
51+
45 qtmir::Screen*const m_wrapped;
52 qtmir::Screen*const m_wrapped;
46 const QScopedPointer<WorkspaceModel> m_workspaces;
53 const QScopedPointer<WorkspaceModel> m_workspaces;
47};
54};
48
55
56+class ScreenProxy : public Screen
57+{
58+ Q_OBJECT
59+public:
60+ explicit ScreenProxy(Screen*const screen);
61+
62+ Screen* proxyObject() const { return m_original.data(); }
63+
64+public Q_SLOTS:
65+ void addWorkspace();
66+
67+private:
68+ const QPointer<Screen> m_original;
69+};
70+
49#endif // SCREEN_H
71#endif // SCREEN_H
plugins/WindowManager/Screens.cpp+85−16
@@ -16,6 +16,7 @@
16
16
17#include "Screens.h"
17#include "Screens.h"
18#include "Screen.h"
18#include "Screen.h"
19+#include "WorkspaceManager.h"
19
20
20// qtmirserver
21// qtmirserver
21#include <qtmir/qtmir.h>
22#include <qtmir/qtmir.h>
@@ -39,10 +40,16 @@ Screens::Screens(QObject *parent)
39 connect(m_wrapped.data(), &qtmir::Screens::activeScreenChanged, this, &Screens::activeScreenChanged);
40 connect(m_wrapped.data(), &qtmir::Screens::activeScreenChanged, this, &Screens::activeScreenChanged);
40
41
41 Q_FOREACH(qtmir::Screen* screen, m_wrapped->screens()) {
42 Q_FOREACH(qtmir::Screen* screen, m_wrapped->screens()) {
42− m_screenList.push_back(new Screen(screen));
43+ m_screens.push_back(new Screen(screen));
43 }
44 }
44}
45}
45
46
47+Screens::Screens(const Screens &other)
48+ : QAbstractListModel(nullptr)
49+ , m_wrapped(other.m_wrapped)
50+{
51+}
52+
46QHash<int, QByteArray> Screens::roleNames() const
53QHash<int, QByteArray> Screens::roleNames() const
47{
54{
48 QHash<int, QByteArray> roles;
55 QHash<int, QByteArray> roles;
@@ -52,13 +59,13 @@ QHash<int, QByteArray> Screens::roleNames() const
52
59
53QVariant Screens::data(const QModelIndex &index, int role) const
60QVariant Screens::data(const QModelIndex &index, int role) const
54{
61{
55− if (!index.isValid() || index.row() >= m_screenList.size()) {
62+ if (!index.isValid() || index.row() >= m_screens.size()) {
56 return QVariant();
63 return QVariant();
57 }
64 }
58
65
59 switch(role) {
66 switch(role) {
60 case ScreenRole:
67 case ScreenRole:
61− return QVariant::fromValue(m_screenList.at(index.row()));
68+ return QVariant::fromValue(m_screens.at(index.row()));
62 } // switch
69 } // switch
63
70
64 return QVariant();
71 return QVariant();
@@ -71,48 +78,66 @@ int Screens::rowCount(const QModelIndex &) const
71
78
72int Screens::count() const
79int Screens::count() const
73{
80{
74− return m_screenList.size();
81+ return m_screens.size();
75}
82}
76
83
77QVariant Screens::activeScreen() const
84QVariant Screens::activeScreen() const
78{
85{
79− for (int i = 0; i < m_screenList.count(); i++) {
86+ for (int i = 0; i < m_screens.count(); i++) {
80− if (m_screenList[i]->isActive()) return i;
87+ if (m_screens[i]->isActive()) return i;
81 }
88 }
82 return QVariant();
89 return QVariant();
83}
90}
84
91
92+ScreensProxy *Screens::createProxy()
93+{
94+ return new ScreensProxy(this);
95+}
96+
97+void Screens::sync(Screens *proxy)
98+{
99+ if (!proxy) return;
100+
101+ const auto& proxyList = proxy->list();
102+ for (int i = 0; i < m_screens.count() && i < proxyList.count(); ++i) {
103+ m_screens[i]->sync(proxyList[i]);
104+ }
105+
106+ // need to clean up all the workspaces we unassigned.
107+ WorkspaceManager::instance()->destroyFloatingWorkspaces();
108+}
109+
85void Screens::activateScreen(const QVariant& vindex)
110void Screens::activateScreen(const QVariant& vindex)
86{
111{
87 bool ok = false;
112 bool ok = false;
88 int index = vindex.toInt(&ok);
113 int index = vindex.toInt(&ok);
89− if (!ok || index < 0 || m_screenList.count() <= index) return;
114+ if (!ok || index < 0 || m_screens.count() <= index) return;
90
115
91− auto screen = m_screenList.at(index);
116+ auto screen = m_screens.at(index);
92 screen->setActive(true);
117 screen->setActive(true);
93}
118}
94
119
95−void Screens::onScreenAdded(qtmir::Screen *screen)
120+void Screens::onScreenAdded(qtmir::Screen *added)
96{
121{
97− Q_FOREACH(auto screenWrapper, m_screenList) {
122+ Q_FOREACH(auto screenWrapper, m_screens) {
98− if (screenWrapper->wrapped() == screen) return;
123+ if (screenWrapper->wrapped() == added) return;
99 }
124 }
100
125
101 beginInsertRows(QModelIndex(), count(), count());
126 beginInsertRows(QModelIndex(), count(), count());
102− auto screenWrapper(new Screen(screen));
127+ auto screenWrapper(new Screen(added));
103− m_screenList.push_back(screenWrapper);
128+ m_screens.push_back(screenWrapper);
104 endInsertRows();
129 endInsertRows();
105 Q_EMIT screenAdded(screenWrapper);
130 Q_EMIT screenAdded(screenWrapper);
106 Q_EMIT countChanged();
131 Q_EMIT countChanged();
107}
132}
108
133
109−void Screens::onScreenRemoved(qtmir::Screen *screen)
134+void Screens::onScreenRemoved(qtmir::Screen *removed)
110{
135{
111 int index = 0;
136 int index = 0;
112− QMutableListIterator<Screen*> iter(m_screenList);
137+ QMutableVectorIterator<Screen*> iter(m_screens);
113 while(iter.hasNext()) {
138 while(iter.hasNext()) {
114 auto screenWrapper = iter.next();
139 auto screenWrapper = iter.next();
115− if (screenWrapper->wrapped() == screen) {
140+ if (screenWrapper->wrapped() == removed) {
116
141
117 beginRemoveRows(QModelIndex(), index, index);
142 beginRemoveRows(QModelIndex(), index, index);
118 iter.remove();
143 iter.remove();
@@ -127,3 +152,47 @@ void Screens::onScreenRemoved(qtmir::Screen *screen)
127 index++;
152 index++;
128 }
153 }
129}
154}
155+
156+ScreensProxy::ScreensProxy(Screens * const screens)
157+ : Screens(*screens)
158+ , m_original(screens)
159+{
160+ connect(screens, &Screens::screenAdded, this, [this](Screen *added) {
161+ Q_FOREACH(auto screen, m_screens) {
162+ auto proxy = static_cast<ScreenProxy*>(screen);
163+ if (proxy->proxyObject() == added) return;
164+ }
165+
166+ beginInsertRows(QModelIndex(), count(), count());
167+ auto screenWrapper(new ScreenProxy(added));
168+ m_screens.push_back(screenWrapper);
169+ endInsertRows();
170+ Q_EMIT screenAdded(screenWrapper);
171+ Q_EMIT countChanged();
172+ });
173+
174+ connect(screens, &Screens::screenAdded, this, [this](Screen *removed) {
175+ int index = 0;
176+ QMutableVectorIterator<Screen*> iter(m_screens);
177+ while(iter.hasNext()) {
178+ auto proxy = static_cast<ScreenProxy*>(iter.next());
179+ if (proxy->proxyObject() == removed) {
180+
181+ beginRemoveRows(QModelIndex(), index, index);
182+ iter.remove();
183+ endRemoveRows();
184+
185+ Q_EMIT screenRemoved(proxy);
186+ Q_EMIT countChanged();
187+
188+ delete proxy;
189+ break;
190+ }
191+ index++;
192+ }
193+ });
194+
195+ Q_FOREACH(Screen* screen, screens->list()) {
196+ m_screens.push_back(new ScreenProxy(screen));
197+ }
198+}
plugins/WindowManager/Screens.h+21−2
@@ -19,6 +19,7 @@
19
19
20#include <QAbstractListModel>
20#include <QAbstractListModel>
21#include <QSharedPointer>
21#include <QSharedPointer>
22+#include <QPointer>
22
23
23class Screen;
24class Screen;
24namespace qtmir
25namespace qtmir
@@ -27,6 +28,8 @@ class Screen;
27class Screens;
28class Screens;
28}
29}
29
30
31+class ScreensProxy;
32+
30class Screens : public QAbstractListModel
33class Screens : public QAbstractListModel
31{
34{
32 Q_OBJECT
35 Q_OBJECT
@@ -41,6 +44,9 @@ public:
41 explicit Screens(QObject *parent = 0);
44 explicit Screens(QObject *parent = 0);
42 virtual ~Screens() noexcept = default;
45 virtual ~Screens() noexcept = default;
43
46
47+ Q_INVOKABLE ScreensProxy *createProxy();
48+ Q_INVOKABLE void sync(Screens *proxy);
49+
44 /* QAbstractItemModel */
50 /* QAbstractItemModel */
45 QHash<int, QByteArray> roleNames() const override;
51 QHash<int, QByteArray> roleNames() const override;
46 QVariant data(const QModelIndex &index, int role = ScreenRole) const override;
52 QVariant data(const QModelIndex &index, int role = ScreenRole) const override;
@@ -49,6 +55,8 @@ public:
49 int count() const;
55 int count() const;
50 QVariant activeScreen() const;
56 QVariant activeScreen() const;
51
57
58+ const QVector<Screen*>& list() const { return m_screens; }
59+
52public Q_SLOTS:
60public Q_SLOTS:
53 void activateScreen(const QVariant& index);
61 void activateScreen(const QVariant& index);
54
62
@@ -63,9 +71,20 @@ private Q_SLOTS:
63 void onScreenAdded(qtmir::Screen *screen);
71 void onScreenAdded(qtmir::Screen *screen);
64 void onScreenRemoved(qtmir::Screen *screen);
72 void onScreenRemoved(qtmir::Screen *screen);
65
73
66−private:
74+protected:
67− QList<Screen*> m_screenList;
75+ Screens(const Screens& other);
76+
77+ QVector<Screen*> m_screens;
68 QSharedPointer<qtmir::Screens> m_wrapped;
78 QSharedPointer<qtmir::Screens> m_wrapped;
69};
79};
70
80
81+class ScreensProxy : public Screens
82+{
83+public:
84+ ScreensProxy(Screens*const screens);
85+
86+private:
87+ const QScopedPointer<Screens> m_original;
88+};
89+
71#endif // SCREENS_H
90#endif // SCREENS_H
plugins/WindowManager/WindowManagerPlugin.cpp+3−2
@@ -48,11 +48,12 @@ void WindowManagerPlugin::registerTypes(const char *uri)
48 qmlRegisterUncreatableType<qtmir::ScreenMode>(uri, 1, 0, "ScreenMode", "ScreenMode is not creatable.");
48 qmlRegisterUncreatableType<qtmir::ScreenMode>(uri, 1, 0, "ScreenMode", "ScreenMode is not creatable.");
49 qmlRegisterUncreatableType<Workspace>(uri, 1, 0, "Workspace", "Workspace is not creatable.");
49 qmlRegisterUncreatableType<Workspace>(uri, 1, 0, "Workspace", "Workspace is not creatable.");
50
50
51− qRegisterMetaType<Window*>("Window*");
51+ qRegisterMetaType<Screen*>("Screen*");
52+ qRegisterMetaType<ScreensProxy*>("ScreensProxy*");
52 qRegisterMetaType<Workspace*>("Workspace*");
53 qRegisterMetaType<Workspace*>("Workspace*");
53
54
55+ qRegisterMetaType<Window*>("Window*");
54 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
56 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
55− qRegisterMetaType<Screen*>("Screen*");
56
57
57 qmlRegisterType<ScreenWindow>(uri, 1, 0, "ScreenWindow");
58 qmlRegisterType<ScreenWindow>(uri, 1, 0, "ScreenWindow");
58 qmlRegisterRevision<QWindow,1>(uri, 1, 0);
59 qmlRegisterRevision<QWindow,1>(uri, 1, 0);
plugins/WindowManager/Workspace.cpp+63−8
@@ -21,9 +21,12 @@
21
21
22#include "windowmanagementpolicy.h"
22#include "windowmanagementpolicy.h"
23
23
24+int nextWorkspace = 0;
25+
24Workspace::Workspace(QObject *parent)
26Workspace::Workspace(QObject *parent)
25 : QObject(parent)
27 : QObject(parent)
26 , m_workspace(WindowManagementPolicy::instance()->createWorkspace())
28 , m_workspace(WindowManagementPolicy::instance()->createWorkspace())
29+ , m_uid(QString("W%1").arg(nextWorkspace++))
27 , m_model(nullptr)
30 , m_model(nullptr)
28 , m_active(false)
31 , m_active(false)
29{
32{
@@ -40,20 +43,42 @@ Workspace::Workspace(QObject *parent)
40 });
43 });
41}
44}
42
45
46+Workspace::Workspace(const Workspace &other)
47+ : QObject(nullptr)
48+ , m_workspace(other.m_workspace)
49+ , m_uid(other.m_uid)
50+ , m_model(nullptr)
51+ , m_active(other.m_active)
52+{
53+ connect(&other, &Workspace::activeChanged, this, [this](bool active) {
54+ m_active = active;
55+ Q_EMIT activeChanged(m_active);
56+ });
57+}
58+
43Workspace::~Workspace()
59Workspace::~Workspace()
44{
60{
45− WindowManagementPolicy::instance()->destroyWorkspace(m_workspace);
46 if (m_model) {
61 if (m_model) {
47 m_model->remove(this);
62 m_model->remove(this);
48 }
63 }
49}
64}
50
65
66+void Workspace::moveWindowsTo(Workspace *workspace)
67+{
68+ WindowManagementPolicy::instance()->moveWorkspaceContentToWorkspace(workspace->m_workspace, m_workspace);
69+}
70+
71+void Workspace::activate()
72+{
73+ WorkspaceManager::instance()->setActiveWorkspace(this);
74+}
75+
51void Workspace::assign(WorkspaceModel *model, const QVariant& vIndex)
76void Workspace::assign(WorkspaceModel *model, const QVariant& vIndex)
52{
77{
53 if (m_model == model) return;
78 if (m_model == model) return;
54
79
55 if (m_model) {
80 if (m_model) {
56− disconnect(model);
81+ disconnect(m_model, 0, this, 0);
57 m_model->remove(this);
82 m_model->remove(this);
58 }
83 }
59
84
@@ -69,22 +94,52 @@ void Workspace::assign(WorkspaceModel *model, const QVariant& vIndex)
69 connect(m_model, &QObject::destroyed, this, [this]() {
94 connect(m_model, &QObject::destroyed, this, [this]() {
70 m_model->remove(this);
95 m_model->remove(this);
71 m_model = nullptr;
96 m_model = nullptr;
97+ Q_EMIT unassigned();
72 });
98 });
73 Q_EMIT assigned();
99 Q_EMIT assigned();
100+ } else {
101+ Q_EMIT unassigned();
74 }
102 }
75}
103}
76
104
77−void Workspace::moveWindowsTo(Workspace *workspace)
105+void Workspace::unassign()
78{
106{
79− WindowManagementPolicy::instance()->moveWorkspaceContentToWorkspace(workspace->m_workspace, m_workspace);
107+ assign(nullptr);
80}
108}
81
109
82−void Workspace::activate()
110+void Workspace::release()
83{
111{
84− WorkspaceManager::instance()->setActiveWorkspace(this);
112+ WindowManagementPolicy::instance()->releaseWorkspace(m_workspace);
113+ deleteLater();
85}
114}
86
115
116+bool Workspace::isAssigned() const
117+{
118+ return m_model != nullptr;
119+}
120+
121+WorkspaceProxy::WorkspaceProxy(Workspace * const workspace)
122+ : Workspace(*workspace)
123+ , m_original(workspace)
124+{
125+}
126+
127+void WorkspaceProxy::assign(WorkspaceModel *model, const QVariant &index)
128+{
129+ Workspace::assign(model, index);
130+}
131+
132+void WorkspaceProxy::unassign()
133+{
87−void Workspace::unassign()
134+ Workspace::unassign();
135+}
136+
137+bool WorkspaceProxy::isActive() const
138+{
139+ return m_original ? m_original->isActive() : false;
140+}
141+
142+void WorkspaceProxy::activate()
88{
143{
89− assign(WorkspaceManager::instance());
144+ if (m_original) m_original->activate();
90}
145}
plugins/WindowManager/Workspace.h+37−7
@@ -19,6 +19,7 @@
19
19
20#include <QObject>
20#include <QObject>
21#include <QVariant>
21#include <QVariant>
22+#include <QPointer>
22
23
23#include <memory>
24#include <memory>
24#include <functional>
25#include <functional>
@@ -39,36 +40,65 @@ namespace unity {
39class Workspace : public QObject
40class Workspace : public QObject
40{
41{
41 Q_OBJECT
42 Q_OBJECT
43+ Q_PROPERTY(QString uid READ uid CONSTANT)
42 Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
44 Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
43public:
45public:
44 ~Workspace();
46 ~Workspace();
45
47
46− Q_INVOKABLE void assign(WorkspaceModel* model, const QVariant& index = QVariant());
48+ QString uid() const { return m_uid; }
47
49
48− bool isActive() const { return m_active; }
50+ virtual void assign(WorkspaceModel* model, const QVariant& index = QVariant());
51+ virtual void unassign();
52+ void release();
49
53
50− std::shared_ptr<miral::Workspace> workspace() const { return m_workspace; }
54+ virtual bool isActive() const { return m_active; }
55+ bool isAssigned() const;
51
56
52− WorkspaceModel* model() const { return m_model; }
53 void moveWindowsTo(Workspace* workspace);
57 void moveWindowsTo(Workspace* workspace);
54
58
59+ std::shared_ptr<miral::Workspace> workspace() const { return m_workspace; }
60+
61+
55public Q_SLOTS:
62public Q_SLOTS:
56− void activate();
63+ virtual void activate();
57− void unassign();
58
64
59Q_SIGNALS:
65Q_SIGNALS:
60 void assigned();
66 void assigned();
67+ void unassigned();
61
68
62 void activeChanged(bool);
69 void activeChanged(bool);
63
70
64protected:
71protected:
65− explicit Workspace(QObject *parent = 0);
72+ Workspace(QObject *parent = 0);
73+ Workspace(Workspace const& other);
66
74
67 std::shared_ptr<miral::Workspace> m_workspace;
75 std::shared_ptr<miral::Workspace> m_workspace;
76+ QString m_uid;
68 WorkspaceModel* m_model;
77 WorkspaceModel* m_model;
69 bool m_active;
78 bool m_active;
70
79
71 friend class WorkspaceManager;
80 friend class WorkspaceManager;
72};
81};
73
82
83+class WorkspaceProxy : public Workspace
84+{
85+ Q_OBJECT
86+public:
87+ WorkspaceProxy(Workspace*const workspace);
88+
89+ Q_INVOKABLE void assign(WorkspaceModel* model, const QVariant& index = QVariant()) override;
90+
91+ bool isActive() const override;
92+
93+ void activate() override;
94+
95+ Workspace* proxyObject() const { return m_original.data(); }
96+
97+public Q_SLOTS:
98+ void unassign() override;
99+
100+private:
101+ const QPointer<Workspace> m_original;
102+};
103+
74#endif // WINDOWMANAGER_WORKSPACE_H
104#endif // WINDOWMANAGER_WORKSPACE_H
plugins/WindowManager/WorkspaceManager.cpp+38−10
@@ -39,14 +39,22 @@ Workspace *WorkspaceManager::createWorkspace()
39 auto workspace = new Workspace(this);
39 auto workspace = new Workspace(this);
40 QQmlEngine::setObjectOwnership(workspace, QQmlEngine::CppOwnership);
40 QQmlEngine::setObjectOwnership(workspace, QQmlEngine::CppOwnership);
41 m_allWorkspaces.insert(workspace);
41 m_allWorkspaces.insert(workspace);
42− workspace->assign(this);
42+ m_floatingWorkspaces.append(workspace);
43+
44+ connect(workspace, &Workspace::assigned, this, [this, workspace]() {
45+ m_floatingWorkspaces.removeOne(workspace);
46+ Q_EMIT floatingWorkspacesChanged();
47+ });
48+ connect(workspace, &Workspace::unassigned, this, [this, workspace]() {
49+ m_floatingWorkspaces.append(workspace);
50+ Q_EMIT floatingWorkspacesChanged();
51+ });
43
52
44 if (m_allWorkspaces.count() == 0 && m_activeWorkspace) {
53 if (m_allWorkspaces.count() == 0 && m_activeWorkspace) {
45− m_activeWorkspace = nullptr;
54+ setActiveWorkspace(nullptr);
46 Q_EMIT activeWorkspaceChanged();
55 Q_EMIT activeWorkspaceChanged();
47 } else if (m_allWorkspaces.count() == 1) {
56 } else if (m_allWorkspaces.count() == 1) {
48− m_activeWorkspace = workspace;
57+ setActiveWorkspace(workspace);
49− Q_EMIT activeWorkspaceChanged();
50 }
58 }
51
59
52 return workspace;
60 return workspace;
@@ -56,17 +64,37 @@ void WorkspaceManager::destroyWorkspace(Workspace *workspace)
56{
64{
57 if (!workspace) return;
65 if (!workspace) return;
58
66
67+ if (workspace->isAssigned()) {
68+ workspace->unassign();
69+ }
70+ m_floatingWorkspaces.removeOne(workspace);
59 m_allWorkspaces.remove(workspace);
71 m_allWorkspaces.remove(workspace);
60− workspace->assign(nullptr);
72+ Q_EMIT floatingWorkspacesChanged();
61
73
62 if (m_activeWorkspace == workspace) {
74 if (m_activeWorkspace == workspace) {
75+ Q_ASSERT(false); // Shouldn't happen, should have chosen something by now.
76+ // just choose anything.
63− m_activeWorkspace = m_allWorkspaces.count() > 0 ? *m_allWorkspaces.begin() : nullptr;
77+ setActiveWorkspace(m_allWorkspaces.count() ? *m_allWorkspaces.begin() : nullptr);
78+ }
64− if (m_activeWorkspace) {
79+ if (m_activeWorkspace) {
65− workspace->moveWindowsTo(m_activeWorkspace);
80+ workspace->moveWindowsTo(m_activeWorkspace);
66− }
67 }
81 }
68
82
83+ disconnect(workspace, 0, this, 0);
69− workspace->deleteLater();
84+ workspace->release();
85+}
86+
87+QQmlListProperty<Workspace> WorkspaceManager::floatingWorkspaces()
88+{
89+ return QQmlListProperty<Workspace>(this, m_floatingWorkspaces);
90+}
91+
92+void WorkspaceManager::destroyFloatingWorkspaces()
93+{
94+ QList<Workspace*> dpCpy(m_floatingWorkspaces);
95+ Q_FOREACH(auto workspace, dpCpy) {
96+ destroyWorkspace(workspace);
97+ }
70}
98}
71
99
72Workspace *WorkspaceManager::activeWorkspace() const
100Workspace *WorkspaceManager::activeWorkspace() const
plugins/WindowManager/WorkspaceManager.h+9−2
@@ -18,13 +18,16 @@
18#define WORKSPACEMANAGER_H
18#define WORKSPACEMANAGER_H
19
19
20#include "WorkspaceModel.h"
20#include "WorkspaceModel.h"
21+#include <QQmlListProperty>
21
22
22class Workspace;
23class Workspace;
24+class ScreensProxy;
23
25
24−class WorkspaceManager : public WorkspaceModel
26+class WorkspaceManager : public QObject
25{
27{
26 Q_OBJECT
28 Q_OBJECT
27 Q_PROPERTY(Workspace* activeWorkspace READ activeWorkspace WRITE setActiveWorkspace NOTIFY activeWorkspaceChanged)
29 Q_PROPERTY(Workspace* activeWorkspace READ activeWorkspace WRITE setActiveWorkspace NOTIFY activeWorkspaceChanged)
30+ Q_PROPERTY(QQmlListProperty<Workspace> floatingWorkspaces READ floatingWorkspaces NOTIFY floatingWorkspacesChanged)
28
31
29public:
32public:
30 static WorkspaceManager* instance();
33 static WorkspaceManager* instance();
@@ -32,17 +35,21 @@ public:
32 Workspace* activeWorkspace() const;
35 Workspace* activeWorkspace() const;
33 void setActiveWorkspace(Workspace* workspace);
36 void setActiveWorkspace(Workspace* workspace);
34
37
35−public Q_SLOTS:
36 Workspace* createWorkspace();
38 Workspace* createWorkspace();
37 void destroyWorkspace(Workspace* workspace);
39 void destroyWorkspace(Workspace* workspace);
38
40
41+ QQmlListProperty<Workspace> floatingWorkspaces();
42+ void destroyFloatingWorkspaces();
43+
39Q_SIGNALS:
44Q_SIGNALS:
40 void activeWorkspaceChanged();
45 void activeWorkspaceChanged();
46+ void floatingWorkspacesChanged();
41
47
42private:
48private:
43 WorkspaceManager();
49 WorkspaceManager();
44
50
45 QSet<Workspace*> m_allWorkspaces;
51 QSet<Workspace*> m_allWorkspaces;
52+ QList<Workspace*> m_floatingWorkspaces;
46 Workspace* m_activeWorkspace;
53 Workspace* m_activeWorkspace;
47};
54};
48
55
plugins/WindowManager/WorkspaceModel.cpp+75−4
@@ -1,4 +1,4 @@
1−/*
1+/*
2 * Copyright (C) 2017 Canonical, Ltd.
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17#include "WorkspaceModel.h"
17#include "WorkspaceModel.h"
18+#include "WorkspaceManager.h"
18#include "Workspace.h"
19#include "Workspace.h"
19
20
20Q_LOGGING_CATEGORY(WORKSPACES, "Workspaces", QtInfoMsg)
21Q_LOGGING_CATEGORY(WORKSPACES, "Workspaces", QtInfoMsg)
@@ -26,7 +27,6 @@ WorkspaceModel::WorkspaceModel(QObject *parent)
26 : QAbstractListModel(parent)
27 : QAbstractListModel(parent)
27{
28{
28}
29}
29−
30void WorkspaceModel::append(Workspace *workspace)
30void WorkspaceModel::append(Workspace *workspace)
31{
31{
32 insert(m_workspaces.count(), workspace);
32 insert(m_workspaces.count(), workspace);
@@ -36,7 +36,7 @@ void WorkspaceModel::insert(int index, Workspace *workspace)
36{
36{
37 beginInsertRows(QModelIndex(), index, index);
37 beginInsertRows(QModelIndex(), index, index);
38
38
39− m_workspaces.append(workspace);
39+ m_workspaces.insert(index, workspace);
40
40
41 endInsertRows();
41 endInsertRows();
42
42
@@ -52,7 +52,6 @@ void WorkspaceModel::remove(Workspace *workspace)
52 beginRemoveRows(QModelIndex(), index, index);
52 beginRemoveRows(QModelIndex(), index, index);
53
53
54 m_workspaces.removeAt(index);
54 m_workspaces.removeAt(index);
55− disconnect(workspace);
56
55
57 endRemoveRows();
56 endRemoveRows();
58
57
@@ -85,6 +84,12 @@ int WorkspaceModel::indexOf(Workspace *workspace) const
85 return m_workspaces.indexOf(workspace);
84 return m_workspaces.indexOf(workspace);
86}
85}
87
86
87+Workspace *WorkspaceModel::get(int index) const
88+{
89+ if (index < 0 || index >= rowCount()) return nullptr;
90+ return m_workspaces.at(index);
91+}
92+
88int WorkspaceModel::rowCount(const QModelIndex &) const
93int WorkspaceModel::rowCount(const QModelIndex &) const
89{
94{
90 return m_workspaces.count();
95 return m_workspaces.count();
@@ -102,3 +107,69 @@ QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
102 return QVariant();
107 return QVariant();
103 }
108 }
104}
109}
110+
111+void WorkspaceModel::sync(WorkspaceModel *proxy)
112+{
113+ if (!proxy) return;
114+ const auto& proxyList = proxy->list();
115+
116+ // check for removals
117+ int removedIndexWhichWasActive = -1;
118+ QVector<Workspace*> dpCpy(this->list());
119+ Q_FOREACH(auto workspace, dpCpy) {
120+
121+ bool found = false;
122+ Q_FOREACH(auto p, proxyList) {
123+ auto workspaceProxy = static_cast<WorkspaceProxy*>(p);
124+ if (workspaceProxy->proxyObject() == workspace) {
125+ found = true;
126+ break;
127+ }
128+ }
129+ if (!found) {
130+ if (workspace->isActive()) {
131+ removedIndexWhichWasActive = indexOf(workspace);
132+ }
133+ workspace->unassign();
134+ }
135+ }
136+
137+ // existing
138+ QSet<Workspace*> newWorkspaces;
139+ for (int i = 0; i < proxyList.count(); i++) {
140+ auto workspaceProxy = static_cast<WorkspaceProxy*>(proxyList[i]);
141+ auto workspace = workspaceProxy->proxyObject();
142+
143+ int oldIndex = this->indexOf(workspace);
144+
145+ if (oldIndex < 0) {
146+ workspace->assign(this, QVariant(i));
147+ } else if (oldIndex != i) {
148+ this->move(oldIndex, i);
149+ }
150+ newWorkspaces.insert(workspace);
151+ }
152+
153+ // Make sure we have at least one workspace in the model.
154+ if (rowCount() == 0) {
155+ Workspace* workspace = WorkspaceManager::instance()->createWorkspace();
156+ workspace->assign(this);
157+ (new WorkspaceProxy(workspace))->assign(proxy);
158+ }
159+
160+ if (removedIndexWhichWasActive != -1) {
161+ int newActiveIndex = qMin(removedIndexWhichWasActive, this->rowCount()-1);
162+ Workspace* newActiveWorkspace = newActiveIndex >= 0 ? this->get(newActiveIndex) : nullptr;
163+
164+ WorkspaceManager::instance()->setActiveWorkspace(newActiveWorkspace);
165+ }
166+}
167+
168+
169+WorkspaceModelProxy::WorkspaceModelProxy(WorkspaceModel * const model)
170+ : m_original(model)
171+{
172+ Q_FOREACH(auto workspace, model->list()) {
173+ (new WorkspaceProxy(workspace))->assign(this);
174+ }
175+}
plugins/WindowManager/WorkspaceModel.h+17−1
@@ -19,10 +19,12 @@
19
19
20#include <QAbstractListModel>
20#include <QAbstractListModel>
21#include <QLoggingCategory>
21#include <QLoggingCategory>
22+#include <QPointer>
22
23
23Q_DECLARE_LOGGING_CATEGORY(WORKSPACES)
24Q_DECLARE_LOGGING_CATEGORY(WORKSPACES)
24
25
25class Workspace;
26class Workspace;
27+class WorkspaceModelProxy;
26
28
27class WorkspaceModel : public QAbstractListModel
29class WorkspaceModel : public QAbstractListModel
28{
30{
@@ -43,9 +45,10 @@ public:
43 void append(Workspace *workspace);
45 void append(Workspace *workspace);
44 void insert(int index, Workspace *workspace);
46 void insert(int index, Workspace *workspace);
45 void remove(Workspace* workspace);
47 void remove(Workspace* workspace);
46− Q_INVOKABLE void move(int from, int to);
48+ void move(int from, int to);
47
49
48 int indexOf(Workspace *workspace) const;
50 int indexOf(Workspace *workspace) const;
51+ Workspace* get(int index) const;
49
52
50 // From QAbstractItemModel
53 // From QAbstractItemModel
51 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
54 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
@@ -55,6 +58,10 @@ public:
55 return roleNames;
58 return roleNames;
56 }
59 }
57
60
61+ const QVector<Workspace*>& list() const { return m_workspaces; }
62+
63+ void sync(WorkspaceModel* proxy);
64+
58Q_SIGNALS:
65Q_SIGNALS:
59 void countChanged();
66 void countChanged();
60
67
@@ -65,4 +72,13 @@ protected:
65 QVector<Workspace*> m_workspaces;
72 QVector<Workspace*> m_workspaces;
66};
73};
67
74
75+class WorkspaceModelProxy : public WorkspaceModel
76+{
77+public:
78+ WorkspaceModelProxy(WorkspaceModel*const model);
79+
80+private:
81+ const QPointer<WorkspaceModel> m_original;
82+};
83+
68#endif // WORKSPACEMODEL_H
84#endif // WORKSPACEMODEL_H
src/libunity8-private/windowmanagementpolicy.cpp+3−3
@@ -22,11 +22,11 @@ WindowManagementPolicy* WindowManagementPolicy::m_self = nullptr;
22
22
23WindowManagementPolicy::WindowManagementPolicy(const miral::WindowManagerTools &tools, qtmir::WindowManagementPolicyPrivate &dd)
23WindowManagementPolicy::WindowManagementPolicy(const miral::WindowManagerTools &tools, qtmir::WindowManagementPolicyPrivate &dd)
24 : qtmir::WindowManagementPolicy(tools, dd)
24 : qtmir::WindowManagementPolicy(tools, dd)
25+ , m_dummyWorkspace(this->tools.create_workspace())
25{
26{
26 m_self = this;
27 m_self = this;
27
28
28 // we must always have a active workspace.
29 // we must always have a active workspace.
29− m_dummyWorkspace = this->tools.create_workspace();
30 m_activeWorkspace = m_dummyWorkspace;
30 m_activeWorkspace = m_dummyWorkspace;
31}
31}
32
32
@@ -50,14 +50,14 @@ std::shared_ptr<miral::Workspace> WindowManagementPolicy::createWorkspace()
50 auto workspace = tools.create_workspace();
50 auto workspace = tools.create_workspace();
51 m_workspaces.insert(workspace);
51 m_workspaces.insert(workspace);
52
52
53− if (m_activeWorkspace = m_dummyWorkspace) {
53+ if (m_activeWorkspace == m_dummyWorkspace) {
54 tools.move_workspace_content_to_workspace(workspace, m_dummyWorkspace);
54 tools.move_workspace_content_to_workspace(workspace, m_dummyWorkspace);
55 m_activeWorkspace = workspace;
55 m_activeWorkspace = workspace;
56 }
56 }
57 return workspace;
57 return workspace;
58}
58}
59
59
60−void WindowManagementPolicy::destroyWorkspace(const std::shared_ptr<miral::Workspace> &workspace)
60+void WindowManagementPolicy::releaseWorkspace(const std::shared_ptr<miral::Workspace> &workspace)
61{
61{
62 auto iter = m_workspaces.find(workspace);
62 auto iter = m_workspaces.find(workspace);
63 if (iter != m_workspaces.end()) m_workspaces.erase(iter);
63 if (iter != m_workspaces.end()) m_workspaces.erase(iter);
src/libunity8-private/windowmanagementpolicy.h+2−2
@@ -34,7 +34,7 @@ public:
34 void advise_new_window(miral::WindowInfo const& window_info) override;
34 void advise_new_window(miral::WindowInfo const& window_info) override;
35
35
36 std::shared_ptr<miral::Workspace> createWorkspace();
36 std::shared_ptr<miral::Workspace> createWorkspace();
37− void destroyWorkspace(const std::shared_ptr<miral::Workspace> &workspace);
37+ void releaseWorkspace(const std::shared_ptr<miral::Workspace> &workspace);
38
38
39 void forEachWindowInWorkspace(
39 void forEachWindowInWorkspace(
40 std::shared_ptr<miral::Workspace> const& workspace,
40 std::shared_ptr<miral::Workspace> const& workspace,
@@ -51,7 +51,7 @@ private:
51 std::shared_ptr<miral::Workspace> m_activeWorkspace;
51 std::shared_ptr<miral::Workspace> m_activeWorkspace;
52
52
53 std::unordered_set<std::shared_ptr<miral::Workspace>> m_workspaces;
53 std::unordered_set<std::shared_ptr<miral::Workspace>> m_workspaces;
54− std::shared_ptr<miral::Workspace> m_dummyWorkspace;
54+ const std::shared_ptr<miral::Workspace> m_dummyWorkspace;
55};
55};
56
56
57#endif // UNITY_WINDOWMANAGEMENTPOLICY_H
57#endif // UNITY_WINDOWMANAGEMENTPOLICY_H