on xenial help sign in
merge prereq
commit781c37de0cdedf604fd3c5352d3c8ef835e08791 authorMichael Zanetti <michael.zanetti@canonical.com> dateThu 2 Mar 2017, 10:18 (10 years ago) parent44063d4327be6d
53 files changed+1239−501
debian/control+1−1 plugins/WindowManager/CMakeLists.txt+6 plugins/WindowManager/Screen.cpp+56−1 plugins/WindowManager/Screen.h+28−3 plugins/WindowManager/Screens.cpp+94−21 plugins/WindowManager/Screens.h+24−5 plugins/WindowManager/TopLevelWindowModel.cpp+167−43 plugins/WindowManager/TopLevelWindowModel.h+19 plugins/WindowManager/WindowManagerPlugin.cpp+6−3 plugins/WindowManager/Workspace.cpp+97−13 plugins/WindowManager/Workspace.h+64−8 plugins/WindowManager/WorkspaceManager.cpp+67−3 plugins/WindowManager/WorkspaceManager.h+20−5 plugins/WindowManager/WorkspaceModel.cpp+94−2 plugins/WindowManager/WorkspaceModel.h+26−4 qml/Shell.qml+1−1 qml/ShellApplication.qml−4 qml/ShellScreen.qml−2 src/CMakeLists.txt+8−2 src/ShellApplication.cpp → src/UnityApplication.cpp+9−29 src/ShellApplication.h → src/UnityApplication.h+6−6 src/UnityCommandLineParser.cpp+8 src/UnityCommandLineParser.h+3 src/libunity8-private/CMakeLists.txt+10 src/libunity8-private/windowmanagementpolicy.cpp+86 src/libunity8-private/windowmanagementpolicy.h+57 src/main.cpp+4−2 tests/mocks/Unity/Application/SurfaceManager.cpp+5 tests/mocks/Unity/Application/SurfaceManager.h+2 tests/mocks/Unity/Application/plugin.cpp+7−1 tests/mocks/WindowManager/CMakeLists.txt+11−7 tests/mocks/WindowManager/MockScreens.cpp+140 tests/mocks/WindowManager/MockScreens.h+46 tests/mocks/WindowManager/Screen.cpp−65 tests/mocks/WindowManager/Screen.h−56 tests/mocks/WindowManager/Screens.cpp−101 tests/mocks/WindowManager/Screens.h−65 tests/mocks/WindowManager/WindowManagerPlugin.cpp+7−3 tests/mocks/WindowManager/windowmanagementpolicy.h+54 tests/qmltests/ApplicationMenuDataLoader.qml+1−4 tests/qmltests/ApplicationMenus/tst_MenuBar.qml−2 tests/qmltests/Panel/tst_ActiveCallHint.qml−2 tests/qmltests/Panel/tst_Panel.qml−2 tests/qmltests/Stage/tst_ApplicationWindow.qml−2 tests/qmltests/Stage/tst_DecoratedWindow.qml−2 tests/qmltests/Stage/tst_DesktopStage.qml+1−3 tests/qmltests/Stage/tst_PhoneStage.qml+1−3 tests/qmltests/Stage/tst_SurfaceContainer.qml−2 tests/qmltests/Stage/tst_TabletStage.qml+1−3 tests/qmltests/Stage/tst_WindowDecoration.qml−2 tests/qmltests/Tutorial/tst_Tutorial.qml+1−3 tests/qmltests/tst_OrientedShell.qml−5 tests/qmltests/tst_Shell.qml+1−10
debian/control+1−1
@@ -31,6 +31,7 @@ Build-Depends: cmake,
3131 libqmenumodel-dev (>= 0.2.11),
3232 libqt5svg5-dev,
3333 libqt5xmlpatterns5-dev,
34+ libqtmirserver-dev (>= 0.6.0),
3435 libsystemsettings-dev,
3536 libubuntu-app-launch2-dev,
3637 libubuntu-download-manager-common-dev,
@@ -68,7 +69,6 @@ Build-Depends: cmake,
6869 qtdeclarative5-private-dev (>= 5.6),
6970 qtdeclarative5-ubuntu-content1,
7071 qtdeclarative5-ubuntu-settings-components (>= 0.11),
71− qtmir-dev (>= 0.6.0),
7272 ttf-ubuntu-font-family,
7373 xvfb,
7474Standards-Version: 3.9.4
plugins/WindowManager/CMakeLists.txt+6
@@ -3,6 +3,11 @@ include_directories(
33 ${QTMIRSERVER_INCLUDE_DIRS}
44)
55
6+include_directories(
7+ ${CMAKE_CURRENT_SOURCE_DIR}
8+ ${libunity8-private_SOURCE_DIR}
9+)
10+
611set(WINDOWMANAGER_SRC
712 TopLevelWindowModel.cpp
813 Window.cpp
@@ -24,6 +29,7 @@ add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
2429
2530target_link_libraries(windowmanager-qml
2631 ${QTMIRSERVER_LDFLAGS}
32+ unity8-private
2733)
2834
2935qt5_use_modules(windowmanager-qml Qml Quick Gui)
plugins/WindowManager/Screen.cpp+56−1
@@ -15,7 +15,6 @@
1515 */
1616
1717#include "Screen.h"
18−#include "WorkspaceModel.h"
1918#include "WorkspaceManager.h"
2019#include "Workspace.h"
2120
@@ -34,10 +33,38 @@ Screen::Screen(qtmir::Screen* screen)
3433 connect(m_wrapped, &qtmir::Screen::currentModeIndexChanged, this, &Screen::currentModeIndexChanged);
3534 connect(m_wrapped, &qtmir::Screen::availableModesChanged, this, &Screen::availableModesChanged);
3635
36+ // Connect the active workspace to activate the screen.
37+ connect(m_workspaces.data(), &WorkspaceModel::workspaceAdded, this, [this](Workspace* workspace) {
38+ connect(workspace, &Workspace::activeChanged, this, [this](bool active) {
39+ if (active) activate();
40+ });
41+ if (workspace->isActive()) activate();
42+ });
43+ connect(m_workspaces.data(), &WorkspaceModel::workspaceRemoved, this, [this](Workspace* workspace) {
44+ disconnect(workspace, &Workspace::activeChanged, this, 0);
45+ });
46+
3747 WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
3848 WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
3949}
4050
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+
4168qtmir::OutputId Screen::outputId() const
4269{
4370 return m_wrapped->outputId();
@@ -113,6 +140,23 @@ bool Screen::applyConfiguration(qtmir::ScreenConfiguration *configuration)
113140 return m_wrapped->applyConfiguration(configuration);
114141}
115142
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+
155+void Screen::activate()
156+{
157+ setActive(true);
158+}
159+
116160void Screen::setActive(bool active)
117161{
118162 m_wrapped->setActive(active);
@@ -122,3 +166,14 @@ QScreen *Screen::qscreen() const
122166{
123167 return m_wrapped->qscreen();
124168}
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+28−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,11 +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);
45+
46+public Q_SLOTS:
47+ void activate();
48+
49+protected:
50+ Screen(Screen const& other);
4051
41−private:
4252 qtmir::Screen*const m_wrapped;
4353 const QScopedPointer<WorkspaceModel> m_workspaces;
4454};
4555
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+
4671#endif // SCREEN_H
plugins/WindowManager/Screens.cpp+94−21
@@ -16,9 +16,9 @@
1616
1717#include "Screens.h"
1818#include "Screen.h"
19+#include "WorkspaceManager.h"
1920
2021// qtmirserver
21−#include <qtmir/qtmir.h>
2222#include <qtmir/screens.h>
2323#include <QGuiApplication>
2424
@@ -26,9 +26,8 @@
2626#include <QScreen>
2727#include <QWindow>
2828
29−Screens::Screens(QObject *parent)
30− : QAbstractListModel(parent)
31− , m_wrapped(qtmir::get_screen_model())
29+Screens::Screens(const QSharedPointer<qtmir::Screens>& model)
30+ : m_wrapped(model)
3231{
3332 if (qGuiApp->platformName() != QLatin1String("mirserver")) {
3433 qCritical("Not using 'mirserver' QPA plugin. Using qGuiApp may produce unknown results.");
@@ -36,13 +35,25 @@ Screens::Screens(QObject *parent)
3635
3736 connect(m_wrapped.data(), &qtmir::Screens::screenAdded, this, &Screens::onScreenAdded);
3837 connect(m_wrapped.data(), &qtmir::Screens::screenRemoved, this, &Screens::onScreenRemoved);
39− connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &Screens::activeScreenChanged);
38+ connect(m_wrapped.data(), &qtmir::Screens::activeScreenChanged, this, &Screens::activeScreenChanged);
4039
4140 Q_FOREACH(qtmir::Screen* screen, m_wrapped->screens()) {
42− m_screenList.push_back(new Screen(screen));
41+ m_screens.push_back(new Screen(screen));
4342 }
4443}
4544
45+Screens::~Screens()
46+{
47+ qDeleteAll(m_screens);
48+ m_screens.clear();
49+}
50+
51+Screens::Screens(const Screens &other)
52+ : QAbstractListModel(nullptr)
53+ , m_wrapped(other.m_wrapped)
54+{
55+}
56+
4657QHash<int, QByteArray> Screens::roleNames() const
4758{
4859 QHash<int, QByteArray> roles;
@@ -52,13 +63,13 @@ QHash<int, QByteArray> Screens::roleNames() const
5263
5364QVariant Screens::data(const QModelIndex &index, int role) const
5465{
55− if (!index.isValid() || index.row() >= m_screenList.size()) {
66+ if (!index.isValid() || index.row() >= m_screens.size()) {
5667 return QVariant();
5768 }
5869
5970 switch(role) {
6071 case ScreenRole:
61− return QVariant::fromValue(m_screenList.at(index.row()));
72+ return QVariant::fromValue(m_screens.at(index.row()));
6273 } // switch
6374
6475 return QVariant();
@@ -71,48 +82,66 @@ int Screens::rowCount(const QModelIndex &) const
7182
7283int Screens::count() const
7384{
74− return m_screenList.size();
85+ return m_screens.size();
7586}
7687
7788QVariant Screens::activeScreen() const
7889{
79− for (int i = 0; i < m_screenList.count(); i++) {
80− if (m_screenList[i]->isActive()) return i;
90+ for (int i = 0; i < m_screens.count(); i++) {
91+ if (m_screens[i]->isActive()) return i;
8192 }
8293 return QVariant();
8394}
8495
96+ScreensProxy *Screens::createProxy()
97+{
98+ return new ScreensProxy(this);
99+}
100+
101+void Screens::sync(Screens *proxy)
102+{
103+ if (!proxy) return;
104+
105+ const auto& proxyList = proxy->list();
106+ for (int i = 0; i < m_screens.count() && i < proxyList.count(); ++i) {
107+ m_screens[i]->sync(proxyList[i]);
108+ }
109+
110+ // need to clean up all the workspaces we unassigned.
111+ WorkspaceManager::instance()->destroyFloatingWorkspaces();
112+}
113+
85114void Screens::activateScreen(const QVariant& vindex)
86115{
87116 bool ok = false;
88117 int index = vindex.toInt(&ok);
89− if (!ok || index < 0 || m_screenList.count() <= index) return;
118+ if (!ok || index < 0 || m_screens.count() <= index) return;
90119
91− auto screen = m_screenList.at(index);
120+ auto screen = m_screens.at(index);
92121 screen->setActive(true);
93122}
94123
95−void Screens::onScreenAdded(qtmir::Screen *screen)
124+void Screens::onScreenAdded(qtmir::Screen *added)
96125{
97− Q_FOREACH(auto screenWrapper, m_screenList) {
98− if (screenWrapper->wrapped() == screen) return;
126+ Q_FOREACH(auto screenWrapper, m_screens) {
127+ if (screenWrapper->wrapped() == added) return;
99128 }
100129
101130 beginInsertRows(QModelIndex(), count(), count());
102− auto screenWrapper(new Screen(screen));
103− m_screenList.push_back(screenWrapper);
131+ auto screenWrapper(new Screen(added));
132+ m_screens.push_back(screenWrapper);
104133 endInsertRows();
105134 Q_EMIT screenAdded(screenWrapper);
106135 Q_EMIT countChanged();
107136}
108137
109−void Screens::onScreenRemoved(qtmir::Screen *screen)
138+void Screens::onScreenRemoved(qtmir::Screen *removed)
110139{
111140 int index = 0;
112− QMutableListIterator<Screen*> iter(m_screenList);
141+ QMutableVectorIterator<Screen*> iter(m_screens);
113142 while(iter.hasNext()) {
114143 auto screenWrapper = iter.next();
115− if (screenWrapper->wrapped() == screen) {
144+ if (screenWrapper->wrapped() == removed) {
116145
117146 beginRemoveRows(QModelIndex(), index, index);
118147 iter.remove();
@@ -127,3 +156,47 @@ void Screens::onScreenRemoved(qtmir::Screen *screen)
127156 index++;
128157 }
129158}
159+
160+ScreensProxy::ScreensProxy(Screens * const screens)
161+ : Screens(*screens)
162+ , m_original(screens)
163+{
164+ connect(screens, &Screens::screenAdded, this, [this](Screen *added) {
165+ Q_FOREACH(auto screen, m_screens) {
166+ auto proxy = static_cast<ScreenProxy*>(screen);
167+ if (proxy->proxyObject() == added) return;
168+ }
169+
170+ beginInsertRows(QModelIndex(), count(), count());
171+ auto screenWrapper(new ScreenProxy(added));
172+ m_screens.push_back(screenWrapper);
173+ endInsertRows();
174+ Q_EMIT screenAdded(screenWrapper);
175+ Q_EMIT countChanged();
176+ });
177+
178+ connect(screens, &Screens::screenAdded, this, [this](Screen *removed) {
179+ int index = 0;
180+ QMutableVectorIterator<Screen*> iter(m_screens);
181+ while(iter.hasNext()) {
182+ auto proxy = static_cast<ScreenProxy*>(iter.next());
183+ if (proxy->proxyObject() == removed) {
184+
185+ beginRemoveRows(QModelIndex(), index, index);
186+ iter.remove();
187+ endRemoveRows();
188+
189+ Q_EMIT screenRemoved(proxy);
190+ Q_EMIT countChanged();
191+
192+ delete proxy;
193+ break;
194+ }
195+ index++;
196+ }
197+ });
198+
199+ Q_FOREACH(Screen* screen, screens->list()) {
200+ m_screens.push_back(new ScreenProxy(screen));
201+ }
202+}
plugins/WindowManager/Screens.h+24−5
@@ -19,14 +19,17 @@
1919
2020#include <QAbstractListModel>
2121#include <QSharedPointer>
22+#include <QPointer>
2223
23−class Screen;
2424namespace qtmir
2525{
2626class Screen;
2727class Screens;
2828}
2929
30+class Screen;
31+class ScreensProxy;
32+
3033class Screens : public QAbstractListModel
3134{
3235 Q_OBJECT
@@ -38,8 +41,11 @@ public:
3841 ScreenRole = Qt::UserRole + 1
3942 };
4043
41− explicit Screens(QObject *parent = 0);
42− virtual ~Screens() noexcept = default;
44+ explicit Screens(const QSharedPointer<qtmir::Screens>& model);
45+ ~Screens();
46+
47+ Q_INVOKABLE ScreensProxy *createProxy();
48+ Q_INVOKABLE void sync(Screens *proxy);
4349
4450 /* QAbstractItemModel */
4551 QHash<int, QByteArray> roleNames() 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 QPointer<Screens> m_original;
88+};
89+
7190#endif // SCREENS_H
plugins/WindowManager/TopLevelWindowModel.cpp+167−43
@@ -24,11 +24,16 @@
2424#include <unity/shell/application/SurfaceManagerInterface.h>
2525
2626// Qt
27−#include <QGuiApplication>
2827#include <QDebug>
2928
3029// local
3130#include "Window.h"
31+#include "Workspace.h"
32+#include "windowmanagementpolicy.h"
33+
34+// qtmir
35+#include <qtmir/mirserverapplication.h>
36+#include <qtmir/windowmodelnotifier.h>
3237
3338Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
3439
@@ -55,35 +60,24 @@ void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInte
5560 beginResetModel();
5661
5762 if (m_applicationManager) {
58− m_windowModel.clear();
5963 disconnect(m_applicationManager, 0, this, 0);
6064 }
6165
6266 m_applicationManager = value;
6367
64− if (m_applicationManager) {
65− connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
66− this, [this](const QModelIndex &/*parent*/, int first, int last) {
67− for (int i = first; i <= last; ++i) {
68− auto application = m_applicationManager->get(i);
69− addApplication(application);
70− }
71− });
68+ if (m_applicationManager && m_workspace) {
7269
73− connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
74− this, [this](const QModelIndex &/*parent*/, int first, int last) {
75− for (int i = first; i <= last; ++i) {
76− auto application = m_applicationManager->get(i);
77− removeApplication(application);
78− }
79− });
70+ if (m_workspace->isActive()) {
71+ connectApplicationManager();
72+ }
8073
81− for (int i = 0; i < m_applicationManager->rowCount(); ++i) {
82− auto application = m_applicationManager->get(i);
83− addApplication(application);
74+ if (m_surfaceManager) {
75+ refreshWindows();
8476 }
8577 }
8678
79+ Q_EMIT applicationManagerChanged(m_applicationManager);
80+
8781 endResetModel();
8882 m_modelState = IdleState;
8983}
@@ -96,6 +90,11 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
9690
9791 DEBUG_MSG << "(" << surfaceManager << ")";
9892
93+ Q_ASSERT(m_modelState == IdleState);
94+ m_modelState = ResettingState;
95+
96+ beginResetModel();
97+
9998 if (m_surfaceManager) {
10099 disconnect(m_surfaceManager, 0, this, 0);
101100 }
@@ -107,9 +106,68 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
107106 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
108107 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
109108 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
109+
110+ connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesAddedToWorkspace,
111+ this, &TopLevelWindowModel::onSurfacesAddedToWorkspace);
112+
113+ if (m_workspace && m_applicationManager) {
114+ refreshWindows();
115+ }
110116 }
111117
112118 Q_EMIT surfaceManagerChanged(m_surfaceManager);
119+
120+ endResetModel();
121+ m_modelState = IdleState;
122+}
123+
124+void TopLevelWindowModel::setWorkspace(Workspace *workspace)
125+{
126+ if (workspace == m_workspace) {
127+ return;
128+ }
129+
130+ DEBUG_MSG << "(" << workspace << ")";
131+
132+ Q_ASSERT(m_modelState == IdleState);
133+ m_modelState = ResettingState;
134+
135+ beginResetModel();
136+
137+ if (m_workspace) {
138+ m_windowModel.clear();
139+ if (m_applicationManager) {
140+ disconnect(m_applicationManager, 0, this, 0);
141+ }
142+ }
143+
144+ disconnect(m_applicationManager, 0 ,this, 0);
145+
146+ m_workspace = workspace;
147+
148+ if (m_workspace) {
149+ connect(m_workspace, &Workspace::activeChanged, this, [this](bool active) {
150+ if (m_applicationManager) {
151+ if (!active) disconnect(m_applicationManager, 0, this, 0);
152+ else {
153+ connectApplicationManager();
154+ }
155+ }
156+ });
157+
158+ if (m_applicationManager && m_workspace->isActive()) {
159+ connectApplicationManager();
160+ }
161+
162+ if (m_surfaceManager && m_applicationManager) {
163+ refreshWindows();
164+ }
165+ }
166+
167+ Q_EMIT workspaceChanged(workspace);
168+
169+ endResetModel();
170+ m_modelState = IdleState;
113171}
114172
115173void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
@@ -328,33 +386,43 @@ Window *TopLevelWindowModel::createWindow(unityapi::MirSurfaceInterface *surface
328386 return qmlWindow;
329387}
330388
331−void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
389+
390+void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface */*surface*/)
332391{
333− DEBUG_MSG << "(" << surface << ")";
392+}
334393
335− if (surface->parentSurface()) {
336− // Wrap it in a Window so that we keep focusedWindow() up to date.
337− Window *window = createWindow(surface);
338− connect(surface, &QObject::destroyed, window, [=](){
339− window->setSurface(nullptr);
340− window->deleteLater();
341− });
342− } else {
343− if (surface->type() == Mir::InputMethodType) {
344− setInputMethodWindow(createWindow(surface));
394+void TopLevelWindowModel::onSurfacesAddedToWorkspace(const std::shared_ptr<miral::Workspace>& workspace,
395+ const QVector<unity::shell::application::MirSurfaceInterface*> surfaces)
396+{
397+ if (workspace != m_workspace->workspace()) return;
398+
399+ Q_FOREACH(auto surface, surfaces) {
400+ DEBUG_MSG << "(" << surface << ")";
401+
402+ if (surface->parentSurface()) {
403+ // Wrap it in a Window so that we keep focusedWindow() up to date.
404+ Window *window = createWindow(surface);
405+ connect(surface, &QObject::destroyed, window, [=](){
406+ window->setSurface(nullptr);
407+ window->deleteLater();
408+ });
345409 } else {
346− auto *application = m_applicationManager->findApplicationWithSurface(surface);
347− if (application) {
348− prependSurface(surface, application);
410+ if (surface->type() == Mir::InputMethodType) {
411+ setInputMethodWindow(createWindow(surface));
349412 } else {
350− // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
351− // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
352− // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
353− Window *promptWindow = createWindow(surface);
354− connect(surface, &QObject::destroyed, promptWindow, [=](){
355− promptWindow->setSurface(nullptr);
356− promptWindow->deleteLater();
357− });
413+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
414+ if (application) {
415+ prependSurface(surface, application);
416+ } else {
417+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
418+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
419+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
420+ Window *promptWindow = createWindow(surface);
421+ connect(surface, &QObject::destroyed, promptWindow, [=](){
422+ promptWindow->setSurface(nullptr);
423+ promptWindow->deleteLater();
424+ });
425+ }
358426 }
359427 }
360428 }
@@ -444,6 +512,26 @@ QVariant TopLevelWindowModel::data(const QModelIndex& index, int role) const
444512 }
445513}
446514
515+void TopLevelWindowModel::connectApplicationManager()
516+{
517+ connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
518+ this, [this](const QModelIndex &/*parent*/, int first, int last) {
519+ for (int i = first; i <= last; ++i) {
520+ auto application = m_applicationManager->get(i);
521+ addApplication(application);
522+ }
523+ });
524+
525+ connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
526+ this, [this](const QModelIndex &/*parent*/, int first, int last) {
527+ for (int i = first; i <= last; ++i) {
528+ auto application = m_applicationManager->get(i);
529+ removeApplication(application);
530+ }
531+ });
532+}
533+
534+
447535int TopLevelWindowModel::findIndexOf(const unityapi::MirSurfaceInterface *surface) const
448536{
449537 for (int i=0; i<m_windowModel.count(); i++) {
@@ -674,3 +762,39 @@ void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
674762 }
675763 }
676764}
765+
766+void TopLevelWindowModel::refreshWindows()
767+{
768+ m_windowModel.clear();
769+ WindowManagementPolicy::instance()->forEachWindowInWorkspace(m_workspace->workspace(), [this](const miral::Window &window) {
770+ auto surface = m_surfaceManager->surfaceFor(window);
771+ if (surface) {
772+ if (surface->parentSurface()) {
773+ // Wrap it in a Window so that we keep focusedWindow() up to date.
774+ Window *window = createWindow(surface);
775+ connect(surface, &QObject::destroyed, window, [=](){
776+ window->setSurface(nullptr);
777+ window->deleteLater();
778+ });
779+ } else {
780+ if (surface->type() == Mir::InputMethodType) {
781+ setInputMethodWindow(createWindow(surface));
782+ } else {
783+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
784+ if (application) {
785+ prependSurface(surface, application);
786+ } else {
787+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
788+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
789+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
790+ Window *promptWindow = createWindow(surface);
791+ connect(surface, &QObject::destroyed, promptWindow, [=](){
792+ promptWindow->setSurface(nullptr);
793+ promptWindow->deleteLater();
794+ });
795+ }
796+ }
797+ }
798+ }
799+ });
800+}
plugins/WindowManager/TopLevelWindowModel.h+19
@@ -20,9 +20,14 @@
2020#include <QAbstractListModel>
2121#include <QLoggingCategory>
2222
23+#include <memory>
24+
2325Q_DECLARE_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL)
2426
2527class Window;
28+class Workspace;
29+
30+namespace miral { class Workspace; }
2631
2732namespace unity {
2833 namespace shell {
@@ -70,6 +75,11 @@ class TopLevelWindowModel : public QAbstractListModel
7075 */
7176 Q_PROPERTY(Window* focusedWindow READ focusedWindow NOTIFY focusedWindowChanged)
7277
78+ Q_PROPERTY(Workspace* workspace
79+ READ workspace
80+ WRITE setWorkspace
81+ NOTIFY workspaceChanged)
82+
7383 Q_PROPERTY(unity::shell::application::SurfaceManagerInterface* surfaceManager
7484 READ surfaceManager
7585 WRITE setSurfaceManager
@@ -111,6 +121,9 @@ public:
111121
112122 // Own API
113123
124+ Workspace* workspace() const { return m_workspace; }
125+ void setWorkspace(Workspace* workspace);
126+
114127 unity::shell::application::MirSurfaceInterface* inputMethodSurface() const;
115128 Window* focusedWindow() const;
116129
@@ -178,8 +191,11 @@ Q_SIGNALS:
178191
179192 void nextIdChanged();
180193
194+ void workspaceChanged(Workspace*);
195+
181196private Q_SLOTS:
182197 void onSurfaceCreated(unity::shell::application::MirSurfaceInterface *surface);
198+ void onSurfacesAddedToWorkspace(const std::shared_ptr<miral::Workspace>& workspace, const QVector<unity::shell::application::MirSurfaceInterface*> surfaces);
183199 void onSurfacesRaised(const QVector<unity::shell::application::MirSurfaceInterface*> &surfaces);
184200
185201 void onModificationsStarted();
@@ -208,6 +224,7 @@ private:
208224 void prependSurfaceHelper(unity::shell::application::MirSurfaceInterface *surface,
209225 unity::shell::application::ApplicationInfoInterface *application);
210226
227+ void connectApplicationManager();
211228 void connectWindow(Window *window);
212229 void connectSurface(unity::shell::application::MirSurfaceInterface *surface);
213230
@@ -219,6 +236,7 @@ private:
219236 void activateEmptyWindow(Window *window);
220237
221238 void activateTopMostWindowWithoutId(int forbiddenId);
239+ void refreshWindows();
222240
223241 Window *createWindow(unity::shell::application::MirSurfaceInterface *surface);
224242
@@ -232,6 +250,7 @@ private:
232250 bool removeOnceSurfaceDestroyed{false};
233251 };
234252
253+ Workspace* m_workspace{nullptr};
235254 QVector<ModelEntry> m_windowModel;
236255 Window* m_inputMethodWindow{nullptr};
237256 Window* m_focusedWindow{nullptr};
plugins/WindowManager/WindowManagerPlugin.cpp+6−3
@@ -26,6 +26,7 @@
2626#include "WorkspaceModel.h"
2727
2828#include <QtQml>
29+#include <qtmir/qtmir.h>
2930
3031static QObject *workspace_manager(QQmlEngine *engine, QJSEngine *scriptEngine)
3132{
@@ -36,7 +37,7 @@ static QObject *workspace_manager(QQmlEngine *engine, QJSEngine *scriptEngine)
3637QObject* screensSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
3738 Q_UNUSED(engine);
3839 Q_UNUSED(scriptEngine);
39− return new Screens();
40+ return new Screens(qtmir::get_screen_model());
4041}
4142
4243void WindowManagerPlugin::registerTypes(const char *uri)
@@ -46,12 +47,14 @@ void WindowManagerPlugin::registerTypes(const char *uri)
4647 qmlRegisterUncreatableType<WorkspaceModel>(uri, 1, 0, "WorkspaceModel", "Not a creatable type");
4748 qmlRegisterSingletonType<Screens>(uri, 1, 0, "Screens", screensSingleton);
4849 qmlRegisterUncreatableType<qtmir::ScreenMode>(uri, 1, 0, "ScreenMode", "ScreenMode is not creatable.");
50+ qmlRegisterUncreatableType<Workspace>(uri, 1, 0, "Workspace", "Workspace is not creatable.");
4951
50− qRegisterMetaType<Window*>("Window*");
52+ qRegisterMetaType<Screen*>("Screen*");
53+ qRegisterMetaType<ScreensProxy*>("ScreensProxy*");
5154 qRegisterMetaType<Workspace*>("Workspace*");
5255
56+ qRegisterMetaType<Window*>("Window*");
5357 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
54− qRegisterMetaType<Screen*>("Screen*");
5558
5659 qmlRegisterType<ScreenWindow>(uri, 1, 0, "ScreenWindow");
5760 qmlRegisterRevision<QWindow,1>(uri, 1, 0);
plugins/WindowManager/Workspace.cpp+97−13
@@ -16,48 +16,132 @@
1616
1717#include "Workspace.h"
1818#include "WorkspaceModel.h"
19+#include "WorkspaceManager.h"
20+#include "TopLevelWindowModel.h"
21+
22+#include "windowmanagementpolicy.h"
23+
24+int nextWorkspace = 0;
1925
2026Workspace::Workspace(QObject *parent)
2127 : QObject(parent)
28+ , m_workspace(WindowManagementPolicy::instance()->createWorkspace())
2229 , m_model(nullptr)
30+ , m_active(false)
2331{
32+ setObjectName((QString("Wks%1").arg(nextWorkspace++)));
33+
34+ connect(WorkspaceManager::instance(), &WorkspaceManager::activeWorkspaceChanged, this, [this]() {
35+ bool newActive = WorkspaceManager::instance()->activeWorkspace() == this;
36+ if (newActive != m_active) {
37+ m_active = newActive;
38+ Q_EMIT activeChanged(m_active);
2439
40+ if (m_active) {
41+ WindowManagementPolicy::instance()->setActiveWorkspace(m_workspace);
42+ }
43+ }
44+ });
45+}
46+
47+Workspace::Workspace(const Workspace &other)
48+ : QObject(nullptr)
49+ , m_workspace(other.m_workspace)
50+ , m_model(nullptr)
51+ , m_active(other.m_active)
52+{
53+ setObjectName(other.objectName());
54+
55+ connect(&other, &Workspace::activeChanged, this, [this](bool active) {
56+ m_active = active;
57+ Q_EMIT activeChanged(m_active);
58+ });
2559}
2660
2761Workspace::~Workspace()
2862{
29− unassign();
63+ if (m_model) {
64+ m_model->remove(this);
65+ }
66+}
67+
68+void Workspace::moveWindowsTo(Workspace *workspace)
69+{
70+ WindowManagementPolicy::instance()->moveWorkspaceContentToWorkspace(workspace->m_workspace, m_workspace);
71+}
72+
73+void Workspace::activate()
74+{
75+ WorkspaceManager::instance()->setActiveWorkspace(this);
3076}
3177
32−void Workspace::assign(WorkspaceModel *model)
78+void Workspace::assign(WorkspaceModel *model, const QVariant& vIndex)
3379{
34− bool wasAssinged = false;
80+ if (m_model == model) return;
81+
3582 if (m_model) {
36− disconnect(model);
83+ disconnect(m_model, 0, this, 0);
3784 m_model->remove(this);
38− wasAssinged = true;
3985 }
4086
4187 m_model = model;
88+
4289 if (model) {
43− model->append(this);
90+ int index = m_model->rowCount();
91+ if (vIndex.isValid() && vIndex.canConvert(QVariant::Int)) {
92+ index = vIndex.toInt();
93+ }
94+ m_model->insert(index, this);
4495
45− connect(model, &QObject::destroyed, this, [this]() {
96+ connect(m_model, &QObject::destroyed, this, [this]() {
97+ m_model->remove(this);
4698 m_model = nullptr;
4799 Q_EMIT unassigned();
48100 });
49101 Q_EMIT assigned();
50− } else if (wasAssinged) {
102+ } else {
51103 Q_EMIT unassigned();
52104 }
53105}
54106
55107void Workspace::unassign()
56108{
57− if (m_model) {
58− m_model->remove(this);
59− m_model = nullptr;
109+ assign(nullptr);
110+}
60111
61− Q_EMIT unassigned();
62− }
112+void Workspace::release()
113+{
114+ WindowManagementPolicy::instance()->releaseWorkspace(m_workspace);
115+ deleteLater();
116+}
117+
118+bool Workspace::isAssigned() const
119+{
120+ return m_model != nullptr;
121+}
122+
123+WorkspaceProxy::WorkspaceProxy(Workspace * const workspace)
124+ : Workspace(*workspace)
125+ , m_original(workspace)
126+{
127+}
128+
129+void WorkspaceProxy::assign(WorkspaceModel *model, const QVariant &index)
130+{
131+ Workspace::assign(model, index);
132+}
133+
134+void WorkspaceProxy::unassign()
135+{
136+ Workspace::unassign();
137+}
138+
139+bool WorkspaceProxy::isActive() const
140+{
141+ return m_original ? m_original->isActive() : false;
142+}
143+
144+void WorkspaceProxy::activate()
145+{
146+ if (m_original) m_original->activate();
63147}
plugins/WindowManager/Workspace.h+64−8
@@ -14,31 +14,87 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#ifndef WORKSPACE_H
18−#define WORKSPACE_H
17+#ifndef WINDOWMANAGER_WORKSPACE_H
18+#define WINDOWMANAGER_WORKSPACE_H
1919
2020#include <QObject>
21+#include <QVariant>
22+#include <QPointer>
23+
24+#include <memory>
25+#include <functional>
2126
2227class WorkspaceModel;
28+class TopLevelWindowModel;
29+
30+namespace miral { class Workspace; }
31+
32+namespace unity {
33+ namespace shell {
34+ namespace application {
35+ class MirSurfaceInterface;
36+ }
37+ }
38+}
2339
2440class Workspace : public QObject
2541{
2642 Q_OBJECT
43+ Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
2744public:
28− explicit Workspace(QObject *parent = 0);
2945 ~Workspace();
3046
31− Q_INVOKABLE void assign(WorkspaceModel* model);
47+ virtual void assign(WorkspaceModel* model, const QVariant& index = QVariant());
48+ virtual void unassign();
49+ void release();
50+
51+ virtual bool isActive() const { return m_active; }
52+ bool isAssigned() const;
53+
54+ void moveWindowsTo(Workspace* workspace);
55+
56+ std::shared_ptr<miral::Workspace> workspace() const { return m_workspace; }
3257
33−public Q_SLOT:
34− void unassign();
58+
59+public Q_SLOTS:
60+ virtual void activate();
3561
3662Q_SIGNALS:
3763 void assigned();
3864 void unassigned();
3965
40−private:
66+ void activeChanged(bool);
67+
68+protected:
69+ Workspace(QObject *parent = 0);
70+ Workspace(Workspace const& other);
71+
72+ std::shared_ptr<miral::Workspace> m_workspace;
4173 WorkspaceModel* m_model;
74+ bool m_active;
75+
76+ friend class WorkspaceManager;
77+};
78+
79+class WorkspaceProxy : public Workspace
80+{
81+ Q_OBJECT
82+public:
83+ WorkspaceProxy(Workspace*const workspace);
84+
85+ Q_INVOKABLE void assign(WorkspaceModel* model, const QVariant& index = QVariant()) override;
86+
87+ bool isActive() const override;
88+
89+ void activate() override;
90+
91+ Workspace* proxyObject() const { return m_original.data(); }
92+
93+public Q_SLOTS:
94+ void unassign() override;
95+
96+private:
97+ const QPointer<Workspace> m_original;
4298};
4399
44−#endif // WORKSPACE_H
100+#endif // WINDOWMANAGER_WORKSPACE_H
plugins/WindowManager/WorkspaceManager.cpp+67−3
@@ -16,6 +16,7 @@
1616
1717#include "WorkspaceManager.h"
1818#include "Workspace.h"
19+#include "TopLevelWindowModel.h"
1920
2021// Qt
2122#include <QGuiApplication>
@@ -29,19 +30,82 @@ WorkspaceManager *WorkspaceManager::instance()
2930}
3031
3132WorkspaceManager::WorkspaceManager()
33+ : m_activeWorkspace(nullptr)
3234{
3335}
36+
3437Workspace *WorkspaceManager::createWorkspace()
3538{
3639 auto workspace = new Workspace(this);
3740 QQmlEngine::setObjectOwnership(workspace, QQmlEngine::CppOwnership);
38− m_allWorkspaces.append(workspace);
39− workspace->assign(this);
41+ m_allWorkspaces.insert(workspace);
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+ });
52+
53+ if (m_allWorkspaces.count() == 0 && m_activeWorkspace) {
54+ setActiveWorkspace(nullptr);
55+ Q_EMIT activeWorkspaceChanged();
56+ } else if (m_allWorkspaces.count() == 1) {
57+ setActiveWorkspace(workspace);
58+ }
59+
4060 return workspace;
4161}
4262
4363void WorkspaceManager::destroyWorkspace(Workspace *workspace)
4464{
45− workspace->deleteLater();
65+ if (!workspace) return;
66+
67+ if (workspace->isAssigned()) {
68+ workspace->unassign();
69+ }
70+ m_floatingWorkspaces.removeOne(workspace);
71+ m_allWorkspaces.remove(workspace);
72+ Q_EMIT floatingWorkspacesChanged();
73+
74+ if (m_activeWorkspace == workspace) {
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);
81+ }
82+
83+ disconnect(workspace, 0, this, 0);
84+ workspace->release();
85+}
86+
87+QQmlListProperty<Workspace> WorkspaceManager::floatingWorkspaces()
88+{
89+ return QQmlListProperty<Workspace>(this, m_floatingWorkspaces);
4690}
4791
92+void WorkspaceManager::destroyFloatingWorkspaces()
93+{
94+ QList<Workspace*> dpCpy(m_floatingWorkspaces);
95+ Q_FOREACH(auto workspace, dpCpy) {
96+ destroyWorkspace(workspace);
97+ }
98+}
99+
100+Workspace *WorkspaceManager::activeWorkspace() const
101+{
102+ return m_activeWorkspace;
103+}
104+
105+void WorkspaceManager::setActiveWorkspace(Workspace *workspace)
106+{
107+ if (workspace != m_activeWorkspace) {
108+ m_activeWorkspace = workspace;
109+ Q_EMIT activeWorkspaceChanged();
110+ }
111+}
plugins/WindowManager/WorkspaceManager.h+20−5
@@ -18,24 +18,39 @@
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
29+ Q_PROPERTY(Workspace* activeWorkspace READ activeWorkspace WRITE setActiveWorkspace NOTIFY activeWorkspaceChanged)
30+ Q_PROPERTY(QQmlListProperty<Workspace> floatingWorkspaces READ floatingWorkspaces NOTIFY floatingWorkspacesChanged)
31+
2732public:
2833 static WorkspaceManager* instance();
2934
30−private:
31− WorkspaceManager();
35+ Workspace* activeWorkspace() const;
36+ void setActiveWorkspace(Workspace* workspace);
3237
33−public Q_SLOTS:
3438 Workspace* createWorkspace();
3539 void destroyWorkspace(Workspace* workspace);
3640
41+ QQmlListProperty<Workspace> floatingWorkspaces();
42+ void destroyFloatingWorkspaces();
43+
44+Q_SIGNALS:
45+ void activeWorkspaceChanged();
46+ void floatingWorkspacesChanged();
47+
3748private:
38− QVector<Workspace*> m_allWorkspaces;
49+ WorkspaceManager();
50+
51+ QSet<Workspace*> m_allWorkspaces;
52+ QList<Workspace*> m_floatingWorkspaces;
53+ Workspace* m_activeWorkspace;
3954};
4055
4156#endif // WORKSPACEMANAGER_H
plugins/WindowManager/WorkspaceModel.cpp+94−2
@@ -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)
@@ -35,8 +36,12 @@ void WorkspaceModel::append(Workspace *workspace)
3536void WorkspaceModel::insert(int index, Workspace *workspace)
3637{
3738 beginInsertRows(QModelIndex(), index, index);
38− m_workspaces.append(workspace);
39+
40+ m_workspaces.insert(index, workspace);
41+
3942 endInsertRows();
43+
44+ Q_EMIT workspaceAdded(workspace);
4045 Q_EMIT countChanged();
4146}
4247
@@ -46,8 +51,12 @@ void WorkspaceModel::remove(Workspace *workspace)
4651 if (index < 0) return;
4752
4853 beginRemoveRows(QModelIndex(), index, index);
54+
4955 m_workspaces.removeAt(index);
56+
5057 endRemoveRows();
58+
59+ Q_EMIT workspaceRemoved(workspace);
5160 Q_EMIT countChanged();
5261}
5362
@@ -71,6 +80,17 @@ void WorkspaceModel::move(int from, int to)
7180 }
7281}
7382
83+int WorkspaceModel::indexOf(Workspace *workspace) const
84+{
85+ return m_workspaces.indexOf(workspace);
86+}
87+
88+Workspace *WorkspaceModel::get(int index) const
89+{
90+ if (index < 0 || index >= rowCount()) return nullptr;
91+ return m_workspaces.at(index);
92+}
93+
7494int WorkspaceModel::rowCount(const QModelIndex &) const
7595{
7696 return m_workspaces.count();
@@ -88,3 +108,75 @@ QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
88108 return QVariant();
89109 }
90110}
111+
112+void WorkspaceModel::sync(WorkspaceModel *proxy)
113+{
114+ if (!proxy) return;
115+ const auto& proxyList = proxy->list();
116+
117+ // check for removals
118+ int removedIndexWhichWasActive = -1;
119+ QVector<Workspace*> dpCpy(this->list());
120+ Q_FOREACH(auto workspace, dpCpy) {
121+
122+ bool found = false;
123+ Q_FOREACH(auto p, proxyList) {
124+ auto workspaceProxy = static_cast<WorkspaceProxy*>(p);
125+ if (workspaceProxy->proxyObject() == workspace) {
126+ found = true;
127+ break;
128+ }
129+ }
130+ if (!found) {
131+ if (workspace->isActive()) {
132+ removedIndexWhichWasActive = indexOf(workspace);
133+ }
134+ workspace->unassign();
135+ }
136+ }
137+
138+ // existing
139+ QSet<Workspace*> newWorkspaces;
140+ for (int i = 0; i < proxyList.count(); i++) {
141+ auto workspaceProxy = static_cast<WorkspaceProxy*>(proxyList[i]);
142+ auto workspace = workspaceProxy->proxyObject();
143+
144+ int oldIndex = this->indexOf(workspace);
145+
146+ if (oldIndex < 0) {
147+ workspace->assign(this, QVariant(i));
148+ } else if (oldIndex != i) {
149+ this->move(oldIndex, i);
150+ }
151+ newWorkspaces.insert(workspace);
152+ }
153+
154+ // Make sure we have at least one workspace in the model.
155+ if (rowCount() == 0) {
156+ Workspace* workspace = WorkspaceManager::instance()->createWorkspace();
157+ workspace->assign(this);
158+ (new WorkspaceProxy(workspace))->assign(proxy);
159+ }
160+
161+ if (removedIndexWhichWasActive != -1) {
162+ int newActiveIndex = qMin(removedIndexWhichWasActive, this->rowCount()-1);
163+ Workspace* newActiveWorkspace = newActiveIndex >= 0 ? this->get(newActiveIndex) : nullptr;
164+
165+ WorkspaceManager::instance()->setActiveWorkspace(newActiveWorkspace);
166+ }
167+}
168+
169+
170+WorkspaceModelProxy::WorkspaceModelProxy(WorkspaceModel * const model)
171+ : m_original(model)
172+{
173+ Q_FOREACH(auto workspace, model->list()) {
174+ (new WorkspaceProxy(workspace))->assign(this);
175+ }
176+}
177+
178+WorkspaceModelProxy::~WorkspaceModelProxy()
179+{
180+ qDeleteAll(m_workspaces.toList()); // make a copy so the list doesnt edit itself during delete.
181+ m_workspaces.clear();
182+}
plugins/WindowManager/WorkspaceModel.h+26−4
@@ -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{
@@ -40,10 +42,13 @@ public:
4042
4143 explicit WorkspaceModel(QObject *parent = 0);
4244
43− Q_INVOKABLE void append(Workspace* workspace);
44− Q_INVOKABLE void insert(int index, Workspace* workspace);
45− Q_INVOKABLE void remove(Workspace* workspace);
46− Q_INVOKABLE void move(int from, int to);
45+ void append(Workspace *workspace);
46+ void insert(int index, Workspace *workspace);
47+ void remove(Workspace* workspace);
48+ void move(int from, int to);
49+
50+ int indexOf(Workspace *workspace) const;
51+ Workspace* get(int index) const;
4752
4853 // From QAbstractItemModel
4954 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
@@ -53,11 +58,28 @@ public:
5358 return roleNames;
5459 }
5560
61+ const QVector<Workspace*>& list() const { return m_workspaces; }
62+
63+ void sync(WorkspaceModel* proxy);
64+
5665Q_SIGNALS:
5766 void countChanged();
5867
68+ void workspaceAdded(Workspace *workspace);
69+ void workspaceRemoved(Workspace *workspace);
70+
5971protected:
6072 QVector<Workspace*> m_workspaces;
6173};
6274
75+class WorkspaceModelProxy : public WorkspaceModel
76+{
77+public:
78+ WorkspaceModelProxy(WorkspaceModel*const model);
79+ ~WorkspaceModelProxy();
80+
81+private:
82+ const QPointer<WorkspaceModel> m_original;
83+};
84+
6385#endif // WORKSPACEMODEL_H
qml/Shell.qml+1−1
@@ -54,7 +54,6 @@ StyledItem {
5454 theme.name: "Ubuntu.Components.Themes.SuruDark"
5555
5656 // to be set from outside
57− property alias surfaceManager: topLevelSurfaceList.surfaceManager
5857 property int orientationAngle: 0
5958 property int orientation
6059 property Orientations orientations
@@ -277,6 +276,7 @@ StyledItem {
277276 id: topLevelSurfaceList
278277 objectName: "topLevelSurfaceList"
279278 applicationManager: ApplicationManager // it's a singleton
279+ surfaceManager: SurfaceManager
280280 }
281281
282282 Stage {
qml/ShellApplication.qml−4
@@ -17,21 +17,17 @@
1717import QtQuick 2.4
1818import QtQuick.Window 2.2
1919import WindowManager 1.0
20−import Unity.Application 0.1
2120
2221Instantiator {
2322 id: root
2423 model: Screens
2524
26− property QtObject surfaceMan: SurfaceManager {}
27−
2825 ShellScreen {
2926 id: window
3027 objectName: "screen"+index
3128 screen: model.screen
3229 visibility: applicationArguments.hasFullscreen ? Window.FullScreen : Window.Windowed
3330 flags: applicationArguments.hasFrameless ? Qt.FramelessWindowHint : 0
34− surfaceManager: surfaceMan
3531
3632 Binding {
3733 when: applicationArguments.hasGeometry
qml/ShellScreen.qml−2
@@ -26,7 +26,6 @@ ScreenWindow {
2626 color: "black"
2727 title: "Unity8 Shell"
2828 property bool primary: false
29− property QtObject surfaceManager: null
3029
3130 DeviceConfiguration {
3231 id: deviceConfiguration
@@ -50,7 +49,6 @@ ScreenWindow {
5049 OrientedShell {
5150 implicitWidth: screenWindow.width
5251 implicitHeight: screenWindow.height
53− surfaceManager: screenWindow.surfaceManager
5452
5553 deviceConfiguration {
5654 name: Screens.count > 1 ? "desktop" : applicationArguments.deviceName
src/CMakeLists.txt+8−2
@@ -28,7 +28,7 @@ set(SOURCE_FILES
2828 ApplicationArguments.cpp
2929 main.cpp
3030 CachingNetworkManagerFactory.cpp
31− ShellApplication.cpp
31+ UnityApplication.cpp
3232 UnityCommandLineParser.cpp
3333 UnixSignalHandler.cpp
3434 DebuggingController.cpp
@@ -46,7 +46,13 @@ qt5_use_modules(${SHELL_APP} DBus Gui Qml Quick Test)
4646if (NOT "${ANDROID_PROPERTIES_INCLUDE_DIRS}" STREQUAL "")
4747 set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${ANDROID_PROPERTIES_INCLUDE_DIRS})
4848endif()
49−target_link_libraries(${SHELL_APP} ${ANDROID_PROPERTIES_LDFLAGS} UbuntuGestures connectivity-qt1 unity8-private qtmirserver)
49+target_link_libraries(${SHELL_APP}
50+ ${ANDROID_PROPERTIES_LDFLAGS}
51+ ${QTMIRSERVER_LDFLAGS}
52+ UbuntuGestures
53+ connectivity-qt1
54+ unity8-private
55+)
5056
5157if (ENABLE_TOUCH_EMULATION)
5258 target_link_libraries(${SHELL_APP} ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
src/ShellApplication.cpp → src/UnityApplication.cpprenamed+9−29
@@ -14,7 +14,7 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#include "ShellApplication.h"
17+#include "UnityApplication.h"
1818
1919// Qt
2020#include <QLibrary>
@@ -32,34 +32,14 @@
3232#include "CachingNetworkManagerFactory.h"
3333#include "UnityCommandLineParser.h"
3434#include "DebuggingController.h"
35+#include "windowmanagementpolicy.h"
3536
3637#include <QDebug>
3738
38−#include <qtmir/windowmanagementpolicy.h>
3939
40−class WindowManagementPolicy : public qtmir::WindowManagementPolicy
41−{
42−public:
43− WindowManagementPolicy(const miral::WindowManagerTools &tools, qtmir::WindowManagementPolicyPrivate& dd)
44− : qtmir::WindowManagementPolicy(tools, dd)
45− {}
46−
47−// virtual void advise_adding_to_workspace(
48−// std::shared_ptr<miral::Workspace> const& workspace,
49−// std::vector<miral::Window> const& windows) override
50−// {
51−// }
52−
53−// virtual void advise_removing_from_workspace(
54−// std::shared_ptr<miral::Workspace> const& workspace,
55−// std::vector<miral::Window> const& windows) override
56−// {
57−// }
58−};
59−
60−
61−ShellApplication::ShellApplication(int & argc, char ** argv)
62− : qtmir::MirServerApplication(argc, argv, {})
40+
41+UnityApplication::UnityApplication(int & argc, char ** argv)
42+ : qtmir::MirServerApplication(argc, argv, { qtmir::SetWindowManagementPolicy<WindowManagementPolicy>() })
6343 , m_qmlArgs(this)
6444{
6545 setApplicationName(QStringLiteral("unity8"));
@@ -103,7 +83,7 @@ ShellApplication::ShellApplication(int & argc, char ** argv)
10383 pxpgu = 8;
10484 }
10585 m_qmlEngine->rootContext()->setContextProperty("internalGu", pxpgu);
106− m_qmlEngine->load(::qmlDirectory() + "/ShellApplication.qml");
86+ m_qmlEngine->load(m_qmlArgs.qmlfie());
10787
10888 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
10989 // You will need this if you want to interact with touch-only components using a mouse
@@ -120,12 +100,12 @@ ShellApplication::ShellApplication(int & argc, char ** argv)
120100 }
121101}
122102
123−ShellApplication::~ShellApplication()
103+UnityApplication::~UnityApplication()
124104{
125105 destroyResources();
126106}
127107
128−void ShellApplication::destroyResources()
108+void UnityApplication::destroyResources()
129109{
130110 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
131111 delete m_mouseTouchAdaptor;
@@ -136,7 +116,7 @@ void ShellApplication::destroyResources()
136116 m_qmlEngine = nullptr;
137117}
138118
139−void ShellApplication::setupQmlEngine()
119+void UnityApplication::setupQmlEngine()
140120{
141121 m_qmlEngine = new QQmlApplicationEngine(this);
142122
src/ShellApplication.h → src/UnityApplication.hrenamed+6−6
@@ -14,8 +14,8 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#ifndef SHELLAPPLICATION_H
18−#define SHELLAPPLICATION_H
17+#ifndef UNITYAPPLICATION_H
18+#define UNITYAPPLICATION_H
1919
2020#include <QGuiApplication>
2121#include <QQmlApplicationEngine>
@@ -30,12 +30,12 @@
3030
3131#include <qtmir/mirserverapplication.h>
3232
33−class ShellApplication : public qtmir::MirServerApplication
33+class UnityApplication : public qtmir::MirServerApplication
3434{
3535 Q_OBJECT
3636public:
37− ShellApplication(int & argc, char ** argv);
38− virtual ~ShellApplication();
37+ UnityApplication(int & argc, char ** argv);
38+ virtual ~UnityApplication();
3939
4040 void destroyResources();
4141
@@ -50,4 +50,4 @@ private:
5050 QQmlApplicationEngine *m_qmlEngine{nullptr};
5151};
5252
53−#endif // SHELLAPPLICATION_H
53+#endif // UNITYAPPLICATION_H
src/UnityCommandLineParser.cpp+8
@@ -15,6 +15,7 @@
1515 */
1616
1717#include "UnityCommandLineParser.h"
18+#include <paths.h>
1819
1920#include <QDebug>
2021
@@ -60,6 +61,11 @@ UnityCommandLineParser::UnityCommandLineParser(const QCoreApplication &app)
6061 QStringLiteral("mode"), QStringLiteral("full-greeter"));
6162 parser.addOption(modeOption);
6263
64+ QCommandLineOption qmlfileOption(QStringLiteral("qmlfile"),
65+ QStringLiteral("The base qml file to load"),
66+ QStringLiteral("qmlfile"), ::qmlDirectory() + "/ShellApplication.qml");
67+ parser.addOption(qmlfileOption);
68+
6369 // Treat args with single dashes the same as arguments with two dashes
6470 // Ex: -fullscreen == --fullscreen
6571 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
@@ -85,6 +91,8 @@ UnityCommandLineParser::UnityCommandLineParser(const QCoreApplication &app)
8591 m_hasFullscreen = parser.isSet(fullscreenOption);
8692 m_deviceName = parser.value(devicenameOption);
8793 resolveMode(parser, modeOption);
94+
95+ m_qmlfile = parser.value(qmlfileOption);
8896}
8997
9098int UnityCommandLineParser::parsePixelsValue(const QString &str)
src/UnityCommandLineParser.h+3
@@ -37,6 +37,8 @@ public:
3737 QString deviceName() const { return m_deviceName; }
3838 QString mode() const { return m_mode; }
3939
40+ QString qmlfie() const { return m_qmlfile; }
41+
4042protected:
4143 int parsePixelsValue(const QString &str);
4244 static float getenvFloat(const char* name, float defaultValue);
@@ -55,6 +57,7 @@ protected:
5557 bool m_hasFullscreen;
5658 QString m_deviceName;
5759 QString m_mode;
60+ QString m_qmlfile;
5861};
5962
6063#endif // UNITY_COMMAND_LINE_PARSER_H
src/libunity8-private/CMakeLists.txt+10
@@ -4,16 +4,26 @@ set(VERSION ${SOVERSION}.0.0)
44
55project(lib${LIB_NAME})
66
7+include_directories(
8+ SYSTEM
9+ ${QTMIRSERVER_INCLUDE_DIRS}
10+)
11+
712set(lib${LIB_NAME}_SRCS
813 abstractdbusservicemonitor.cpp
914 unitydbusobject.cpp
1015 unitydbusvirtualobject.cpp
16+ windowmanagementpolicy.cpp
1117 )
1218
1319add_library(${LIB_NAME} SHARED
1420 ${lib${LIB_NAME}_SRCS}
1521 )
1622
23+target_link_libraries(${LIB_NAME}
24+ ${QTMIRSERVER_LDFLAGS}
25+ )
26+
1727set_target_properties(${LIB_NAME} PROPERTIES
1828 VERSION ${VERSION}
1929 SOVERSION ${SOVERSION}
src/libunity8-private/windowmanagementpolicy.cppnew file+86
@@ -0,0 +1,86 @@
1+/*
2+ * Copyright (C) 2017 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 "windowmanagementpolicy.h"
18+
19+#include <QDebug>
20+
21+WindowManagementPolicy* WindowManagementPolicy::m_self = nullptr;
22+
23+WindowManagementPolicy::WindowManagementPolicy(const miral::WindowManagerTools &tools, qtmir::WindowManagementPolicyPrivate &dd)
24+ : qtmir::WindowManagementPolicy(tools, dd)
25+ , m_dummyWorkspace(this->tools.create_workspace())
26+{
27+ m_self = this;
28+
29+ // we must always have a active workspace.
30+ m_activeWorkspace = m_dummyWorkspace;
31+}
32+
33+WindowManagementPolicy *WindowManagementPolicy::instance()
34+{
35+ return m_self;
36+}
37+
38+void WindowManagementPolicy::advise_new_window(miral::WindowInfo const& window_info)
39+{
40+ qtmir::WindowManagementPolicy::advise_new_window(window_info);
41+
42+ auto const parent = window_info.parent();
43+
44+ if (!parent && m_activeWorkspace)
45+ tools.add_tree_to_workspace(window_info.window(), m_activeWorkspace);
46+}
47+
48+std::shared_ptr<miral::Workspace> WindowManagementPolicy::createWorkspace()
49+{
50+ auto workspace = tools.create_workspace();
51+ m_workspaces.insert(workspace);
52+
53+ if (m_activeWorkspace == m_dummyWorkspace) {
54+ tools.move_workspace_content_to_workspace(workspace, m_dummyWorkspace);
55+ m_activeWorkspace = workspace;
56+ }
57+ return workspace;
58+}
59+
60+void WindowManagementPolicy::releaseWorkspace(const std::shared_ptr<miral::Workspace> &workspace)
61+{
62+ auto iter = m_workspaces.find(workspace);
63+ if (iter != m_workspaces.end()) m_workspaces.erase(iter);
64+
65+ if (m_workspaces.size() == 0) {
66+ m_activeWorkspace = m_dummyWorkspace;
67+ tools.move_workspace_content_to_workspace(m_dummyWorkspace, workspace);
68+ }
69+}
70+
71+void WindowManagementPolicy::forEachWindowInWorkspace(const std::shared_ptr<miral::Workspace> &workspace, const std::function<void (const miral::Window &)> &callback)
72+{
73+ tools.for_each_window_in_workspace(workspace, callback);
74+}
75+
76+void WindowManagementPolicy::moveWorkspaceContentToWorkspace(const std::shared_ptr<miral::Workspace> &toWorkspace, const std::shared_ptr<miral::Workspace> &fromWorkspace)
77+{
78+ tools.move_workspace_content_to_workspace(toWorkspace, fromWorkspace);
79+}
80+
81+void WindowManagementPolicy::setActiveWorkspace(const std::shared_ptr<miral::Workspace> &workspace)
82+{
83+ if (workspace == m_activeWorkspace)
84+ return;
85+ m_activeWorkspace = workspace ? workspace : m_dummyWorkspace;
86+}
src/libunity8-private/windowmanagementpolicy.hnew file+57
@@ -0,0 +1,57 @@
1+/*
2+ * Copyright (C) 2017 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 UNITY_WINDOWMANAGEMENTPOLICY_H
18+#define UNITY_WINDOWMANAGEMENTPOLICY_H
19+
20+#include <QObject>
21+#include <qtmir/windowmanagementpolicy.h>
22+
23+#include <unordered_set>
24+
25+class Q_DECL_EXPORT WindowManagementPolicy : public QObject,
26+ public qtmir::WindowManagementPolicy
27+{
28+ Q_OBJECT
29+public:
30+ WindowManagementPolicy(const miral::WindowManagerTools &tools, qtmir::WindowManagementPolicyPrivate& dd);
31+
32+ static WindowManagementPolicy *instance();
33+
34+ void advise_new_window(miral::WindowInfo const& window_info) override;
35+
36+ std::shared_ptr<miral::Workspace> createWorkspace();
37+ void releaseWorkspace(const std::shared_ptr<miral::Workspace> &workspace);
38+
39+ void forEachWindowInWorkspace(
40+ std::shared_ptr<miral::Workspace> const& workspace,
41+ std::function<void(miral::Window const& window)> const& callback);
42+
43+ void moveWorkspaceContentToWorkspace(const std::shared_ptr<miral::Workspace> &toWorkspace,
44+ const std::shared_ptr<miral::Workspace> &fromWorkspace);
45+
46+public Q_SLOTS:
47+ void setActiveWorkspace(const std::shared_ptr<miral::Workspace>& workspace);
48+
49+private:
50+ static WindowManagementPolicy* m_self;
51+ std::shared_ptr<miral::Workspace> m_activeWorkspace;
52+
53+ std::unordered_set<std::shared_ptr<miral::Workspace>> m_workspaces;
54+ const std::shared_ptr<miral::Workspace> m_dummyWorkspace;
55+};
56+
57+#endif // UNITY_WINDOWMANAGEMENTPOLICY_H
src/main.cpp+4−2
@@ -15,9 +15,10 @@
1515 */
1616
1717// local
18−#include "ShellApplication.h"
18+#include "UnityApplication.h"
1919#include "qmldebuggerutils.h"
2020#include "UnixSignalHandler.h"
21+#include <paths.h>
2122
2223#include <QTranslator>
2324#include <QLibraryInfo>
@@ -31,7 +32,8 @@ int main(int argc, const char *argv[])
3132 QQmlDebuggingEnabler qQmlEnableDebuggingHelper(true);
3233 }
3334
34− ShellApplication *application = new ShellApplication(argc, (char**)argv);
35+ auto *application = new UnityApplication(argc,
36+ (char**)argv);
3537
3638 UnixSignalHandler signalHandler([]{
3739 QGuiApplication::exit(0);
tests/mocks/Unity/Application/SurfaceManager.cpp+5
@@ -38,6 +38,11 @@ SurfaceManager *SurfaceManager::instance()
3838 return m_instance;
3939}
4040
41+MirSurfaceInterface *SurfaceManager::surfaceFor(const miral::Window&)
42+{
43+ return nullptr;
44+}
45+
4146SurfaceManager::SurfaceManager(QObject *)
4247{
4348 DEBUG_MSG("");
tests/mocks/Unity/Application/SurfaceManager.h+2
@@ -42,6 +42,8 @@ public:
4242
4343 static SurfaceManager *instance();
4444
45+ unity::shell::application::MirSurfaceInterface *surfaceFor(const miral::Window& window) override;
46+
4547 // SurfaceManagerInterface
4648 void raise(unity::shell::application::MirSurfaceInterface *surface) override;
4749 void activate(unity::shell::application::MirSurfaceInterface *surface) override;
tests/mocks/Unity/Application/plugin.cpp+7−1
@@ -38,6 +38,12 @@ QObject* mirSingleton(QQmlEngine*, QJSEngine*)
3838{
3939 return new MirMock;
4040}
41+
42+QObject* surfaceManagerSingleton(QQmlEngine*, QJSEngine*)
43+{
44+ return new SurfaceManager;
45+}
46+
4147} // anonymous namespace
4248
4349void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
@@ -59,7 +65,7 @@ void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
5965
6066 qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
6167 qmlRegisterSingletonType<MirMock>(uri, 0, 1, "Mir", mirSingleton);
62− qmlRegisterType<SurfaceManager>(uri, 0, 1, "SurfaceManager");
68+ qmlRegisterSingletonType<SurfaceManager>(uri, 0, 1, "SurfaceManager", surfaceManagerSingleton);
6369}
6470
6571void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
tests/mocks/WindowManager/CMakeLists.txt+11−7
@@ -1,22 +1,26 @@
11include_directories(
2− ${CMAKE_SOURCE_DIR}/plugins/WindowManager
2+ SYSTEM
3+ ${QTMIRSERVER_INCLUDE_DIRS}
34)
45
56include_directories(
6− SYSTEM
7− ${QTMIRSERVER_INCLUDE_DIRS}
7+ ${CMAKE_CURRENT_SOURCE_DIR}
8+ ${CMAKE_CURRENT_BINARY_DIR}
9+ ${CMAKE_SOURCE_DIR}/plugins/WindowManager
810)
911
1012set(WINDOWMANAGER_SRC
13+ ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Screen.cpp
14+ ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Screens.cpp
1115 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/TopLevelWindowModel.cpp
1216 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Window.cpp
13− ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Workspace.cpp
1417 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/WorkspaceManager.cpp
1518 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/WorkspaceModel.cpp
16− WindowManagerPlugin.cpp
17− Screens.cpp
18− Screen.cpp
19+ ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Workspace.cpp
20+ MockScreens.cpp
1921 ScreenWindow.cpp
22+ WindowManagerPlugin.cpp
23+ windowmanagementpolicy.h
2024 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
2125 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
2226 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
tests/mocks/WindowManager/MockScreens.cppnew file+140
@@ -0,0 +1,140 @@
1+/*
2+ * Copyright (C) 2016-2017 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 "MockScreens.h"
18+
19+// qtmirserver
20+#include <qtmir/screen.h>
21+
22+namespace {
23+
24+class MockScreen : public qtmir::Screen
25+{
26+ Q_OBJECT
27+public:
28+ MockScreen()
29+ {
30+ m_sizes.append(new qtmir::ScreenMode(50, QSize(640,480)));
31+ m_sizes.append(new qtmir::ScreenMode(60, QSize(1280,1024)));
32+ m_sizes.append(new qtmir::ScreenMode(60, QSize(1440,900)));
33+ m_sizes.append(new qtmir::ScreenMode(60, QSize(1920,1080)));
34+ m_physicalSize = QSize(800,568);
35+ }
36+
37+ qtmir::OutputId outputId() const override { return m_id; }
38+ bool used() const override { return m_used; }
39+ QString name() const override { return m_name; }
40+ float scale() const override { return m_scale; }
41+ QSizeF physicalSize() const override { return m_physicalSize; }
42+ qtmir::FormFactor formFactor() const override { return m_formFactor; }
43+ qtmir::OutputTypes outputType() const override { return m_outputType; }
44+ MirPowerMode powerMode() const override { return m_powerMode; }
45+ Qt::ScreenOrientation orientation() const override { return m_orientation; }
46+ QPoint position() const override { return m_position; }
47+ uint currentModeIndex() const override { return m_currentModeIndex; }
48+ bool isActive() const override { return m_active; }
49+
50+ QQmlListProperty<qtmir::ScreenMode> availableModes() override {
51+ return QQmlListProperty<qtmir::ScreenMode>(this, m_sizes);
52+ }
53+
54+ void setActive(bool active) override {
55+ if (m_active != active) {
56+ m_active = active;
57+ Q_EMIT activeChanged(m_active);
58+ }
59+ }
60+
61+ QScreen* qscreen() const override { return nullptr; }
62+
63+ qtmir::ScreenConfiguration *beginConfiguration() const override {
64+ auto config = new qtmir::ScreenConfiguration;
65+ config->valid = true;
66+ config->id = m_id;
67+ config->used = m_used;
68+ config->topLeft = m_position;
69+ config->currentModeIndex = m_currentModeIndex;
70+ config->powerMode = m_powerMode;
71+ config->scale = m_scale;
72+ config->formFactor = m_formFactor;
73+ return config;
74+ }
75+
76+ bool applyConfiguration(qtmir::ScreenConfiguration *configuration) override {
77+ m_used = configuration->used;
78+ m_position = configuration->topLeft;
79+ m_currentModeIndex = configuration->currentModeIndex;
80+ m_powerMode = configuration->powerMode;
81+ m_scale = configuration->scale;
82+ m_formFactor = configuration->formFactor;
83+ return true;
84+ }
85+
86+public:
87+ qtmir::OutputId m_id{0};
88+ bool m_active{false};
89+ bool m_used{true};
90+ QString m_name;
91+ qtmir::OutputTypes m_outputType{qtmir::Unknown};
92+ MirPowerMode m_powerMode{mir_power_mode_on};
93+ Qt::ScreenOrientation m_orientation{Qt::PrimaryOrientation};
94+ float m_scale{1.0};
95+ qtmir::FormFactor m_formFactor{qtmir::FormFactorMonitor};
96+ QPoint m_position;
97+ uint m_currentModeIndex{0};
98+ QList<qtmir::ScreenMode*> m_sizes;
99+ QSizeF m_physicalSize;
100+};
101+}
102+
103+MockScreens::MockScreens()
104+{
105+ bool ok = false;
106+ int screenCount = qEnvironmentVariableIntValue("UNITY_MOCK_SCREEN_COUNT", &ok);
107+ if (!ok) screenCount = 1;
108+ QPoint lastPoint(0,0);
109+ for (int i = 0; i < screenCount; ++i) {
110+ auto screen = new MockScreen();
111+ screen->m_id = qtmir::OutputId{i};
112+ screen->m_active = i == 0;
113+ screen->m_name = QString("Monitor %1").arg(i);
114+ screen->m_position = QPoint(lastPoint.x(), lastPoint.y());
115+ screen->m_currentModeIndex = 3;
116+ m_mocks.append(screen);
117+
118+ lastPoint.rx() += screen->m_sizes[screen->m_currentModeIndex]->size.width();
119+ }
120+}
121+
122+MockScreens::~MockScreens()
123+{
124+ qDeleteAll(m_mocks);
125+}
126+
127+QVector<qtmir::Screen *> MockScreens::screens() const
128+{
129+ return m_mocks;
130+}
131+
132+qtmir::Screen *MockScreens::activeScreen() const
133+{
134+ Q_FOREACH(auto screen, m_mocks) {
135+ if (screen->isActive()) return screen;
136+ }
137+ return nullptr;
138+}
139+
140+#include "MockScreens.moc"
tests/mocks/WindowManager/MockScreens.hnew file+46
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright (C) 2016 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 MOCK_SCREENS_H
18+#define MOCK_SCREENS_H
19+
20+#include <QAbstractListModel>
21+#include <QSharedPointer>
22+
23+#include <qtmir/screens.h>
24+
25+class Screen;
26+namespace qtmir
27+{
28+class Screens;
29+}
30+
31+class MockScreens : public qtmir::Screens
32+{
33+ Q_OBJECT
34+public:
35+ MockScreens();
36+ ~MockScreens();
37+
38+ QVector<qtmir::Screen*> screens() const override;
39+
40+ qtmir::Screen *activeScreen() const override;
41+
42+private:
43+ QVector<qtmir::Screen*> m_mocks;
44+};
45+
46+#endif // MOCK_SCREENS_H
tests/mocks/WindowManager/Screen.cppdeleted−65
@@ -1,65 +0,0 @@
1−/*
2− * Copyright (C) 2017 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 "Screen.h"
18−#include "WorkspaceModel.h"
19−#include "WorkspaceManager.h"
20−#include "Workspace.h"
21−
22−Screen::Screen()
23− : m_workspaces(new WorkspaceModel)
24−{
25− WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
26− WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
27−}
28−
29−QQmlListProperty<qtmir::ScreenMode> Screen::availableModes()
30−{
31− return QQmlListProperty<qtmir::ScreenMode>(this, m_sizes);
32−}
33−
34−qtmir::ScreenConfiguration *Screen::beginConfiguration() const
35−{
36− auto config = new qtmir::ScreenConfiguration;
37− config->valid = true;
38− config->id = m_id;
39− config->used = m_used;
40− config->topLeft = m_position;
41− config->currentModeIndex = m_currentModeIndex;
42− config->powerMode = m_powerMode;
43− config->scale = m_scale;
44− config->formFactor = m_formFactor;
45− return config;
46−}
47−
48−bool Screen::applyConfiguration(qtmir::ScreenConfiguration *configuration)
49−{
50− m_used = configuration->used;
51− m_position = configuration->topLeft;
52− m_currentModeIndex = configuration->currentModeIndex;
53− m_powerMode = configuration->powerMode;
54− m_scale = configuration->scale;
55− m_formFactor = configuration->formFactor;
56−
57−// m_orientation = configuration->orientation;
58− return true;
59−}
60−
61−void Screen::setActive(bool active)
62−{
63− m_active = active;
64− Q_EMIT activeChanged(active);
65−}
tests/mocks/WindowManager/Screen.hdeleted−56
@@ -1,56 +0,0 @@
1−#ifndef MOCK_SCREEN_H
2−#define MOCK_SCREEN_H
3−
4−#include <qtmir/screen.h>
5−#include <QScopedPointer>
6−
7−class WorkspaceModel;
8−
9−class Screen : public qtmir::Screen
10−{
11− Q_OBJECT
12− Q_PROPERTY(WorkspaceModel* workspaces READ workspaces CONSTANT)
13−
14−public:
15− Screen();
16−
17− qtmir::OutputId outputId() const override { return m_id; }
18− bool used() const override { return m_used; }
19− QString name() const override { return m_name; }
20− float scale() const override { return m_scale; }
21− QSizeF physicalSize() const override { return m_physicalSize; }
22− qtmir::FormFactor formFactor() const override { return m_formFactor; }
23− qtmir::OutputTypes outputType() const override { return m_outputType; }
24− MirPowerMode powerMode() const override { return m_powerMode; }
25− Qt::ScreenOrientation orientation() const override { return m_orientation; }
26− QPoint position() const override { return m_position; }
27− QQmlListProperty<qtmir::ScreenMode> availableModes() override;
28− uint currentModeIndex() const override { return m_currentModeIndex; }
29− bool isActive() const override { return m_active; }
30− void setActive(bool active) override;
31−
32− QScreen* qscreen() const override { return nullptr; }
33−
34− qtmir::ScreenConfiguration *beginConfiguration() const override;
35− bool applyConfiguration(qtmir::ScreenConfiguration *configuration) override;
36−
37− WorkspaceModel* workspaces() const { return m_workspaces.data(); }
38−
39−public:
40− qtmir::OutputId m_id{0};
41− bool m_active{false};
42− bool m_used{true};
43− QString m_name;
44− qtmir::OutputTypes m_outputType{qtmir::Unknown};
45− MirPowerMode m_powerMode{mir_power_mode_on};
46− Qt::ScreenOrientation m_orientation{Qt::PrimaryOrientation};
47− float m_scale{1.0};
48− qtmir::FormFactor m_formFactor{qtmir::FormFactorMonitor};
49− QPoint m_position;
50− uint m_currentModeIndex{0};
51− QList<qtmir::ScreenMode*> m_sizes;
52− QSizeF m_physicalSize;
53− const QScopedPointer<WorkspaceModel> m_workspaces;
54−};
55−
56−#endif // MOCK_SCREEN_H
tests/mocks/WindowManager/Screens.cppdeleted−101
@@ -1,101 +0,0 @@
1−/*
2− * Copyright (C) 2016-2017 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 "Screens.h"
18−#include "Screen.h"
19−
20−// qtmirserver
21−#include <qtmir/qtmir.h>
22−#include <qtmir/screens.h>
23−#include <QGuiApplication>
24−
25−// Qt
26−#include <QScreen>
27−#include <QWindow>
28−
29−Screens::Screens(QObject *parent)
30− : QAbstractListModel(parent)
31−{
32− bool ok = false;
33− int screenCount = qEnvironmentVariableIntValue("UNITY_MOCK_SCREEN_COUNT", &ok);
34− if (!ok) screenCount = 1;
35− QPoint lastPoint(0,0);
36− for (int i = 0; i < screenCount; ++i) {
37− auto screen = new Screen();
38− screen->m_id = qtmir::OutputId{i};
39− screen->m_active = i == 0;
40− screen->m_name = QString("Monitor %1").arg(i);
41− screen->m_position = QPoint(lastPoint.x(), lastPoint.y());
42− screen->m_sizes.append(new qtmir::ScreenMode(50, QSize(640,480)));
43− screen->m_sizes.append(new qtmir::ScreenMode(60, QSize(1280,1024)));
44− screen->m_sizes.append(new qtmir::ScreenMode(60, QSize(1440,900)));
45− screen->m_sizes.append(new qtmir::ScreenMode(60, QSize(1920,1080)));
46− screen->m_currentModeIndex = 3;
47− screen->m_physicalSize = QSize(800,568);
48− m_screenList.append(screen);
49−
50− lastPoint.rx() += screen->m_sizes[screen->m_currentModeIndex]->size.width();
51− }
52−}
53−
54−QHash<int, QByteArray> Screens::roleNames() const
55−{
56− QHash<int, QByteArray> roles;
57− roles[ScreenRole] = "screen";
58− return roles;
59−}
60−
61−QVariant Screens::data(const QModelIndex &index, int role) const
62−{
63− if (!index.isValid() || index.row() >= m_screenList.size()) {
64− return QVariant();
65− }
66−
67− switch(role) {
68− case ScreenRole:
69− return QVariant::fromValue(m_screenList.at(index.row()));
70− } // switch
71−
72− return QVariant();
73−}
74−
75−int Screens::rowCount(const QModelIndex &) const
76−{
77− return count();
78−}
79−
80−int Screens::count() const
81−{
82− return m_screenList.size();
83−}
84−
85−QVariant Screens::activeScreen() const
86−{
87− for (int i = 0; i < m_screenList.count(); i++) {
88− if (m_screenList[i]->isActive()) return i;
89− }
90− return QVariant();
91−}
92−
93−void Screens::activateScreen(const QVariant& vindex)
94−{
95− bool ok = false;
96− int index = vindex.toInt(&ok);
97− if (!ok || index < 0 || m_screenList.count() <= index) return;
98−
99− auto screen = m_screenList.at(index);
100− screen->setActive(true);
101−}
tests/mocks/WindowManager/Screens.hdeleted−65
@@ -1,65 +0,0 @@
1−/*
2− * Copyright (C) 2016 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 UNITY_SCREENS_H
18−#define UNITY_SCREENS_H
19−
20−#include <QAbstractListModel>
21−#include <QSharedPointer>
22−
23−class Screen;
24−namespace qtmir
25−{
26−class Screens;
27−}
28−
29−class Screens : public QAbstractListModel
30−{
31− Q_OBJECT
32− Q_PROPERTY(int count READ count NOTIFY countChanged)
33− Q_PROPERTY(QVariant activeScreen READ activeScreen WRITE activateScreen NOTIFY activeScreenChanged)
34−
35−public:
36− enum ItemRoles {
37− ScreenRole = Qt::UserRole + 1
38− };
39−
40− explicit Screens(QObject *parent = 0);
41− virtual ~Screens() noexcept = default;
42−
43− /* QAbstractItemModel */
44− QHash<int, QByteArray> roleNames() const override;
45− QVariant data(const QModelIndex &index, int role = ScreenRole) const override;
46− int rowCount(const QModelIndex &parent = QModelIndex()) const override;
47−
48− int count() const;
49− QVariant activeScreen() const;
50−
51−public Q_SLOTS:
52− void activateScreen(const QVariant& index);
53−
54−Q_SIGNALS:
55− void countChanged();
56− void activeScreenChanged();
57−
58− void screenAdded(Screen* screen);
59− void screenRemoved(Screen* screen);
60−
61−private:
62− QList<Screen*> m_screenList;
63−};
64−
65−#endif // SCREENS_H
tests/mocks/WindowManager/WindowManagerPlugin.cpp+7−3
@@ -18,6 +18,7 @@
1818
1919#include "Screens.h"
2020#include "Screen.h"
21+#include "MockScreens.h"
2122#include "ScreenWindow.h"
2223#include "TopLevelWindowModel.h"
2324#include "Window.h"
@@ -36,7 +37,8 @@ static QObject *workspace_manager(QQmlEngine *engine, QJSEngine *scriptEngine)
3637QObject* screensSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
3738 Q_UNUSED(engine);
3839 Q_UNUSED(scriptEngine);
39− return new Screens();
40+ QSharedPointer<qtmir::Screens> mockScreens(new MockScreens());
41+ return new Screens(mockScreens);
4042}
4143
4244void WindowManagerPlugin::registerTypes(const char *uri)
@@ -46,12 +48,14 @@ void WindowManagerPlugin::registerTypes(const char *uri)
4648 qmlRegisterUncreatableType<WorkspaceModel>(uri, 1, 0, "WorkspaceModel", "Not a creatable type");
4749 qmlRegisterSingletonType<Screens>(uri, 1, 0, "Screens", screensSingleton);
4850 qmlRegisterUncreatableType<qtmir::ScreenMode>(uri, 1, 0, "ScreenMode", "ScreenMode is not creatable.");
51+ qmlRegisterUncreatableType<Workspace>(uri, 1, 0, "Workspace", "Workspace is not creatable.");
4952
50− qRegisterMetaType<Window*>("Window*");
53+ qRegisterMetaType<Screen*>("Screen*");
54+ qRegisterMetaType<ScreensProxy*>("ScreensProxy*");
5155 qRegisterMetaType<Workspace*>("Workspace*");
5256
57+ qRegisterMetaType<Window*>("Window*");
5358 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
54− qRegisterMetaType<Screen*>("Screen*");
5559
5660 qmlRegisterType<ScreenWindow>(uri, 1, 0, "ScreenWindow");
5761 qmlRegisterRevision<QWindow,1>(uri, 1, 0);
tests/mocks/WindowManager/windowmanagementpolicy.hnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright (C) 2017 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 MOCKWINDOMANAGEMENTPOLICY_H
18+#define MOCKWINDOMANAGEMENTPOLICY_H
19+
20+#include <QObject>
21+
22+namespace miral {
23+class Window;
24+class Workspace {};
25+}
26+
27+// A Fake window management policy for the mock.
28+class WindowManagementPolicy : public QObject
29+{
30+ Q_OBJECT
31+public:
32+ WindowManagementPolicy() {}
33+
34+ static WindowManagementPolicy *instance() {
35+ static WindowManagementPolicy* inst(new WindowManagementPolicy());
36+ return inst;
37+ }
38+
39+ std::shared_ptr<miral::Workspace> createWorkspace() { return std::make_shared<miral::Workspace>(); }
40+ void releaseWorkspace(const std::shared_ptr<miral::Workspace>&) {}
41+
42+ void forEachWindowInWorkspace(
43+ std::shared_ptr<miral::Workspace> const&,
44+ std::function<void(miral::Window const&)> const&) {}
45+
46+ void moveWorkspaceContentToWorkspace(const std::shared_ptr<miral::Workspace>&,
47+ const std::shared_ptr<miral::Workspace>&)
48+ {}
49+
50+public Q_SLOTS:
51+ void setActiveWorkspace(const std::shared_ptr<miral::Workspace>&) {}
52+};
53+
54+#endif // UNITY_WINDOWMANAGEMENTPOLICY_H
tests/qmltests/ApplicationMenuDataLoader.qml+1−4
@@ -6,11 +6,8 @@ import Unity.Indicators 0.1 as Indicators
66
77Object {
88
9− property alias surfaceManager: sMgrHandler.target
10−
119 Connections {
12− id: sMgrHandler
13− target: null
10+ target: SurfaceManager
1411 onSurfaceCreated: {
1512 var fakeMenuPath = "/" + surface.persistentId.replace(/\W+/g, "");
1613
tests/qmltests/ApplicationMenus/tst_MenuBar.qml−2
@@ -42,10 +42,8 @@ Item {
4242 value: false
4343 }
4444
45− SurfaceManager { id: sMgr }
4645 ApplicationMenuDataLoader {
4746 id: appMenuData
48− surfaceManager: sMgr
4947 }
5048
5149 Rectangle {
tests/qmltests/Panel/tst_ActiveCallHint.qml−2
@@ -41,8 +41,6 @@ Item {
4141 elapsedTimerRunning: true
4242 }
4343
44− SurfaceManager {}
45−
4644 ActiveCallHint {
4745 id: callHint
4846 anchors {
tests/qmltests/Panel/tst_Panel.qml−2
@@ -44,10 +44,8 @@ PanelTest {
4444
4545 readonly property alias panelState: panel.panelState
4646
47− SurfaceManager { id: sMgr }
4847 ApplicationMenuDataLoader {
4948 id: appMenuData
50− surfaceManager: sMgr
5149 }
5250
5351 Component.onCompleted: {
tests/qmltests/Stage/tst_ApplicationWindow.qml−2
@@ -37,8 +37,6 @@ Rectangle {
3737 }
3838 property QtObject fakeApplication: null
3939
40− SurfaceManager{}
41−
4240 Loader {
4341 id: applicationWindowLoader
4442 focus: true
tests/qmltests/Stage/tst_DecoratedWindow.qml−2
@@ -46,10 +46,8 @@ Rectangle {
4646 value: false
4747 }
4848
49− SurfaceManager { id: sMgr }
5049 ApplicationMenuDataLoader {
5150 id: appMenuData
52− surfaceManager: sMgr
5351 }
5452
5553 PanelState {
tests/qmltests/Stage/tst_DesktopStage.qml+1−3
@@ -67,16 +67,14 @@ Item {
6767 }
6868 }
6969
70− SurfaceManager { id: sMgr }
7170 ApplicationMenuDataLoader {
7271 id: appMenuData
73− surfaceManager: sMgr
7472 }
7573
7674 TopLevelWindowModel {
7775 id: topSurfaceList
7876 applicationManager: ApplicationManager
79− surfaceManager: sMgr
77+ surfaceManager: SurfaceManager
8078 }
8179
8280 Loader {
tests/qmltests/Stage/tst_PhoneStage.qml+1−3
@@ -31,10 +31,8 @@ Item {
3131
3232 property var greeter: { fullyShown: true }
3333
34− SurfaceManager { id: sMgr }
3534 ApplicationMenuDataLoader {
3635 id: appMenuData
37− surfaceManager: sMgr
3836 }
3937
4038 Stage {
@@ -50,7 +48,7 @@ Item {
5048 topLevelSurfaceList: TopLevelWindowModel {
5149 id: topLevelSurfaceList
5250 applicationManager: ApplicationManager
53− surfaceManager: sMgr
51+ surfaceManager: SurfaceManager
5452 }
5553 Component.onCompleted: {
5654 ApplicationManager.startApplication("unity8-dash");
tests/qmltests/Stage/tst_SurfaceContainer.qml−2
@@ -51,8 +51,6 @@ Rectangle {
5151 }
5252 }
5353
54− SurfaceManager {}
55−
5654 Loader {
5755 id: surfaceContainerLoader
5856 focus: true
tests/qmltests/Stage/tst_TabletStage.qml+1−3
@@ -35,10 +35,8 @@ Rectangle {
3535
3636 property var greeter: { fullyShown: true }
3737
38− SurfaceManager { id: sMgr }
3938 ApplicationMenuDataLoader {
4039 id: appMenuData
41− surfaceManager: sMgr
4240 }
4341
4442 Stage {
@@ -59,7 +57,7 @@ Rectangle {
5957 topLevelSurfaceList: TopLevelWindowModel {
6058 id: topLevelSurfaceList
6159 applicationManager: ApplicationManager
62− surfaceManager: sMgr
60+ surfaceManager: SurfaceManager
6361 }
6462 Component.onCompleted: {
6563 ApplicationManager.startApplication("unity8-dash");
tests/qmltests/Stage/tst_WindowDecoration.qml−2
@@ -47,10 +47,8 @@ Item {
4747 property string name: "webbrowser"
4848 }
4949
50− SurfaceManager { id: sMgr }
5150 ApplicationMenuDataLoader {
5251 id: appMenuData
53− surfaceManager: sMgr
5452 }
5553
5654 UnityMenuModel {
tests/qmltests/Tutorial/tst_Tutorial.qml+1−3
@@ -326,9 +326,7 @@ Rectangle {
326326 }
327327
328328 function ensureInputMethodSurface() {
329− var surfaceManager = findInvisibleChild(shell, "surfaceManager");
330− verify(surfaceManager);
331− surfaceManager.createInputMethodSurface();
329+ SurfaceManager.createInputMethodSurface();
332330
333331 tryCompareFunction(function() { return topLevelSurfaceList.inputMethodSurface !== null }, true);
334332 }
tests/qmltests/tst_OrientedShell.qml−5
@@ -179,11 +179,6 @@ Rectangle {
179179 Component.onDestruction: {
180180 orientedShellLoader.itemDestroyed = true;
181181 }
182−
183− SurfaceManager {
184− id: surfaceMan
185− }
186− surfaceManager: surfaceMan
187182 }
188183 }
189184 }
tests/qmltests/tst_Shell.qml+1−10
@@ -61,11 +61,9 @@ Rectangle {
6161 onShellChanged: {
6262 if (shell) {
6363 topLevelSurfaceList = testCase.findInvisibleChild(shell, "topLevelSurfaceList");
64− appMenuData.surfaceManager = testCase.findInvisibleChild(shell, "surfaceManager");
6564 panelState = testCase.findInvisibleChild(shell, "panelState");
6665 } else {
6766 topLevelSurfaceList = null;
68− appMenuData.surfaceManager = null;
6967 panelState = undefined;
7068 }
7169 }
@@ -152,11 +150,6 @@ Rectangle {
152150 Component.onDestruction: {
153151 shellLoader.itemDestroyed = true;
154152 }
155−
156− SurfaceManager {
157− id: surfaceMan
158− }
159− surfaceManager: surfaceMan
160153 }
161154 }
162155 }
@@ -696,9 +689,7 @@ Rectangle {
696689 }
697690
698691 function ensureInputMethodSurface() {
699− var surfaceManager = shell.surfaceManager;
700− verify(surfaceManager);
701− surfaceManager.createInputMethodSurface();
692+ SurfaceManager.createInputMethodSurface();
702693
703694 tryCompareFunction(function() { return root.topLevelSurfaceList.inputMethodSurface !== null }, true);
704695 }