on xenial help sign in
merge prereq
781c37dMichael Zanetti
debian/control+1−1
@@ -31,6 +31,7 @@ Build-Depends: cmake,
31 libqmenumodel-dev (>= 0.2.11),
31 libqmenumodel-dev (>= 0.2.11),
32 libqt5svg5-dev,
32 libqt5svg5-dev,
33 libqt5xmlpatterns5-dev,
33 libqt5xmlpatterns5-dev,
34+ libqtmirserver-dev (>= 0.6.0),
34 libsystemsettings-dev,
35 libsystemsettings-dev,
35 libubuntu-app-launch2-dev,
36 libubuntu-app-launch2-dev,
36 libubuntu-download-manager-common-dev,
37 libubuntu-download-manager-common-dev,
@@ -68,7 +69,6 @@ Build-Depends: cmake,
68 qtdeclarative5-private-dev (>= 5.6),
69 qtdeclarative5-private-dev (>= 5.6),
69 qtdeclarative5-ubuntu-content1,
70 qtdeclarative5-ubuntu-content1,
70 qtdeclarative5-ubuntu-settings-components (>= 0.11),
71 qtdeclarative5-ubuntu-settings-components (>= 0.11),
71− qtmir-dev (>= 0.6.0),
72 ttf-ubuntu-font-family,
72 ttf-ubuntu-font-family,
73 xvfb,
73 xvfb,
74Standards-Version: 3.9.4
74Standards-Version: 3.9.4
plugins/WindowManager/CMakeLists.txt+6
@@ -3,6 +3,11 @@ include_directories(
3 ${QTMIRSERVER_INCLUDE_DIRS}
3 ${QTMIRSERVER_INCLUDE_DIRS}
4)
4)
5
5
6+include_directories(
7+ ${CMAKE_CURRENT_SOURCE_DIR}
8+ ${libunity8-private_SOURCE_DIR}
9+)
10+
6set(WINDOWMANAGER_SRC
11set(WINDOWMANAGER_SRC
7 TopLevelWindowModel.cpp
12 TopLevelWindowModel.cpp
8 Window.cpp
13 Window.cpp
@@ -24,6 +29,7 @@ add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
24
29
25target_link_libraries(windowmanager-qml
30target_link_libraries(windowmanager-qml
26 ${QTMIRSERVER_LDFLAGS}
31 ${QTMIRSERVER_LDFLAGS}
32+ unity8-private
27)
33)
28
34
29qt5_use_modules(windowmanager-qml Qml Quick Gui)
35qt5_use_modules(windowmanager-qml Qml Quick Gui)
plugins/WindowManager/Screen.cpp+56−1
@@ -15,7 +15,6 @@
15 */
15 */
16
16
17#include "Screen.h"
17#include "Screen.h"
18−#include "WorkspaceModel.h"
19#include "WorkspaceManager.h"
18#include "WorkspaceManager.h"
20#include "Workspace.h"
19#include "Workspace.h"
21
20
@@ -34,10 +33,38 @@ Screen::Screen(qtmir::Screen* screen)
34 connect(m_wrapped, &qtmir::Screen::currentModeIndexChanged, this, &Screen::currentModeIndexChanged);
33 connect(m_wrapped, &qtmir::Screen::currentModeIndexChanged, this, &Screen::currentModeIndexChanged);
35 connect(m_wrapped, &qtmir::Screen::availableModesChanged, this, &Screen::availableModesChanged);
34 connect(m_wrapped, &qtmir::Screen::availableModesChanged, this, &Screen::availableModesChanged);
36
35
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+
37 WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
47 WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
38 WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
48 WorkspaceManager::instance()->createWorkspace()->assign(m_workspaces.data());
39}
49}
40
50
51+Screen::Screen(const Screen &other)
52+ : qtmir::Screen(nullptr)
53+ , m_wrapped(other.m_wrapped)
54+ , m_workspaces(new WorkspaceModelProxy(other.m_workspaces.data()))
55+{
56+ connect(m_wrapped, &qtmir::Screen::usedChanged, this, &Screen::usedChanged);
57+ connect(m_wrapped, &qtmir::Screen::nameChanged, this, &Screen::nameChanged);
58+ connect(m_wrapped, &qtmir::Screen::outputTypeChanged, this, &Screen::outputTypeChanged);
59+ connect(m_wrapped, &qtmir::Screen::scaleChanged, this, &Screen::scaleChanged);
60+ connect(m_wrapped, &qtmir::Screen::formFactorChanged, this, &Screen::formFactorChanged);
61+ connect(m_wrapped, &qtmir::Screen::physicalSizeChanged, this, &Screen::physicalSizeChanged);
62+ connect(m_wrapped, &qtmir::Screen::positionChanged, this, &Screen::positionChanged);
63+ connect(m_wrapped, &qtmir::Screen::activeChanged, this, &Screen::activeChanged);
64+ connect(m_wrapped, &qtmir::Screen::currentModeIndexChanged, this, &Screen::currentModeIndexChanged);
65+ connect(m_wrapped, &qtmir::Screen::availableModesChanged, this, &Screen::availableModesChanged);
66+}
67+
41qtmir::OutputId Screen::outputId() const
68qtmir::OutputId Screen::outputId() const
42{
69{
43 return m_wrapped->outputId();
70 return m_wrapped->outputId();
@@ -113,6 +140,23 @@ bool Screen::applyConfiguration(qtmir::ScreenConfiguration *configuration)
113 return m_wrapped->applyConfiguration(configuration);
140 return m_wrapped->applyConfiguration(configuration);
114}
141}
115
142
143+WorkspaceModel *Screen::workspaces() const
144+{
145+ return m_workspaces.data();
146+}
147+
148+void Screen::sync(Screen *proxy)
149+{
150+ if (!proxy) return;
151+
152+ workspaces()->sync(proxy->workspaces());
153+}
154+
155+void Screen::activate()
156+{
157+ setActive(true);
158+}
159+
116void Screen::setActive(bool active)
160void Screen::setActive(bool active)
117{
161{
118 m_wrapped->setActive(active);
162 m_wrapped->setActive(active);
@@ -122,3 +166,14 @@ QScreen *Screen::qscreen() const
122{
166{
123 return m_wrapped->qscreen();
167 return m_wrapped->qscreen();
124}
168}
169+
170+ScreenProxy::ScreenProxy(ScreenProxy::Screen *const screen)
171+ : Screen(*screen)
172+ , m_original(screen)
173+{
174+}
175+
176+void ScreenProxy::addWorkspace()
177+{
178+ (new WorkspaceProxy(WorkspaceManager::instance()->createWorkspace()))->assign(workspaces());
179+}
plugins/WindowManager/Screen.h+28−3
@@ -3,8 +3,11 @@
3
3
4#include <qtmir/screen.h>
4#include <qtmir/screen.h>
5#include <QScopedPointer>
5#include <QScopedPointer>
6+#include <QPointer>
6
7
7−class WorkspaceModel;
8+#include "WorkspaceModel.h"
9+
10+class ScreenProxy;
8
11
9class Screen : public qtmir::Screen
12class Screen : public qtmir::Screen
10{
13{
@@ -36,11 +39,33 @@ public:
36
39
37 qtmir::Screen* wrapped() const { return m_wrapped; }
40 qtmir::Screen* wrapped() const { return m_wrapped; }
38
41
39− WorkspaceModel* workspaces() const { return m_workspaces.data(); }
42+ WorkspaceModel* workspaces() const;
43+
44+ void sync(Screen* proxy);
45+
46+public Q_SLOTS:
47+ void activate();
48+
49+protected:
50+ Screen(Screen const& other);
40
51
41−private:
42 qtmir::Screen*const m_wrapped;
52 qtmir::Screen*const m_wrapped;
43 const QScopedPointer<WorkspaceModel> m_workspaces;
53 const QScopedPointer<WorkspaceModel> m_workspaces;
44};
54};
45
55
56+class ScreenProxy : public Screen
57+{
58+ Q_OBJECT
59+public:
60+ explicit ScreenProxy(Screen*const screen);
61+
62+ Screen* proxyObject() const { return m_original.data(); }
63+
64+public Q_SLOTS:
65+ void addWorkspace();
66+
67+private:
68+ const QPointer<Screen> m_original;
69+};
70+
46#endif // SCREEN_H
71#endif // SCREEN_H
plugins/WindowManager/Screens.cpp+94−21
@@ -16,9 +16,9 @@
16
16
17#include "Screens.h"
17#include "Screens.h"
18#include "Screen.h"
18#include "Screen.h"
19+#include "WorkspaceManager.h"
19
20
20// qtmirserver
21// qtmirserver
21−#include <qtmir/qtmir.h>
22#include <qtmir/screens.h>
22#include <qtmir/screens.h>
23#include <QGuiApplication>
23#include <QGuiApplication>
24
24
@@ -26,9 +26,8 @@
26#include <QScreen>
26#include <QScreen>
27#include <QWindow>
27#include <QWindow>
28
28
29−Screens::Screens(QObject *parent)
29+Screens::Screens(const QSharedPointer<qtmir::Screens>& model)
30− : QAbstractListModel(parent)
31− , m_wrapped(qtmir::get_screen_model())
30+ : m_wrapped(model)
32{
31{
33 if (qGuiApp->platformName() != QLatin1String("mirserver")) {
32 if (qGuiApp->platformName() != QLatin1String("mirserver")) {
34 qCritical("Not using 'mirserver' QPA plugin. Using qGuiApp may produce unknown results.");
33 qCritical("Not using 'mirserver' QPA plugin. Using qGuiApp may produce unknown results.");
@@ -36,13 +35,25 @@ Screens::Screens(QObject *parent)
36
35
37 connect(m_wrapped.data(), &qtmir::Screens::screenAdded, this, &Screens::onScreenAdded);
36 connect(m_wrapped.data(), &qtmir::Screens::screenAdded, this, &Screens::onScreenAdded);
38 connect(m_wrapped.data(), &qtmir::Screens::screenRemoved, this, &Screens::onScreenRemoved);
37 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);
40
39
41 Q_FOREACH(qtmir::Screen* screen, m_wrapped->screens()) {
40 Q_FOREACH(qtmir::Screen* screen, m_wrapped->screens()) {
42− m_screenList.push_back(new Screen(screen));
41+ m_screens.push_back(new Screen(screen));
43 }
42 }
44}
43}
45
44
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+
46QHash<int, QByteArray> Screens::roleNames() const
57QHash<int, QByteArray> Screens::roleNames() const
47{
58{
48 QHash<int, QByteArray> roles;
59 QHash<int, QByteArray> roles;
@@ -52,13 +63,13 @@ QHash<int, QByteArray> Screens::roleNames() const
52
63
53QVariant Screens::data(const QModelIndex &index, int role) const
64QVariant Screens::data(const QModelIndex &index, int role) const
54{
65{
55− if (!index.isValid() || index.row() >= m_screenList.size()) {
66+ if (!index.isValid() || index.row() >= m_screens.size()) {
56 return QVariant();
67 return QVariant();
57 }
68 }
58
69
59 switch(role) {
70 switch(role) {
60 case ScreenRole:
71 case ScreenRole:
61− return QVariant::fromValue(m_screenList.at(index.row()));
72+ return QVariant::fromValue(m_screens.at(index.row()));
62 } // switch
73 } // switch
63
74
64 return QVariant();
75 return QVariant();
@@ -71,48 +82,66 @@ int Screens::rowCount(const QModelIndex &) const
71
82
72int Screens::count() const
83int Screens::count() const
73{
84{
74− return m_screenList.size();
85+ return m_screens.size();
75}
86}
76
87
77QVariant Screens::activeScreen() const
88QVariant Screens::activeScreen() const
78{
89{
79− for (int i = 0; i < m_screenList.count(); i++) {
90+ for (int i = 0; i < m_screens.count(); i++) {
80− if (m_screenList[i]->isActive()) return i;
91+ if (m_screens[i]->isActive()) return i;
81 }
92 }
82 return QVariant();
93 return QVariant();
83}
94}
84
95
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+
85void Screens::activateScreen(const QVariant& vindex)
114void Screens::activateScreen(const QVariant& vindex)
86{
115{
87 bool ok = false;
116 bool ok = false;
88 int index = vindex.toInt(&ok);
117 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;
90
119
91− auto screen = m_screenList.at(index);
120+ auto screen = m_screens.at(index);
92 screen->setActive(true);
121 screen->setActive(true);
93}
122}
94
123
95−void Screens::onScreenAdded(qtmir::Screen *screen)
124+void Screens::onScreenAdded(qtmir::Screen *added)
96{
125{
97− Q_FOREACH(auto screenWrapper, m_screenList) {
126+ Q_FOREACH(auto screenWrapper, m_screens) {
98− if (screenWrapper->wrapped() == screen) return;
127+ if (screenWrapper->wrapped() == added) return;
99 }
128 }
100
129
101 beginInsertRows(QModelIndex(), count(), count());
130 beginInsertRows(QModelIndex(), count(), count());
102− auto screenWrapper(new Screen(screen));
131+ auto screenWrapper(new Screen(added));
103− m_screenList.push_back(screenWrapper);
132+ m_screens.push_back(screenWrapper);
104 endInsertRows();
133 endInsertRows();
105 Q_EMIT screenAdded(screenWrapper);
134 Q_EMIT screenAdded(screenWrapper);
106 Q_EMIT countChanged();
135 Q_EMIT countChanged();
107}
136}
108
137
109−void Screens::onScreenRemoved(qtmir::Screen *screen)
138+void Screens::onScreenRemoved(qtmir::Screen *removed)
110{
139{
111 int index = 0;
140 int index = 0;
112− QMutableListIterator<Screen*> iter(m_screenList);
141+ QMutableVectorIterator<Screen*> iter(m_screens);
113 while(iter.hasNext()) {
142 while(iter.hasNext()) {
114 auto screenWrapper = iter.next();
143 auto screenWrapper = iter.next();
115− if (screenWrapper->wrapped() == screen) {
144+ if (screenWrapper->wrapped() == removed) {
116
145
117 beginRemoveRows(QModelIndex(), index, index);
146 beginRemoveRows(QModelIndex(), index, index);
118 iter.remove();
147 iter.remove();
@@ -127,3 +156,47 @@ void Screens::onScreenRemoved(qtmir::Screen *screen)
127 index++;
156 index++;
128 }
157 }
129}
158}
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 @@
19
19
20#include <QAbstractListModel>
20#include <QAbstractListModel>
21#include <QSharedPointer>
21#include <QSharedPointer>
22+#include <QPointer>
22
23
23−class Screen;
24namespace qtmir
24namespace qtmir
25{
25{
26class Screen;
26class Screen;
27class Screens;
27class Screens;
28}
28}
29
29
30+class Screen;
31+class ScreensProxy;
32+
30class Screens : public QAbstractListModel
33class Screens : public QAbstractListModel
31{
34{
32 Q_OBJECT
35 Q_OBJECT
@@ -38,8 +41,11 @@ public:
38 ScreenRole = Qt::UserRole + 1
41 ScreenRole = Qt::UserRole + 1
39 };
42 };
40
43
41− explicit Screens(QObject *parent = 0);
44+ explicit Screens(const QSharedPointer<qtmir::Screens>& model);
42− virtual ~Screens() noexcept = default;
45+ ~Screens();
46+
47+ Q_INVOKABLE ScreensProxy *createProxy();
48+ Q_INVOKABLE void sync(Screens *proxy);
43
49
44 /* QAbstractItemModel */
50 /* QAbstractItemModel */
45 QHash<int, QByteArray> roleNames() const override;
51 QHash<int, QByteArray> roleNames() const override;
@@ -49,6 +55,8 @@ public:
49 int count() const;
55 int count() const;
50 QVariant activeScreen() const;
56 QVariant activeScreen() const;
51
57
58+ const QVector<Screen*>& list() const { return m_screens; }
59+
52public Q_SLOTS:
60public Q_SLOTS:
53 void activateScreen(const QVariant& index);
61 void activateScreen(const QVariant& index);
54
62
@@ -63,9 +71,20 @@ private Q_SLOTS:
63 void onScreenAdded(qtmir::Screen *screen);
71 void onScreenAdded(qtmir::Screen *screen);
64 void onScreenRemoved(qtmir::Screen *screen);
72 void onScreenRemoved(qtmir::Screen *screen);
65
73
66−private:
74+protected:
67− QList<Screen*> m_screenList;
75+ Screens(const Screens& other);
76+
77+ QVector<Screen*> m_screens;
68 QSharedPointer<qtmir::Screens> m_wrapped;
78 QSharedPointer<qtmir::Screens> m_wrapped;
69};
79};
70
80
81+class ScreensProxy : public Screens
82+{
83+public:
84+ ScreensProxy(Screens*const screens);
85+
86+private:
87+ const QPointer<Screens> m_original;
88+};
89+
71#endif // SCREENS_H
90#endif // SCREENS_H
plugins/WindowManager/TopLevelWindowModel.cpp+167−43
@@ -24,11 +24,16 @@
24#include <unity/shell/application/SurfaceManagerInterface.h>
24#include <unity/shell/application/SurfaceManagerInterface.h>
25
25
26// Qt
26// Qt
27−#include <QGuiApplication>
28#include <QDebug>
27#include <QDebug>
29
28
30// local
29// local
31#include "Window.h"
30#include "Window.h"
31+#include "Workspace.h"
32+#include "windowmanagementpolicy.h"
33+
34+// qtmir
35+#include <qtmir/mirserverapplication.h>
36+#include <qtmir/windowmodelnotifier.h>
32
37
33Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
38Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
34
39
@@ -55,35 +60,24 @@ void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInte
55 beginResetModel();
60 beginResetModel();
56
61
57 if (m_applicationManager) {
62 if (m_applicationManager) {
58− m_windowModel.clear();
59 disconnect(m_applicationManager, 0, this, 0);
63 disconnect(m_applicationManager, 0, this, 0);
60 }
64 }
61
65
62 m_applicationManager = value;
66 m_applicationManager = value;
63
67
64− if (m_applicationManager) {
68+ if (m_applicationManager && m_workspace) {
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− });
72
69
73− connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
70+ if (m_workspace->isActive()) {
74− this, [this](const QModelIndex &/*parent*/, int first, int last) {
71+ connectApplicationManager();
75− for (int i = first; i <= last; ++i) {
76− auto application = m_applicationManager->get(i);
77− removeApplication(application);
78− }
79− });
72+ }
80
73
81− for (int i = 0; i < m_applicationManager->rowCount(); ++i) {
74+ if (m_surfaceManager) {
82− auto application = m_applicationManager->get(i);
75+ refreshWindows();
83− addApplication(application);
84 }
76 }
85 }
77 }
86
78
79+ Q_EMIT applicationManagerChanged(m_applicationManager);
80+
87 endResetModel();
81 endResetModel();
88 m_modelState = IdleState;
82 m_modelState = IdleState;
89}
83}
@@ -96,6 +90,11 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
96
90
97 DEBUG_MSG << "(" << surfaceManager << ")";
91 DEBUG_MSG << "(" << surfaceManager << ")";
98
92
93+ Q_ASSERT(m_modelState == IdleState);
94+ m_modelState = ResettingState;
95+
96+ beginResetModel();
97+
99 if (m_surfaceManager) {
98 if (m_surfaceManager) {
100 disconnect(m_surfaceManager, 0, this, 0);
99 disconnect(m_surfaceManager, 0, this, 0);
101 }
100 }
@@ -107,9 +106,68 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
107 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
106 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
108 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
107 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
109 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
108 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+ }
110 }
116 }
111
117
112 Q_EMIT surfaceManagerChanged(m_surfaceManager);
118 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;
113}
171}
114
172
115void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
173void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
@@ -328,33 +386,43 @@ Window *TopLevelWindowModel::createWindow(unityapi::MirSurfaceInterface *surface
328 return qmlWindow;
386 return qmlWindow;
329}
387}
330
388
389+
331−void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
390+void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface */*surface*/)
332{
391{
333− DEBUG_MSG << "(" << surface << ")";
392+}
334
393
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+
335− if (surface->parentSurface()) {
402+ if (surface->parentSurface()) {
336− // Wrap it in a Window so that we keep focusedWindow() up to date.
403+ // Wrap it in a Window so that we keep focusedWindow() up to date.
337− Window *window = createWindow(surface);
404+ Window *window = createWindow(surface);
338− connect(surface, &QObject::destroyed, window, [=](){
405+ connect(surface, &QObject::destroyed, window, [=](){
339− window->setSurface(nullptr);
406+ window->setSurface(nullptr);
340− window->deleteLater();
407+ window->deleteLater();
341− });
408+ });
342− } else {
343− if (surface->type() == Mir::InputMethodType) {
344− setInputMethodWindow(createWindow(surface));
345 } else {
409 } else {
346− auto *application = m_applicationManager->findApplicationWithSurface(surface);
410+ if (surface->type() == Mir::InputMethodType) {
347− if (application) {
411+ setInputMethodWindow(createWindow(surface));
348− prependSurface(surface, application);
349 } else {
412 } else {
413+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
414+ if (application) {
415+ prependSurface(surface, application);
416+ } else {
350− // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
417+ // 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.
418+ // 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.
419+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
353− Window *promptWindow = createWindow(surface);
420+ Window *promptWindow = createWindow(surface);
354− connect(surface, &QObject::destroyed, promptWindow, [=](){
421+ connect(surface, &QObject::destroyed, promptWindow, [=](){
355− promptWindow->setSurface(nullptr);
422+ promptWindow->setSurface(nullptr);
356− promptWindow->deleteLater();
423+ promptWindow->deleteLater();
357− });
424+ });
425+ }
358 }
426 }
359 }
427 }
360 }
428 }
@@ -444,6 +512,26 @@ QVariant TopLevelWindowModel::data(const QModelIndex& index, int role) const
444 }
512 }
445}
513}
446
514
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+
447int TopLevelWindowModel::findIndexOf(const unityapi::MirSurfaceInterface *surface) const
535int TopLevelWindowModel::findIndexOf(const unityapi::MirSurfaceInterface *surface) const
448{
536{
449 for (int i=0; i<m_windowModel.count(); i++) {
537 for (int i=0; i<m_windowModel.count(); i++) {
@@ -674,3 +762,39 @@ void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
674 }
762 }
675 }
763 }
676}
764}
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 @@
20#include <QAbstractListModel>
20#include <QAbstractListModel>
21#include <QLoggingCategory>
21#include <QLoggingCategory>
22
22
23+#include <memory>
24+
23Q_DECLARE_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL)
25Q_DECLARE_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL)
24
26
25class Window;
27class Window;
28+class Workspace;
29+
30+namespace miral { class Workspace; }
26
31
27namespace unity {
32namespace unity {
28 namespace shell {
33 namespace shell {
@@ -70,6 +75,11 @@ class TopLevelWindowModel : public QAbstractListModel
70 */
75 */
71 Q_PROPERTY(Window* focusedWindow READ focusedWindow NOTIFY focusedWindowChanged)
76 Q_PROPERTY(Window* focusedWindow READ focusedWindow NOTIFY focusedWindowChanged)
72
77
78+ Q_PROPERTY(Workspace* workspace
79+ READ workspace
80+ WRITE setWorkspace
81+ NOTIFY workspaceChanged)
82+
73 Q_PROPERTY(unity::shell::application::SurfaceManagerInterface* surfaceManager
83 Q_PROPERTY(unity::shell::application::SurfaceManagerInterface* surfaceManager
74 READ surfaceManager
84 READ surfaceManager
75 WRITE setSurfaceManager
85 WRITE setSurfaceManager
@@ -111,6 +121,9 @@ public:
111
121
112 // Own API
122 // Own API
113
123
124+ Workspace* workspace() const { return m_workspace; }
125+ void setWorkspace(Workspace* workspace);
126+
114 unity::shell::application::MirSurfaceInterface* inputMethodSurface() const;
127 unity::shell::application::MirSurfaceInterface* inputMethodSurface() const;
115 Window* focusedWindow() const;
128 Window* focusedWindow() const;
116
129
@@ -178,8 +191,11 @@ Q_SIGNALS:
178
191
179 void nextIdChanged();
192 void nextIdChanged();
180
193
194+ void workspaceChanged(Workspace*);
195+
181private Q_SLOTS:
196private Q_SLOTS:
182 void onSurfaceCreated(unity::shell::application::MirSurfaceInterface *surface);
197 void onSurfaceCreated(unity::shell::application::MirSurfaceInterface *surface);
198+ void onSurfacesAddedToWorkspace(const std::shared_ptr<miral::Workspace>& workspace, const QVector<unity::shell::application::MirSurfaceInterface*> surfaces);
183 void onSurfacesRaised(const QVector<unity::shell::application::MirSurfaceInterface*> &surfaces);
199 void onSurfacesRaised(const QVector<unity::shell::application::MirSurfaceInterface*> &surfaces);
184
200
185 void onModificationsStarted();
201 void onModificationsStarted();
@@ -208,6 +224,7 @@ private:
208 void prependSurfaceHelper(unity::shell::application::MirSurfaceInterface *surface,
224 void prependSurfaceHelper(unity::shell::application::MirSurfaceInterface *surface,
209 unity::shell::application::ApplicationInfoInterface *application);
225 unity::shell::application::ApplicationInfoInterface *application);
210
226
227+ void connectApplicationManager();
211 void connectWindow(Window *window);
228 void connectWindow(Window *window);
212 void connectSurface(unity::shell::application::MirSurfaceInterface *surface);
229 void connectSurface(unity::shell::application::MirSurfaceInterface *surface);
213
230
@@ -219,6 +236,7 @@ private:
219 void activateEmptyWindow(Window *window);
236 void activateEmptyWindow(Window *window);
220
237
221 void activateTopMostWindowWithoutId(int forbiddenId);
238 void activateTopMostWindowWithoutId(int forbiddenId);
239+ void refreshWindows();
222
240
223 Window *createWindow(unity::shell::application::MirSurfaceInterface *surface);
241 Window *createWindow(unity::shell::application::MirSurfaceInterface *surface);
224
242
@@ -232,6 +250,7 @@ private:
232 bool removeOnceSurfaceDestroyed{false};
250 bool removeOnceSurfaceDestroyed{false};
233 };
251 };
234
252
253+ Workspace* m_workspace{nullptr};
235 QVector<ModelEntry> m_windowModel;
254 QVector<ModelEntry> m_windowModel;
236 Window* m_inputMethodWindow{nullptr};
255 Window* m_inputMethodWindow{nullptr};
237 Window* m_focusedWindow{nullptr};
256 Window* m_focusedWindow{nullptr};
plugins/WindowManager/WindowManagerPlugin.cpp+6−3
@@ -26,6 +26,7 @@
26#include "WorkspaceModel.h"
26#include "WorkspaceModel.h"
27
27
28#include <QtQml>
28#include <QtQml>
29+#include <qtmir/qtmir.h>
29
30
30static QObject *workspace_manager(QQmlEngine *engine, QJSEngine *scriptEngine)
31static QObject *workspace_manager(QQmlEngine *engine, QJSEngine *scriptEngine)
31{
32{
@@ -36,7 +37,7 @@ static QObject *workspace_manager(QQmlEngine *engine, QJSEngine *scriptEngine)
36QObject* screensSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
37QObject* screensSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
37 Q_UNUSED(engine);
38 Q_UNUSED(engine);
38 Q_UNUSED(scriptEngine);
39 Q_UNUSED(scriptEngine);
39− return new Screens();
40+ return new Screens(qtmir::get_screen_model());
40}
41}
41
42
42void WindowManagerPlugin::registerTypes(const char *uri)
43void WindowManagerPlugin::registerTypes(const char *uri)
@@ -46,12 +47,14 @@ void WindowManagerPlugin::registerTypes(const char *uri)
46 qmlRegisterUncreatableType<WorkspaceModel>(uri, 1, 0, "WorkspaceModel", "Not a creatable type");
47 qmlRegisterUncreatableType<WorkspaceModel>(uri, 1, 0, "WorkspaceModel", "Not a creatable type");
47 qmlRegisterSingletonType<Screens>(uri, 1, 0, "Screens", screensSingleton);
48 qmlRegisterSingletonType<Screens>(uri, 1, 0, "Screens", screensSingleton);
48 qmlRegisterUncreatableType<qtmir::ScreenMode>(uri, 1, 0, "ScreenMode", "ScreenMode is not creatable.");
49 qmlRegisterUncreatableType<qtmir::ScreenMode>(uri, 1, 0, "ScreenMode", "ScreenMode is not creatable.");
50+ qmlRegisterUncreatableType<Workspace>(uri, 1, 0, "Workspace", "Workspace is not creatable.");
49
51
50− qRegisterMetaType<Window*>("Window*");
52+ qRegisterMetaType<Screen*>("Screen*");
53+ qRegisterMetaType<ScreensProxy*>("ScreensProxy*");
51 qRegisterMetaType<Workspace*>("Workspace*");
54 qRegisterMetaType<Workspace*>("Workspace*");
52
55
56+ qRegisterMetaType<Window*>("Window*");
53 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
57 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
54− qRegisterMetaType<Screen*>("Screen*");
55
58
56 qmlRegisterType<ScreenWindow>(uri, 1, 0, "ScreenWindow");
59 qmlRegisterType<ScreenWindow>(uri, 1, 0, "ScreenWindow");
57 qmlRegisterRevision<QWindow,1>(uri, 1, 0);
60 qmlRegisterRevision<QWindow,1>(uri, 1, 0);
plugins/WindowManager/Workspace.cpp+97−13
@@ -16,48 +16,132 @@
16
16
17#include "Workspace.h"
17#include "Workspace.h"
18#include "WorkspaceModel.h"
18#include "WorkspaceModel.h"
19+#include "WorkspaceManager.h"
20+#include "TopLevelWindowModel.h"
21+
22+#include "windowmanagementpolicy.h"
23+
24+int nextWorkspace = 0;
19
25
20Workspace::Workspace(QObject *parent)
26Workspace::Workspace(QObject *parent)
21 : QObject(parent)
27 : QObject(parent)
28+ , m_workspace(WindowManagementPolicy::instance()->createWorkspace())
22 , m_model(nullptr)
29 , m_model(nullptr)
30+ , m_active(false)
23{
31{
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);
24
39
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+ });
25}
59}
26
60
27Workspace::~Workspace()
61Workspace::~Workspace()
28{
62{
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);
30}
76}
31
77
32−void Workspace::assign(WorkspaceModel *model)
78+void Workspace::assign(WorkspaceModel *model, const QVariant& vIndex)
33{
79{
34− bool wasAssinged = false;
80+ if (m_model == model) return;
81+
35 if (m_model) {
82 if (m_model) {
36− disconnect(model);
83+ disconnect(m_model, 0, this, 0);
37 m_model->remove(this);
84 m_model->remove(this);
38− wasAssinged = true;
39 }
85 }
40
86
41 m_model = model;
87 m_model = model;
88+
42 if (model) {
89 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);
44
95
45− connect(model, &QObject::destroyed, this, [this]() {
96+ connect(m_model, &QObject::destroyed, this, [this]() {
97+ m_model->remove(this);
46 m_model = nullptr;
98 m_model = nullptr;
47 Q_EMIT unassigned();
99 Q_EMIT unassigned();
48 });
100 });
49 Q_EMIT assigned();
101 Q_EMIT assigned();
50− } else if (wasAssinged) {
102+ } else {
51 Q_EMIT unassigned();
103 Q_EMIT unassigned();
52 }
104 }
53}
105}
54
106
55void Workspace::unassign()
107void Workspace::unassign()
56{
108{
57− if (m_model) {
58− m_model->remove(this);
59− m_model = nullptr;
109+ assign(nullptr);
110+}
60
111
61− Q_EMIT unassigned();
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();
62− }
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();
63}
147}
plugins/WindowManager/Workspace.h+64−8
@@ -14,31 +14,87 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#ifndef WORKSPACE_H
17+#ifndef WINDOWMANAGER_WORKSPACE_H
18−#define WORKSPACE_H
18+#define WINDOWMANAGER_WORKSPACE_H
19
19
20#include <QObject>
20#include <QObject>
21+#include <QVariant>
22+#include <QPointer>
23+
24+#include <memory>
25+#include <functional>
21
26
22class WorkspaceModel;
27class 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+}
23
39
24class Workspace : public QObject
40class Workspace : public QObject
25{
41{
26 Q_OBJECT
42 Q_OBJECT
43+ Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
27public:
44public:
28− explicit Workspace(QObject *parent = 0);
29 ~Workspace();
45 ~Workspace();
30
46
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; }
32
57
58+
33−public Q_SLOT:
59+public Q_SLOTS:
34− void unassign();
60+ virtual void activate();
35
61
36Q_SIGNALS:
62Q_SIGNALS:
37 void assigned();
63 void assigned();
38 void unassigned();
64 void unassigned();
39
65
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;
41 WorkspaceModel* m_model;
73 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;
42};
98};
43
99
44−#endif // WORKSPACE_H
100+#endif // WINDOWMANAGER_WORKSPACE_H
plugins/WindowManager/WorkspaceManager.cpp+67−3
@@ -16,6 +16,7 @@
16
16
17#include "WorkspaceManager.h"
17#include "WorkspaceManager.h"
18#include "Workspace.h"
18#include "Workspace.h"
19+#include "TopLevelWindowModel.h"
19
20
20// Qt
21// Qt
21#include <QGuiApplication>
22#include <QGuiApplication>
@@ -29,19 +30,82 @@ WorkspaceManager *WorkspaceManager::instance()
29}
30}
30
31
31WorkspaceManager::WorkspaceManager()
32WorkspaceManager::WorkspaceManager()
33+ : m_activeWorkspace(nullptr)
32{
34{
33}
35}
36+
34Workspace *WorkspaceManager::createWorkspace()
37Workspace *WorkspaceManager::createWorkspace()
35{
38{
36 auto workspace = new Workspace(this);
39 auto workspace = new Workspace(this);
37 QQmlEngine::setObjectOwnership(workspace, QQmlEngine::CppOwnership);
40 QQmlEngine::setObjectOwnership(workspace, QQmlEngine::CppOwnership);
38− m_allWorkspaces.append(workspace);
41+ m_allWorkspaces.insert(workspace);
39− 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+ });
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+
40 return workspace;
60 return workspace;
41}
61}
42
62
43void WorkspaceManager::destroyWorkspace(Workspace *workspace)
63void WorkspaceManager::destroyWorkspace(Workspace *workspace)
44{
64{
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);
46}
90}
47
91
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 @@
18#define WORKSPACEMANAGER_H
18#define WORKSPACEMANAGER_H
19
19
20#include "WorkspaceModel.h"
20#include "WorkspaceModel.h"
21+#include <QQmlListProperty>
21
22
22class Workspace;
23class Workspace;
24+class ScreensProxy;
23
25
24−class WorkspaceManager : public WorkspaceModel
26+class WorkspaceManager : public QObject
25{
27{
26 Q_OBJECT
28 Q_OBJECT
29+ Q_PROPERTY(Workspace* activeWorkspace READ activeWorkspace WRITE setActiveWorkspace NOTIFY activeWorkspaceChanged)
30+ Q_PROPERTY(QQmlListProperty<Workspace> floatingWorkspaces READ floatingWorkspaces NOTIFY floatingWorkspacesChanged)
31+
27public:
32public:
28 static WorkspaceManager* instance();
33 static WorkspaceManager* instance();
29
34
30−private:
35+ Workspace* activeWorkspace() const;
31− WorkspaceManager();
36+ void setActiveWorkspace(Workspace* workspace);
32
37
33−public Q_SLOTS:
34 Workspace* createWorkspace();
38 Workspace* createWorkspace();
35 void destroyWorkspace(Workspace* workspace);
39 void destroyWorkspace(Workspace* workspace);
36
40
41+ QQmlListProperty<Workspace> floatingWorkspaces();
42+ void destroyFloatingWorkspaces();
43+
44+Q_SIGNALS:
45+ void activeWorkspaceChanged();
46+ void floatingWorkspacesChanged();
47+
37private:
48private:
49+ WorkspaceManager();
50+
38− QVector<Workspace*> m_allWorkspaces;
51+ QSet<Workspace*> m_allWorkspaces;
52+ QList<Workspace*> m_floatingWorkspaces;
53+ Workspace* m_activeWorkspace;
39};
54};
40
55
41#endif // WORKSPACEMANAGER_H
56#endif // WORKSPACEMANAGER_H
plugins/WindowManager/WorkspaceModel.cpp+94−2
@@ -1,4 +1,4 @@
1−/*
1+/*
2 * Copyright (C) 2017 Canonical, Ltd.
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17#include "WorkspaceModel.h"
17#include "WorkspaceModel.h"
18+#include "WorkspaceManager.h"
18#include "Workspace.h"
19#include "Workspace.h"
19
20
20Q_LOGGING_CATEGORY(WORKSPACES, "Workspaces", QtInfoMsg)
21Q_LOGGING_CATEGORY(WORKSPACES, "Workspaces", QtInfoMsg)
@@ -35,8 +36,12 @@ void WorkspaceModel::append(Workspace *workspace)
35void WorkspaceModel::insert(int index, Workspace *workspace)
36void WorkspaceModel::insert(int index, Workspace *workspace)
36{
37{
37 beginInsertRows(QModelIndex(), index, index);
38 beginInsertRows(QModelIndex(), index, index);
39+
38− m_workspaces.append(workspace);
40+ m_workspaces.insert(index, workspace);
41+
39 endInsertRows();
42 endInsertRows();
43+
44+ Q_EMIT workspaceAdded(workspace);
40 Q_EMIT countChanged();
45 Q_EMIT countChanged();
41}
46}
42
47
@@ -46,8 +51,12 @@ void WorkspaceModel::remove(Workspace *workspace)
46 if (index < 0) return;
51 if (index < 0) return;
47
52
48 beginRemoveRows(QModelIndex(), index, index);
53 beginRemoveRows(QModelIndex(), index, index);
54+
49 m_workspaces.removeAt(index);
55 m_workspaces.removeAt(index);
56+
50 endRemoveRows();
57 endRemoveRows();
58+
59+ Q_EMIT workspaceRemoved(workspace);
51 Q_EMIT countChanged();
60 Q_EMIT countChanged();
52}
61}
53
62
@@ -71,6 +80,17 @@ void WorkspaceModel::move(int from, int to)
71 }
80 }
72}
81}
73
82
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+
74int WorkspaceModel::rowCount(const QModelIndex &) const
94int WorkspaceModel::rowCount(const QModelIndex &) const
75{
95{
76 return m_workspaces.count();
96 return m_workspaces.count();
@@ -88,3 +108,75 @@ QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
88 return QVariant();
108 return QVariant();
89 }
109 }
90}
110}
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 @@
19
19
20#include <QAbstractListModel>
20#include <QAbstractListModel>
21#include <QLoggingCategory>
21#include <QLoggingCategory>
22+#include <QPointer>
22
23
23Q_DECLARE_LOGGING_CATEGORY(WORKSPACES)
24Q_DECLARE_LOGGING_CATEGORY(WORKSPACES)
24
25
25class Workspace;
26class Workspace;
27+class WorkspaceModelProxy;
26
28
27class WorkspaceModel : public QAbstractListModel
29class WorkspaceModel : public QAbstractListModel
28{
30{
@@ -40,10 +42,13 @@ public:
40
42
41 explicit WorkspaceModel(QObject *parent = 0);
43 explicit WorkspaceModel(QObject *parent = 0);
42
44
43− Q_INVOKABLE void append(Workspace* workspace);
45+ void append(Workspace *workspace);
44− Q_INVOKABLE void insert(int index, Workspace* workspace);
46+ void insert(int index, Workspace *workspace);
45− Q_INVOKABLE void remove(Workspace* workspace);
47+ void remove(Workspace* workspace);
46− Q_INVOKABLE void move(int from, int to);
48+ void move(int from, int to);
49+
50+ int indexOf(Workspace *workspace) const;
51+ Workspace* get(int index) const;
47
52
48 // From QAbstractItemModel
53 // From QAbstractItemModel
49 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
54 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
@@ -53,11 +58,28 @@ public:
53 return roleNames;
58 return roleNames;
54 }
59 }
55
60
61+ const QVector<Workspace*>& list() const { return m_workspaces; }
62+
63+ void sync(WorkspaceModel* proxy);
64+
56Q_SIGNALS:
65Q_SIGNALS:
57 void countChanged();
66 void countChanged();
58
67
68+ void workspaceAdded(Workspace *workspace);
69+ void workspaceRemoved(Workspace *workspace);
70+
59protected:
71protected:
60 QVector<Workspace*> m_workspaces;
72 QVector<Workspace*> m_workspaces;
61};
73};
62
74
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+
63#endif // WORKSPACEMODEL_H
85#endif // WORKSPACEMODEL_H
qml/Shell.qml+1−1
@@ -54,7 +54,6 @@ StyledItem {
54 theme.name: "Ubuntu.Components.Themes.SuruDark"
54 theme.name: "Ubuntu.Components.Themes.SuruDark"
55
55
56 // to be set from outside
56 // to be set from outside
57− property alias surfaceManager: topLevelSurfaceList.surfaceManager
58 property int orientationAngle: 0
57 property int orientationAngle: 0
59 property int orientation
58 property int orientation
60 property Orientations orientations
59 property Orientations orientations
@@ -277,6 +276,7 @@ StyledItem {
277 id: topLevelSurfaceList
276 id: topLevelSurfaceList
278 objectName: "topLevelSurfaceList"
277 objectName: "topLevelSurfaceList"
279 applicationManager: ApplicationManager // it's a singleton
278 applicationManager: ApplicationManager // it's a singleton
279+ surfaceManager: SurfaceManager
280 }
280 }
281
281
282 Stage {
282 Stage {
qml/ShellApplication.qml−4
@@ -17,21 +17,17 @@
17import QtQuick 2.4
17import QtQuick 2.4
18import QtQuick.Window 2.2
18import QtQuick.Window 2.2
19import WindowManager 1.0
19import WindowManager 1.0
20−import Unity.Application 0.1
21
20
22Instantiator {
21Instantiator {
23 id: root
22 id: root
24 model: Screens
23 model: Screens
25
24
26− property QtObject surfaceMan: SurfaceManager {}
27−
28 ShellScreen {
25 ShellScreen {
29 id: window
26 id: window
30 objectName: "screen"+index
27 objectName: "screen"+index
31 screen: model.screen
28 screen: model.screen
32 visibility: applicationArguments.hasFullscreen ? Window.FullScreen : Window.Windowed
29 visibility: applicationArguments.hasFullscreen ? Window.FullScreen : Window.Windowed
33 flags: applicationArguments.hasFrameless ? Qt.FramelessWindowHint : 0
30 flags: applicationArguments.hasFrameless ? Qt.FramelessWindowHint : 0
34− surfaceManager: surfaceMan
35
31
36 Binding {
32 Binding {
37 when: applicationArguments.hasGeometry
33 when: applicationArguments.hasGeometry
qml/ShellScreen.qml−2
@@ -26,7 +26,6 @@ ScreenWindow {
26 color: "black"
26 color: "black"
27 title: "Unity8 Shell"
27 title: "Unity8 Shell"
28 property bool primary: false
28 property bool primary: false
29− property QtObject surfaceManager: null
30
29
31 DeviceConfiguration {
30 DeviceConfiguration {
32 id: deviceConfiguration
31 id: deviceConfiguration
@@ -50,7 +49,6 @@ ScreenWindow {
50 OrientedShell {
49 OrientedShell {
51 implicitWidth: screenWindow.width
50 implicitWidth: screenWindow.width
52 implicitHeight: screenWindow.height
51 implicitHeight: screenWindow.height
53− surfaceManager: screenWindow.surfaceManager
54
52
55 deviceConfiguration {
53 deviceConfiguration {
56 name: Screens.count > 1 ? "desktop" : applicationArguments.deviceName
54 name: Screens.count > 1 ? "desktop" : applicationArguments.deviceName
src/CMakeLists.txt+8−2
@@ -28,7 +28,7 @@ set(SOURCE_FILES
28 ApplicationArguments.cpp
28 ApplicationArguments.cpp
29 main.cpp
29 main.cpp
30 CachingNetworkManagerFactory.cpp
30 CachingNetworkManagerFactory.cpp
31− ShellApplication.cpp
31+ UnityApplication.cpp
32 UnityCommandLineParser.cpp
32 UnityCommandLineParser.cpp
33 UnixSignalHandler.cpp
33 UnixSignalHandler.cpp
34 DebuggingController.cpp
34 DebuggingController.cpp
@@ -46,7 +46,13 @@ qt5_use_modules(${SHELL_APP} DBus Gui Qml Quick Test)
46if (NOT "${ANDROID_PROPERTIES_INCLUDE_DIRS}" STREQUAL "")
46if (NOT "${ANDROID_PROPERTIES_INCLUDE_DIRS}" STREQUAL "")
47 set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${ANDROID_PROPERTIES_INCLUDE_DIRS})
47 set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${ANDROID_PROPERTIES_INCLUDE_DIRS})
48endif()
48endif()
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+)
50
56
51if (ENABLE_TOUCH_EMULATION)
57if (ENABLE_TOUCH_EMULATION)
52 target_link_libraries(${SHELL_APP} ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
58 target_link_libraries(${SHELL_APP} ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
src/ShellApplication.cpp → src/UnityApplication.cpprenamed+9−29
@@ -14,7 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#include "ShellApplication.h"
17+#include "UnityApplication.h"
18
18
19// Qt
19// Qt
20#include <QLibrary>
20#include <QLibrary>
@@ -32,34 +32,14 @@
32#include "CachingNetworkManagerFactory.h"
32#include "CachingNetworkManagerFactory.h"
33#include "UnityCommandLineParser.h"
33#include "UnityCommandLineParser.h"
34#include "DebuggingController.h"
34#include "DebuggingController.h"
35+#include "windowmanagementpolicy.h"
35
36
36#include <QDebug>
37#include <QDebug>
37
38
38−#include <qtmir/windowmanagementpolicy.h>
39
39
40−class WindowManagementPolicy : public qtmir::WindowManagementPolicy
40+
41−{
41+UnityApplication::UnityApplication(int & argc, char ** argv)
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, {})
42+ : qtmir::MirServerApplication(argc, argv, { qtmir::SetWindowManagementPolicy<WindowManagementPolicy>() })
63 , m_qmlArgs(this)
43 , m_qmlArgs(this)
64{
44{
65 setApplicationName(QStringLiteral("unity8"));
45 setApplicationName(QStringLiteral("unity8"));
@@ -103,7 +83,7 @@ ShellApplication::ShellApplication(int & argc, char ** argv)
103 pxpgu = 8;
83 pxpgu = 8;
104 }
84 }
105 m_qmlEngine->rootContext()->setContextProperty("internalGu", pxpgu);
85 m_qmlEngine->rootContext()->setContextProperty("internalGu", pxpgu);
106− m_qmlEngine->load(::qmlDirectory() + "/ShellApplication.qml");
86+ m_qmlEngine->load(m_qmlArgs.qmlfie());
107
87
108 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
88 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
109 // You will need this if you want to interact with touch-only components using a mouse
89 // 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)
120 }
100 }
121}
101}
122
102
123−ShellApplication::~ShellApplication()
103+UnityApplication::~UnityApplication()
124{
104{
125 destroyResources();
105 destroyResources();
126}
106}
127
107
128−void ShellApplication::destroyResources()
108+void UnityApplication::destroyResources()
129{
109{
130 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
110 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
131 delete m_mouseTouchAdaptor;
111 delete m_mouseTouchAdaptor;
@@ -136,7 +116,7 @@ void ShellApplication::destroyResources()
136 m_qmlEngine = nullptr;
116 m_qmlEngine = nullptr;
137}
117}
138
118
139−void ShellApplication::setupQmlEngine()
119+void UnityApplication::setupQmlEngine()
140{
120{
141 m_qmlEngine = new QQmlApplicationEngine(this);
121 m_qmlEngine = new QQmlApplicationEngine(this);
142
122
src/ShellApplication.h → src/UnityApplication.hrenamed+6−6
@@ -14,8 +14,8 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#ifndef SHELLAPPLICATION_H
17+#ifndef UNITYAPPLICATION_H
18−#define SHELLAPPLICATION_H
18+#define UNITYAPPLICATION_H
19
19
20#include <QGuiApplication>
20#include <QGuiApplication>
21#include <QQmlApplicationEngine>
21#include <QQmlApplicationEngine>
@@ -30,12 +30,12 @@
30
30
31#include <qtmir/mirserverapplication.h>
31#include <qtmir/mirserverapplication.h>
32
32
33−class ShellApplication : public qtmir::MirServerApplication
33+class UnityApplication : public qtmir::MirServerApplication
34{
34{
35 Q_OBJECT
35 Q_OBJECT
36public:
36public:
37− ShellApplication(int & argc, char ** argv);
37+ UnityApplication(int & argc, char ** argv);
38− virtual ~ShellApplication();
38+ virtual ~UnityApplication();
39
39
40 void destroyResources();
40 void destroyResources();
41
41
@@ -50,4 +50,4 @@ private:
50 QQmlApplicationEngine *m_qmlEngine{nullptr};
50 QQmlApplicationEngine *m_qmlEngine{nullptr};
51};
51};
52
52
53−#endif // SHELLAPPLICATION_H
53+#endif // UNITYAPPLICATION_H
src/UnityCommandLineParser.cpp+8
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17#include "UnityCommandLineParser.h"
17#include "UnityCommandLineParser.h"
18+#include <paths.h>
18
19
19#include <QDebug>
20#include <QDebug>
20
21
@@ -60,6 +61,11 @@ UnityCommandLineParser::UnityCommandLineParser(const QCoreApplication &app)
60 QStringLiteral("mode"), QStringLiteral("full-greeter"));
61 QStringLiteral("mode"), QStringLiteral("full-greeter"));
61 parser.addOption(modeOption);
62 parser.addOption(modeOption);
62
63
64+ QCommandLineOption qmlfileOption(QStringLiteral("qmlfile"),
65+ QStringLiteral("The base qml file to load"),
66+ QStringLiteral("qmlfile"), ::qmlDirectory() + "/ShellApplication.qml");
67+ parser.addOption(qmlfileOption);
68+
63 // Treat args with single dashes the same as arguments with two dashes
69 // Treat args with single dashes the same as arguments with two dashes
64 // Ex: -fullscreen == --fullscreen
70 // Ex: -fullscreen == --fullscreen
65 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
71 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
@@ -85,6 +91,8 @@ UnityCommandLineParser::UnityCommandLineParser(const QCoreApplication &app)
85 m_hasFullscreen = parser.isSet(fullscreenOption);
91 m_hasFullscreen = parser.isSet(fullscreenOption);
86 m_deviceName = parser.value(devicenameOption);
92 m_deviceName = parser.value(devicenameOption);
87 resolveMode(parser, modeOption);
93 resolveMode(parser, modeOption);
94+
95+ m_qmlfile = parser.value(qmlfileOption);
88}
96}
89
97
90int UnityCommandLineParser::parsePixelsValue(const QString &str)
98int UnityCommandLineParser::parsePixelsValue(const QString &str)
src/UnityCommandLineParser.h+3
@@ -37,6 +37,8 @@ public:
37 QString deviceName() const { return m_deviceName; }
37 QString deviceName() const { return m_deviceName; }
38 QString mode() const { return m_mode; }
38 QString mode() const { return m_mode; }
39
39
40+ QString qmlfie() const { return m_qmlfile; }
41+
40protected:
42protected:
41 int parsePixelsValue(const QString &str);
43 int parsePixelsValue(const QString &str);
42 static float getenvFloat(const char* name, float defaultValue);
44 static float getenvFloat(const char* name, float defaultValue);
@@ -55,6 +57,7 @@ protected:
55 bool m_hasFullscreen;
57 bool m_hasFullscreen;
56 QString m_deviceName;
58 QString m_deviceName;
57 QString m_mode;
59 QString m_mode;
60+ QString m_qmlfile;
58};
61};
59
62
60#endif // UNITY_COMMAND_LINE_PARSER_H
63#endif // UNITY_COMMAND_LINE_PARSER_H
src/libunity8-private/CMakeLists.txt+10
@@ -4,16 +4,26 @@ set(VERSION ${SOVERSION}.0.0)
4
4
5project(lib${LIB_NAME})
5project(lib${LIB_NAME})
6
6
7+include_directories(
8+ SYSTEM
9+ ${QTMIRSERVER_INCLUDE_DIRS}
10+)
11+
7set(lib${LIB_NAME}_SRCS
12set(lib${LIB_NAME}_SRCS
8 abstractdbusservicemonitor.cpp
13 abstractdbusservicemonitor.cpp
9 unitydbusobject.cpp
14 unitydbusobject.cpp
10 unitydbusvirtualobject.cpp
15 unitydbusvirtualobject.cpp
16+ windowmanagementpolicy.cpp
11 )
17 )
12
18
13add_library(${LIB_NAME} SHARED
19add_library(${LIB_NAME} SHARED
14 ${lib${LIB_NAME}_SRCS}
20 ${lib${LIB_NAME}_SRCS}
15 )
21 )
16
22
23+target_link_libraries(${LIB_NAME}
24+ ${QTMIRSERVER_LDFLAGS}
25+ )
26+
17set_target_properties(${LIB_NAME} PROPERTIES
27set_target_properties(${LIB_NAME} PROPERTIES
18 VERSION ${VERSION}
28 VERSION ${VERSION}
19 SOVERSION ${SOVERSION}
29 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 @@
15 */
15 */
16
16
17// local
17// local
18−#include "ShellApplication.h"
18+#include "UnityApplication.h"
19#include "qmldebuggerutils.h"
19#include "qmldebuggerutils.h"
20#include "UnixSignalHandler.h"
20#include "UnixSignalHandler.h"
21+#include <paths.h>
21
22
22#include <QTranslator>
23#include <QTranslator>
23#include <QLibraryInfo>
24#include <QLibraryInfo>
@@ -31,7 +32,8 @@ int main(int argc, const char *argv[])
31 QQmlDebuggingEnabler qQmlEnableDebuggingHelper(true);
32 QQmlDebuggingEnabler qQmlEnableDebuggingHelper(true);
32 }
33 }
33
34
34− ShellApplication *application = new ShellApplication(argc, (char**)argv);
35+ auto *application = new UnityApplication(argc,
36+ (char**)argv);
35
37
36 UnixSignalHandler signalHandler([]{
38 UnixSignalHandler signalHandler([]{
37 QGuiApplication::exit(0);
39 QGuiApplication::exit(0);
tests/mocks/Unity/Application/SurfaceManager.cpp+5
@@ -38,6 +38,11 @@ SurfaceManager *SurfaceManager::instance()
38 return m_instance;
38 return m_instance;
39}
39}
40
40
41+MirSurfaceInterface *SurfaceManager::surfaceFor(const miral::Window&)
42+{
43+ return nullptr;
44+}
45+
41SurfaceManager::SurfaceManager(QObject *)
46SurfaceManager::SurfaceManager(QObject *)
42{
47{
43 DEBUG_MSG("");
48 DEBUG_MSG("");
tests/mocks/Unity/Application/SurfaceManager.h+2
@@ -42,6 +42,8 @@ public:
42
42
43 static SurfaceManager *instance();
43 static SurfaceManager *instance();
44
44
45+ unity::shell::application::MirSurfaceInterface *surfaceFor(const miral::Window& window) override;
46+
45 // SurfaceManagerInterface
47 // SurfaceManagerInterface
46 void raise(unity::shell::application::MirSurfaceInterface *surface) override;
48 void raise(unity::shell::application::MirSurfaceInterface *surface) override;
47 void activate(unity::shell::application::MirSurfaceInterface *surface) override;
49 void activate(unity::shell::application::MirSurfaceInterface *surface) override;
tests/mocks/Unity/Application/plugin.cpp+7−1
@@ -38,6 +38,12 @@ QObject* mirSingleton(QQmlEngine*, QJSEngine*)
38{
38{
39 return new MirMock;
39 return new MirMock;
40}
40}
41+
42+QObject* surfaceManagerSingleton(QQmlEngine*, QJSEngine*)
43+{
44+ return new SurfaceManager;
45+}
46+
41} // anonymous namespace
47} // anonymous namespace
42
48
43void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
49void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
@@ -59,7 +65,7 @@ void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
59
65
60 qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
66 qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
61 qmlRegisterSingletonType<MirMock>(uri, 0, 1, "Mir", mirSingleton);
67 qmlRegisterSingletonType<MirMock>(uri, 0, 1, "Mir", mirSingleton);
62− qmlRegisterType<SurfaceManager>(uri, 0, 1, "SurfaceManager");
68+ qmlRegisterSingletonType<SurfaceManager>(uri, 0, 1, "SurfaceManager", surfaceManagerSingleton);
63}
69}
64
70
65void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
71void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
tests/mocks/WindowManager/CMakeLists.txt+11−7
@@ -1,22 +1,26 @@
1include_directories(
1include_directories(
2− ${CMAKE_SOURCE_DIR}/plugins/WindowManager
2+ SYSTEM
3+ ${QTMIRSERVER_INCLUDE_DIRS}
3)
4)
4
5
5include_directories(
6include_directories(
6− SYSTEM
7+ ${CMAKE_CURRENT_SOURCE_DIR}
7− ${QTMIRSERVER_INCLUDE_DIRS}
8+ ${CMAKE_CURRENT_BINARY_DIR}
9+ ${CMAKE_SOURCE_DIR}/plugins/WindowManager
8)
10)
9
11
10set(WINDOWMANAGER_SRC
12set(WINDOWMANAGER_SRC
13+ ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Screen.cpp
14+ ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Screens.cpp
11 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/TopLevelWindowModel.cpp
15 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/TopLevelWindowModel.cpp
12 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Window.cpp
16 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Window.cpp
13− ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Workspace.cpp
14 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/WorkspaceManager.cpp
17 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/WorkspaceManager.cpp
15 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/WorkspaceModel.cpp
18 ${CMAKE_SOURCE_DIR}/plugins/WindowManager/WorkspaceModel.cpp
16− WindowManagerPlugin.cpp
19+ ${CMAKE_SOURCE_DIR}/plugins/WindowManager/Workspace.cpp
17− Screens.cpp
20+ MockScreens.cpp
18− Screen.cpp
19 ScreenWindow.cpp
21 ScreenWindow.cpp
22+ WindowManagerPlugin.cpp
23+ windowmanagementpolicy.h
20 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
24 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
21 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
25 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
22 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
26 ${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 @@
18
18
19#include "Screens.h"
19#include "Screens.h"
20#include "Screen.h"
20#include "Screen.h"
21+#include "MockScreens.h"
21#include "ScreenWindow.h"
22#include "ScreenWindow.h"
22#include "TopLevelWindowModel.h"
23#include "TopLevelWindowModel.h"
23#include "Window.h"
24#include "Window.h"
@@ -36,7 +37,8 @@ static QObject *workspace_manager(QQmlEngine *engine, QJSEngine *scriptEngine)
36QObject* screensSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
37QObject* screensSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
37 Q_UNUSED(engine);
38 Q_UNUSED(engine);
38 Q_UNUSED(scriptEngine);
39 Q_UNUSED(scriptEngine);
40+ QSharedPointer<qtmir::Screens> mockScreens(new MockScreens());
39− return new Screens();
41+ return new Screens(mockScreens);
40}
42}
41
43
42void WindowManagerPlugin::registerTypes(const char *uri)
44void WindowManagerPlugin::registerTypes(const char *uri)
@@ -46,12 +48,14 @@ void WindowManagerPlugin::registerTypes(const char *uri)
46 qmlRegisterUncreatableType<WorkspaceModel>(uri, 1, 0, "WorkspaceModel", "Not a creatable type");
48 qmlRegisterUncreatableType<WorkspaceModel>(uri, 1, 0, "WorkspaceModel", "Not a creatable type");
47 qmlRegisterSingletonType<Screens>(uri, 1, 0, "Screens", screensSingleton);
49 qmlRegisterSingletonType<Screens>(uri, 1, 0, "Screens", screensSingleton);
48 qmlRegisterUncreatableType<qtmir::ScreenMode>(uri, 1, 0, "ScreenMode", "ScreenMode is not creatable.");
50 qmlRegisterUncreatableType<qtmir::ScreenMode>(uri, 1, 0, "ScreenMode", "ScreenMode is not creatable.");
51+ qmlRegisterUncreatableType<Workspace>(uri, 1, 0, "Workspace", "Workspace is not creatable.");
49
52
50− qRegisterMetaType<Window*>("Window*");
53+ qRegisterMetaType<Screen*>("Screen*");
54+ qRegisterMetaType<ScreensProxy*>("ScreensProxy*");
51 qRegisterMetaType<Workspace*>("Workspace*");
55 qRegisterMetaType<Workspace*>("Workspace*");
52
56
57+ qRegisterMetaType<Window*>("Window*");
53 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
58 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
54− qRegisterMetaType<Screen*>("Screen*");
55
59
56 qmlRegisterType<ScreenWindow>(uri, 1, 0, "ScreenWindow");
60 qmlRegisterType<ScreenWindow>(uri, 1, 0, "ScreenWindow");
57 qmlRegisterRevision<QWindow,1>(uri, 1, 0);
61 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
6
6
7Object {
7Object {
8
8
9− property alias surfaceManager: sMgrHandler.target
10−
11 Connections {
9 Connections {
12− id: sMgrHandler
13− target: null
10+ target: SurfaceManager
14 onSurfaceCreated: {
11 onSurfaceCreated: {
15 var fakeMenuPath = "/" + surface.persistentId.replace(/\W+/g, "");
12 var fakeMenuPath = "/" + surface.persistentId.replace(/\W+/g, "");
16
13
tests/qmltests/ApplicationMenus/tst_MenuBar.qml−2
@@ -42,10 +42,8 @@ Item {
42 value: false
42 value: false
43 }
43 }
44
44
45− SurfaceManager { id: sMgr }
46 ApplicationMenuDataLoader {
45 ApplicationMenuDataLoader {
47 id: appMenuData
46 id: appMenuData
48− surfaceManager: sMgr
49 }
47 }
50
48
51 Rectangle {
49 Rectangle {
tests/qmltests/Panel/tst_ActiveCallHint.qml−2
@@ -41,8 +41,6 @@ Item {
41 elapsedTimerRunning: true
41 elapsedTimerRunning: true
42 }
42 }
43
43
44− SurfaceManager {}
45−
46 ActiveCallHint {
44 ActiveCallHint {
47 id: callHint
45 id: callHint
48 anchors {
46 anchors {
tests/qmltests/Panel/tst_Panel.qml−2
@@ -44,10 +44,8 @@ PanelTest {
44
44
45 readonly property alias panelState: panel.panelState
45 readonly property alias panelState: panel.panelState
46
46
47− SurfaceManager { id: sMgr }
48 ApplicationMenuDataLoader {
47 ApplicationMenuDataLoader {
49 id: appMenuData
48 id: appMenuData
50− surfaceManager: sMgr
51 }
49 }
52
50
53 Component.onCompleted: {
51 Component.onCompleted: {
tests/qmltests/Stage/tst_ApplicationWindow.qml−2
@@ -37,8 +37,6 @@ Rectangle {
37 }
37 }
38 property QtObject fakeApplication: null
38 property QtObject fakeApplication: null
39
39
40− SurfaceManager{}
41−
42 Loader {
40 Loader {
43 id: applicationWindowLoader
41 id: applicationWindowLoader
44 focus: true
42 focus: true
tests/qmltests/Stage/tst_DecoratedWindow.qml−2
@@ -46,10 +46,8 @@ Rectangle {
46 value: false
46 value: false
47 }
47 }
48
48
49− SurfaceManager { id: sMgr }
50 ApplicationMenuDataLoader {
49 ApplicationMenuDataLoader {
51 id: appMenuData
50 id: appMenuData
52− surfaceManager: sMgr
53 }
51 }
54
52
55 PanelState {
53 PanelState {
tests/qmltests/Stage/tst_DesktopStage.qml+1−3
@@ -67,16 +67,14 @@ Item {
67 }
67 }
68 }
68 }
69
69
70− SurfaceManager { id: sMgr }
71 ApplicationMenuDataLoader {
70 ApplicationMenuDataLoader {
72 id: appMenuData
71 id: appMenuData
73− surfaceManager: sMgr
74 }
72 }
75
73
76 TopLevelWindowModel {
74 TopLevelWindowModel {
77 id: topSurfaceList
75 id: topSurfaceList
78 applicationManager: ApplicationManager
76 applicationManager: ApplicationManager
79− surfaceManager: sMgr
77+ surfaceManager: SurfaceManager
80 }
78 }
81
79
82 Loader {
80 Loader {
tests/qmltests/Stage/tst_PhoneStage.qml+1−3
@@ -31,10 +31,8 @@ Item {
31
31
32 property var greeter: { fullyShown: true }
32 property var greeter: { fullyShown: true }
33
33
34− SurfaceManager { id: sMgr }
35 ApplicationMenuDataLoader {
34 ApplicationMenuDataLoader {
36 id: appMenuData
35 id: appMenuData
37− surfaceManager: sMgr
38 }
36 }
39
37
40 Stage {
38 Stage {
@@ -50,7 +48,7 @@ Item {
50 topLevelSurfaceList: TopLevelWindowModel {
48 topLevelSurfaceList: TopLevelWindowModel {
51 id: topLevelSurfaceList
49 id: topLevelSurfaceList
52 applicationManager: ApplicationManager
50 applicationManager: ApplicationManager
53− surfaceManager: sMgr
51+ surfaceManager: SurfaceManager
54 }
52 }
55 Component.onCompleted: {
53 Component.onCompleted: {
56 ApplicationManager.startApplication("unity8-dash");
54 ApplicationManager.startApplication("unity8-dash");
tests/qmltests/Stage/tst_SurfaceContainer.qml−2
@@ -51,8 +51,6 @@ Rectangle {
51 }
51 }
52 }
52 }
53
53
54− SurfaceManager {}
55−
56 Loader {
54 Loader {
57 id: surfaceContainerLoader
55 id: surfaceContainerLoader
58 focus: true
56 focus: true
tests/qmltests/Stage/tst_TabletStage.qml+1−3
@@ -35,10 +35,8 @@ Rectangle {
35
35
36 property var greeter: { fullyShown: true }
36 property var greeter: { fullyShown: true }
37
37
38− SurfaceManager { id: sMgr }
39 ApplicationMenuDataLoader {
38 ApplicationMenuDataLoader {
40 id: appMenuData
39 id: appMenuData
41− surfaceManager: sMgr
42 }
40 }
43
41
44 Stage {
42 Stage {
@@ -59,7 +57,7 @@ Rectangle {
59 topLevelSurfaceList: TopLevelWindowModel {
57 topLevelSurfaceList: TopLevelWindowModel {
60 id: topLevelSurfaceList
58 id: topLevelSurfaceList
61 applicationManager: ApplicationManager
59 applicationManager: ApplicationManager
62− surfaceManager: sMgr
60+ surfaceManager: SurfaceManager
63 }
61 }
64 Component.onCompleted: {
62 Component.onCompleted: {
65 ApplicationManager.startApplication("unity8-dash");
63 ApplicationManager.startApplication("unity8-dash");
tests/qmltests/Stage/tst_WindowDecoration.qml−2
@@ -47,10 +47,8 @@ Item {
47 property string name: "webbrowser"
47 property string name: "webbrowser"
48 }
48 }
49
49
50− SurfaceManager { id: sMgr }
51 ApplicationMenuDataLoader {
50 ApplicationMenuDataLoader {
52 id: appMenuData
51 id: appMenuData
53− surfaceManager: sMgr
54 }
52 }
55
53
56 UnityMenuModel {
54 UnityMenuModel {
tests/qmltests/Tutorial/tst_Tutorial.qml+1−3
@@ -326,9 +326,7 @@ Rectangle {
326 }
326 }
327
327
328 function ensureInputMethodSurface() {
328 function ensureInputMethodSurface() {
329− var surfaceManager = findInvisibleChild(shell, "surfaceManager");
330− verify(surfaceManager);
331− surfaceManager.createInputMethodSurface();
329+ SurfaceManager.createInputMethodSurface();
332
330
333 tryCompareFunction(function() { return topLevelSurfaceList.inputMethodSurface !== null }, true);
331 tryCompareFunction(function() { return topLevelSurfaceList.inputMethodSurface !== null }, true);
334 }
332 }
tests/qmltests/tst_OrientedShell.qml−5
@@ -179,11 +179,6 @@ Rectangle {
179 Component.onDestruction: {
179 Component.onDestruction: {
180 orientedShellLoader.itemDestroyed = true;
180 orientedShellLoader.itemDestroyed = true;
181 }
181 }
182−
183− SurfaceManager {
184− id: surfaceMan
185− }
186− surfaceManager: surfaceMan
187 }
182 }
188 }
183 }
189 }
184 }
tests/qmltests/tst_Shell.qml+1−10
@@ -61,11 +61,9 @@ Rectangle {
61 onShellChanged: {
61 onShellChanged: {
62 if (shell) {
62 if (shell) {
63 topLevelSurfaceList = testCase.findInvisibleChild(shell, "topLevelSurfaceList");
63 topLevelSurfaceList = testCase.findInvisibleChild(shell, "topLevelSurfaceList");
64− appMenuData.surfaceManager = testCase.findInvisibleChild(shell, "surfaceManager");
65 panelState = testCase.findInvisibleChild(shell, "panelState");
64 panelState = testCase.findInvisibleChild(shell, "panelState");
66 } else {
65 } else {
67 topLevelSurfaceList = null;
66 topLevelSurfaceList = null;
68− appMenuData.surfaceManager = null;
69 panelState = undefined;
67 panelState = undefined;
70 }
68 }
71 }
69 }
@@ -152,11 +150,6 @@ Rectangle {
152 Component.onDestruction: {
150 Component.onDestruction: {
153 shellLoader.itemDestroyed = true;
151 shellLoader.itemDestroyed = true;
154 }
152 }
155−
156− SurfaceManager {
157− id: surfaceMan
158− }
159− surfaceManager: surfaceMan
160 }
153 }
161 }
154 }
162 }
155 }
@@ -696,9 +689,7 @@ Rectangle {
696 }
689 }
697
690
698 function ensureInputMethodSurface() {
691 function ensureInputMethodSurface() {
699− var surfaceManager = shell.surfaceManager;
700− verify(surfaceManager);
701− surfaceManager.createInputMethodSurface();
692+ SurfaceManager.createInputMethodSurface();
702
693
703 tryCompareFunction(function() { return root.topLevelSurfaceList.inputMethodSurface !== null }, true);
694 tryCompareFunction(function() { return root.topLevelSurfaceList.inputMethodSurface !== null }, true);
704 }
695 }