on xenial help sign in
Workspaces revisited
commita0ca0a0d16f170b68105be881955eb1327a5a160 authorNick Dedekind <nick.dedekind@canonical.com> dateWed 1 Mar 2017, 11:55 (10 years ago) parent747a319
13 files changed+418−61
plugins/WindowManager/Screen.cpp+40−1 plugins/WindowManager/Screen.h+25−3 plugins/WindowManager/Screens.cpp+85−16 plugins/WindowManager/Screens.h+21−2 plugins/WindowManager/WindowManagerPlugin.cpp+3−2 plugins/WindowManager/Workspace.cpp+63−8 plugins/WindowManager/Workspace.h+37−7 plugins/WindowManager/WorkspaceManager.cpp+38−10 plugins/WindowManager/WorkspaceManager.h+9−2 plugins/WindowManager/WorkspaceModel.cpp+75−4 plugins/WindowManager/WorkspaceModel.h+17−1 src/libunity8-private/windowmanagementpolicy.cpp+3−3 src/libunity8-private/windowmanagementpolicy.h+2−2
plugins/WindowManager/Screen.cpp+40−1
@@ -15,7 +15,6 @@
1515 */
1616
1717#include "Screen.h"
18−#include "WorkspaceModel.h"
1918#include "WorkspaceManager.h"
2019#include "Workspace.h"
2120
@@ -49,6 +48,23 @@ Screen::Screen(qtmir::Screen* screen)
4948 WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
5049}
5150
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+
5268qtmir::OutputId Screen::outputId() const
5369{
5470 return m_wrapped->outputId();
@@ -124,6 +140,18 @@ bool Screen::applyConfiguration(qtmir::ScreenConfiguration *configuration)
124140 return m_wrapped->applyConfiguration(configuration);
125141}
126142
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+
127155void Screen::activate()
128156{
129157 setActive(true);
@@ -138,3 +166,14 @@ QScreen *Screen::qscreen() const
138166{
139167 return m_wrapped->qscreen();
140168}
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 @@
33
44#include <qtmir/screen.h>
55#include <QScopedPointer>
6+#include <QPointer>
67
7−class WorkspaceModel;
8+#include "WorkspaceModel.h"
9+
10+class ScreenProxy;
811
912class Screen : public qtmir::Screen
1013{
@@ -36,14 +39,33 @@ public:
3639
3740 qtmir::Screen* wrapped() const { return m_wrapped; }
3841
39− WorkspaceModel* workspaces() const { return m_workspaces.data(); }
42+ WorkspaceModel* workspaces() const;
43+
44+ void sync(Screen* proxy);
4045
4146public Q_SLOTS:
4247 void activate();
4348
44−private:
49+protected:
50+ Screen(Screen const& other);
51+
4552 qtmir::Screen*const m_wrapped;
4653 const QScopedPointer<WorkspaceModel> m_workspaces;
4754};
4855
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+
4971#endif // SCREEN_H
plugins/WindowManager/Screens.cpp+85−16
@@ -16,6 +16,7 @@
1616
1717#include "Screens.h"
1818#include "Screen.h"
19+#include "WorkspaceManager.h"
1920
2021// qtmirserver
2122#include <qtmir/qtmir.h>
@@ -39,10 +40,16 @@ Screens::Screens(QObject *parent)
3940 connect(m_wrapped.data(), &qtmir::Screens::activeScreenChanged, this, &Screens::activeScreenChanged);
4041
4142 Q_FOREACH(qtmir::Screen* screen, m_wrapped->screens()) {
42− m_screenList.push_back(new Screen(screen));
43+ m_screens.push_back(new Screen(screen));
4344 }
4445}
4546
47+Screens::Screens(const Screens &other)
48+ : QAbstractListModel(nullptr)
49+ , m_wrapped(other.m_wrapped)
50+{
51+}
52+
4653QHash<int, QByteArray> Screens::roleNames() const
4754{
4855 QHash<int, QByteArray> roles;
@@ -52,13 +59,13 @@ QHash<int, QByteArray> Screens::roleNames() const
5259
5360QVariant Screens::data(const QModelIndex &index, int role) const
5461{
55− if (!index.isValid() || index.row() >= m_screenList.size()) {
62+ if (!index.isValid() || index.row() >= m_screens.size()) {
5663 return QVariant();
5764 }
5865
5966 switch(role) {
6067 case ScreenRole:
61− return QVariant::fromValue(m_screenList.at(index.row()));
68+ return QVariant::fromValue(m_screens.at(index.row()));
6269 } // switch
6370
6471 return QVariant();
@@ -71,48 +78,66 @@ int Screens::rowCount(const QModelIndex &) const
7178
7279int Screens::count() const
7380{
74− return m_screenList.size();
81+ return m_screens.size();
7582}
7683
7784QVariant Screens::activeScreen() const
7885{
79− for (int i = 0; i < m_screenList.count(); i++) {
80− if (m_screenList[i]->isActive()) return i;
86+ for (int i = 0; i < m_screens.count(); i++) {
87+ if (m_screens[i]->isActive()) return i;
8188 }
8289 return QVariant();
8390}
8491
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+
85110void Screens::activateScreen(const QVariant& vindex)
86111{
87112 bool ok = false;
88113 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;
90115
91− auto screen = m_screenList.at(index);
116+ auto screen = m_screens.at(index);
92117 screen->setActive(true);
93118}
94119
95−void Screens::onScreenAdded(qtmir::Screen *screen)
120+void Screens::onScreenAdded(qtmir::Screen *added)
96121{
97− Q_FOREACH(auto screenWrapper, m_screenList) {
98− if (screenWrapper->wrapped() == screen) return;
122+ Q_FOREACH(auto screenWrapper, m_screens) {
123+ if (screenWrapper->wrapped() == added) return;
99124 }
100125
101126 beginInsertRows(QModelIndex(), count(), count());
102− auto screenWrapper(new Screen(screen));
103− m_screenList.push_back(screenWrapper);
127+ auto screenWrapper(new Screen(added));
128+ m_screens.push_back(screenWrapper);
104129 endInsertRows();
105130 Q_EMIT screenAdded(screenWrapper);
106131 Q_EMIT countChanged();
107132}
108133
109−void Screens::onScreenRemoved(qtmir::Screen *screen)
134+void Screens::onScreenRemoved(qtmir::Screen *removed)
110135{
111136 int index = 0;
112− QMutableListIterator<Screen*> iter(m_screenList);
137+ QMutableVectorIterator<Screen*> iter(m_screens);
113138 while(iter.hasNext()) {
114139 auto screenWrapper = iter.next();
115− if (screenWrapper->wrapped() == screen) {
140+ if (screenWrapper->wrapped() == removed) {
116141
117142 beginRemoveRows(QModelIndex(), index, index);
118143 iter.remove();
@@ -127,3 +152,47 @@ void Screens::onScreenRemoved(qtmir::Screen *screen)
127152 index++;
128153 }
129154}
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 @@
1919
2020#include <QAbstractListModel>
2121#include <QSharedPointer>
22+#include <QPointer>
2223
2324class Screen;
2425namespace qtmir
@@ -27,6 +28,8 @@ class Screen;
2728class Screens;
2829}
2930
31+class ScreensProxy;
32+
3033class Screens : public QAbstractListModel
3134{
3235 Q_OBJECT
@@ -41,6 +44,9 @@ public:
4144 explicit Screens(QObject *parent = 0);
4245 virtual ~Screens() noexcept = default;
4346
47+ Q_INVOKABLE ScreensProxy *createProxy();
48+ Q_INVOKABLE void sync(Screens *proxy);
49+
4450 /* QAbstractItemModel */
4551 QHash<int, QByteArray> roleNames() const override;
4652 QVariant data(const QModelIndex &index, int role = ScreenRole) const override;
@@ -49,6 +55,8 @@ public:
4955 int count() const;
5056 QVariant activeScreen() const;
5157
58+ const QVector<Screen*>& list() const { return m_screens; }
59+
5260public Q_SLOTS:
5361 void activateScreen(const QVariant& index);
5462
@@ -63,9 +71,20 @@ private Q_SLOTS:
6371 void onScreenAdded(qtmir::Screen *screen);
6472 void onScreenRemoved(qtmir::Screen *screen);
6573
66−private:
67− QList<Screen*> m_screenList;
74+protected:
75+ Screens(const Screens& other);
76+
77+ QVector<Screen*> m_screens;
6878 QSharedPointer<qtmir::Screens> m_wrapped;
6979};
7080
81+class ScreensProxy : public Screens
82+{
83+public:
84+ ScreensProxy(Screens*const screens);
85+
86+private:
87+ const QScopedPointer<Screens> m_original;
88+};
89+
7190#endif // SCREENS_H
plugins/WindowManager/WindowManagerPlugin.cpp+3−2
@@ -48,11 +48,12 @@ void WindowManagerPlugin::registerTypes(const char *uri)
4848 qmlRegisterUncreatableType<qtmir::ScreenMode>(uri, 1, 0, "ScreenMode", "ScreenMode is not creatable.");
4949 qmlRegisterUncreatableType<Workspace>(uri, 1, 0, "Workspace", "Workspace is not creatable.");
5050
51− qRegisterMetaType<Window*>("Window*");
51+ qRegisterMetaType<Screen*>("Screen*");
52+ qRegisterMetaType<ScreensProxy*>("ScreensProxy*");
5253 qRegisterMetaType<Workspace*>("Workspace*");
5354
55+ qRegisterMetaType<Window*>("Window*");
5456 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
55− qRegisterMetaType<Screen*>("Screen*");
5657
5758 qmlRegisterType<ScreenWindow>(uri, 1, 0, "ScreenWindow");
5859 qmlRegisterRevision<QWindow,1>(uri, 1, 0);
plugins/WindowManager/Workspace.cpp+63−8
@@ -21,9 +21,12 @@
2121
2222#include "windowmanagementpolicy.h"
2323
24+int nextWorkspace = 0;
25+
2426Workspace::Workspace(QObject *parent)
2527 : QObject(parent)
2628 , m_workspace(WindowManagementPolicy::instance()->createWorkspace())
29+ , m_uid(QString("W%1").arg(nextWorkspace++))
2730 , m_model(nullptr)
2831 , m_active(false)
2932{
@@ -40,20 +43,42 @@ Workspace::Workspace(QObject *parent)
4043 });
4144}
4245
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+
4359Workspace::~Workspace()
4460{
45− WindowManagementPolicy::instance()->destroyWorkspace(m_workspace);
4661 if (m_model) {
4762 m_model->remove(this);
4863 }
4964}
5065
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+
5176void Workspace::assign(WorkspaceModel *model, const QVariant& vIndex)
5277{
5378 if (m_model == model) return;
5479
5580 if (m_model) {
56− disconnect(model);
81+ disconnect(m_model, 0, this, 0);
5782 m_model->remove(this);
5883 }
5984
@@ -69,22 +94,52 @@ void Workspace::assign(WorkspaceModel *model, const QVariant& vIndex)
6994 connect(m_model, &QObject::destroyed, this, [this]() {
7095 m_model->remove(this);
7196 m_model = nullptr;
97+ Q_EMIT unassigned();
7298 });
7399 Q_EMIT assigned();
100+ } else {
101+ Q_EMIT unassigned();
74102 }
75103}
76104
77−void Workspace::moveWindowsTo(Workspace *workspace)
105+void Workspace::unassign()
78106{
79− WindowManagementPolicy::instance()->moveWorkspaceContentToWorkspace(workspace->m_workspace, m_workspace);
107+ assign(nullptr);
80108}
81109
82−void Workspace::activate()
110+void Workspace::release()
83111{
84− WorkspaceManager::instance()->setActiveWorkspace(this);
112+ WindowManagementPolicy::instance()->releaseWorkspace(m_workspace);
113+ deleteLater();
85114}
86115
87−void Workspace::unassign()
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+{
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()
88143{
89− assign(WorkspaceManager::instance());
144+ if (m_original) m_original->activate();
90145}
plugins/WindowManager/Workspace.h+37−7
@@ -19,6 +19,7 @@
1919
2020#include <QObject>
2121#include <QVariant>
22+#include <QPointer>
2223
2324#include <memory>
2425#include <functional>
@@ -39,36 +40,65 @@ namespace unity {
3940class Workspace : public QObject
4041{
4142 Q_OBJECT
43+ Q_PROPERTY(QString uid READ uid CONSTANT)
4244 Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
4345public:
4446 ~Workspace();
4547
46− Q_INVOKABLE void assign(WorkspaceModel* model, const QVariant& index = QVariant());
48+ QString uid() const { return m_uid; }
4749
48− bool isActive() const { return m_active; }
50+ virtual void assign(WorkspaceModel* model, const QVariant& index = QVariant());
51+ virtual void unassign();
52+ void release();
4953
50− std::shared_ptr<miral::Workspace> workspace() const { return m_workspace; }
54+ virtual bool isActive() const { return m_active; }
55+ bool isAssigned() const;
5156
52− WorkspaceModel* model() const { return m_model; }
5357 void moveWindowsTo(Workspace* workspace);
5458
59+ std::shared_ptr<miral::Workspace> workspace() const { return m_workspace; }
60+
61+
5562public Q_SLOTS:
56− void activate();
57− void unassign();
63+ virtual void activate();
5864
5965Q_SIGNALS:
6066 void assigned();
67+ void unassigned();
6168
6269 void activeChanged(bool);
6370
6471protected:
65− explicit Workspace(QObject *parent = 0);
72+ Workspace(QObject *parent = 0);
73+ Workspace(Workspace const& other);
6674
6775 std::shared_ptr<miral::Workspace> m_workspace;
76+ QString m_uid;
6877 WorkspaceModel* m_model;
6978 bool m_active;
7079
7180 friend class WorkspaceManager;
7281};
7382
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+
74104#endif // WINDOWMANAGER_WORKSPACE_H
plugins/WindowManager/WorkspaceManager.cpp+38−10
@@ -39,14 +39,22 @@ Workspace *WorkspaceManager::createWorkspace()
3939 auto workspace = new Workspace(this);
4040 QQmlEngine::setObjectOwnership(workspace, QQmlEngine::CppOwnership);
4141 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+ });
4352
4453 if (m_allWorkspaces.count() == 0 && m_activeWorkspace) {
45− m_activeWorkspace = nullptr;
54+ setActiveWorkspace(nullptr);
4655 Q_EMIT activeWorkspaceChanged();
4756 } else if (m_allWorkspaces.count() == 1) {
48− m_activeWorkspace = workspace;
49− Q_EMIT activeWorkspaceChanged();
57+ setActiveWorkspace(workspace);
5058 }
5159
5260 return workspace;
@@ -56,17 +64,37 @@ void WorkspaceManager::destroyWorkspace(Workspace *workspace)
5664{
5765 if (!workspace) return;
5866
67+ if (workspace->isAssigned()) {
68+ workspace->unassign();
69+ }
70+ m_floatingWorkspaces.removeOne(workspace);
5971 m_allWorkspaces.remove(workspace);
60− workspace->assign(nullptr);
72+ Q_EMIT floatingWorkspacesChanged();
6173
6274 if (m_activeWorkspace == workspace) {
63− m_activeWorkspace = m_allWorkspaces.count() > 0 ? *m_allWorkspaces.begin() : nullptr;
64− if (m_activeWorkspace) {
65− workspace->moveWindowsTo(m_activeWorkspace);
66− }
75+ Q_ASSERT(false); // Shouldn't happen, should have chosen something by now.
76+ // just choose anything.
77+ setActiveWorkspace(m_allWorkspaces.count() ? *m_allWorkspaces.begin() : nullptr);
78+ }
79+ if (m_activeWorkspace) {
80+ workspace->moveWindowsTo(m_activeWorkspace);
6781 }
6882
69− workspace->deleteLater();
83+ disconnect(workspace, 0, this, 0);
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+ }
7098}
7199
72100Workspace *WorkspaceManager::activeWorkspace() const
plugins/WindowManager/WorkspaceManager.h+9−2
@@ -18,13 +18,16 @@
1818#define WORKSPACEMANAGER_H
1919
2020#include "WorkspaceModel.h"
21+#include <QQmlListProperty>
2122
2223class Workspace;
24+class ScreensProxy;
2325
24−class WorkspaceManager : public WorkspaceModel
26+class WorkspaceManager : public QObject
2527{
2628 Q_OBJECT
2729 Q_PROPERTY(Workspace* activeWorkspace READ activeWorkspace WRITE setActiveWorkspace NOTIFY activeWorkspaceChanged)
30+ Q_PROPERTY(QQmlListProperty<Workspace> floatingWorkspaces READ floatingWorkspaces NOTIFY floatingWorkspacesChanged)
2831
2932public:
3033 static WorkspaceManager* instance();
@@ -32,17 +35,21 @@ public:
3235 Workspace* activeWorkspace() const;
3336 void setActiveWorkspace(Workspace* workspace);
3437
35−public Q_SLOTS:
3638 Workspace* createWorkspace();
3739 void destroyWorkspace(Workspace* workspace);
3840
41+ QQmlListProperty<Workspace> floatingWorkspaces();
42+ void destroyFloatingWorkspaces();
43+
3944Q_SIGNALS:
4045 void activeWorkspaceChanged();
46+ void floatingWorkspacesChanged();
4147
4248private:
4349 WorkspaceManager();
4450
4551 QSet<Workspace*> m_allWorkspaces;
52+ QList<Workspace*> m_floatingWorkspaces;
4653 Workspace* m_activeWorkspace;
4754};
4855
plugins/WindowManager/WorkspaceModel.cpp+75−4
@@ -1,4 +1,4 @@
1−/*
1+/*
22 * Copyright (C) 2017 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
@@ -15,6 +15,7 @@
1515 */
1616
1717#include "WorkspaceModel.h"
18+#include "WorkspaceManager.h"
1819#include "Workspace.h"
1920
2021Q_LOGGING_CATEGORY(WORKSPACES, "Workspaces", QtInfoMsg)
@@ -26,7 +27,6 @@ WorkspaceModel::WorkspaceModel(QObject *parent)
2627 : QAbstractListModel(parent)
2728{
2829}
29−
3030void WorkspaceModel::append(Workspace *workspace)
3131{
3232 insert(m_workspaces.count(), workspace);
@@ -36,7 +36,7 @@ void WorkspaceModel::insert(int index, Workspace *workspace)
3636{
3737 beginInsertRows(QModelIndex(), index, index);
3838
39− m_workspaces.append(workspace);
39+ m_workspaces.insert(index, workspace);
4040
4141 endInsertRows();
4242
@@ -52,7 +52,6 @@ void WorkspaceModel::remove(Workspace *workspace)
5252 beginRemoveRows(QModelIndex(), index, index);
5353
5454 m_workspaces.removeAt(index);
55− disconnect(workspace);
5655
5756 endRemoveRows();
5857
@@ -85,6 +84,12 @@ int WorkspaceModel::indexOf(Workspace *workspace) const
8584 return m_workspaces.indexOf(workspace);
8685}
8786
87+Workspace *WorkspaceModel::get(int index) const
88+{
89+ if (index < 0 || index >= rowCount()) return nullptr;
90+ return m_workspaces.at(index);
91+}
92+
8893int WorkspaceModel::rowCount(const QModelIndex &) const
8994{
9095 return m_workspaces.count();
@@ -102,3 +107,69 @@ QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
102107 return QVariant();
103108 }
104109}
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 @@
1919
2020#include <QAbstractListModel>
2121#include <QLoggingCategory>
22+#include <QPointer>
2223
2324Q_DECLARE_LOGGING_CATEGORY(WORKSPACES)
2425
2526class Workspace;
27+class WorkspaceModelProxy;
2628
2729class WorkspaceModel : public QAbstractListModel
2830{
@@ -43,9 +45,10 @@ public:
4345 void append(Workspace *workspace);
4446 void insert(int index, Workspace *workspace);
4547 void remove(Workspace* workspace);
46− Q_INVOKABLE void move(int from, int to);
48+ void move(int from, int to);
4749
4850 int indexOf(Workspace *workspace) const;
51+ Workspace* get(int index) const;
4952
5053 // From QAbstractItemModel
5154 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
@@ -55,6 +58,10 @@ public:
5558 return roleNames;
5659 }
5760
61+ const QVector<Workspace*>& list() const { return m_workspaces; }
62+
63+ void sync(WorkspaceModel* proxy);
64+
5865Q_SIGNALS:
5966 void countChanged();
6067
@@ -65,4 +72,13 @@ protected:
6572 QVector<Workspace*> m_workspaces;
6673};
6774
75+class WorkspaceModelProxy : public WorkspaceModel
76+{
77+public:
78+ WorkspaceModelProxy(WorkspaceModel*const model);
79+
80+private:
81+ const QPointer<WorkspaceModel> m_original;
82+};
83+
6884#endif // WORKSPACEMODEL_H
src/libunity8-private/windowmanagementpolicy.cpp+3−3
@@ -22,11 +22,11 @@ WindowManagementPolicy* WindowManagementPolicy::m_self = nullptr;
2222
2323WindowManagementPolicy::WindowManagementPolicy(const miral::WindowManagerTools &tools, qtmir::WindowManagementPolicyPrivate &dd)
2424 : qtmir::WindowManagementPolicy(tools, dd)
25+ , m_dummyWorkspace(this->tools.create_workspace())
2526{
2627 m_self = this;
2728
2829 // we must always have a active workspace.
29− m_dummyWorkspace = this->tools.create_workspace();
3030 m_activeWorkspace = m_dummyWorkspace;
3131}
3232
@@ -50,14 +50,14 @@ std::shared_ptr<miral::Workspace> WindowManagementPolicy::createWorkspace()
5050 auto workspace = tools.create_workspace();
5151 m_workspaces.insert(workspace);
5252
53− if (m_activeWorkspace = m_dummyWorkspace) {
53+ if (m_activeWorkspace == m_dummyWorkspace) {
5454 tools.move_workspace_content_to_workspace(workspace, m_dummyWorkspace);
5555 m_activeWorkspace = workspace;
5656 }
5757 return workspace;
5858}
5959
60−void WindowManagementPolicy::destroyWorkspace(const std::shared_ptr<miral::Workspace> &workspace)
60+void WindowManagementPolicy::releaseWorkspace(const std::shared_ptr<miral::Workspace> &workspace)
6161{
6262 auto iter = m_workspaces.find(workspace);
6363 if (iter != m_workspaces.end()) m_workspaces.erase(iter);
src/libunity8-private/windowmanagementpolicy.h+2−2
@@ -34,7 +34,7 @@ public:
3434 void advise_new_window(miral::WindowInfo const& window_info) override;
3535
3636 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);
3838
3939 void forEachWindowInWorkspace(
4040 std::shared_ptr<miral::Workspace> const& workspace,
@@ -51,7 +51,7 @@ private:
5151 std::shared_ptr<miral::Workspace> m_activeWorkspace;
5252
5353 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;
5555};
5656
5757#endif // UNITY_WINDOWMANAGEMENTPOLICY_H