@@ -24,11 +24,16 @@
2424#include <unity/shell/application/SurfaceManagerInterface.h>
2525
2626// Qt
27−#include <QGuiApplication>
2827#include <QDebug>
2928
3029// local
3130#include "Window.h"
31+#include "Workspace.h"
32+#include "windowmanagementpolicy.h"
33+
34+// qtmir
35+#include <qtmir/mirserverapplication.h>
36+#include <qtmir/windowmodelnotifier.h>
3237
3338Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
3439
@@ -55,35 +60,24 @@ void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInte
5560 beginResetModel();
5661
5762 if (m_applicationManager) {
58− m_windowModel.clear();
5963 disconnect(m_applicationManager, 0, this, 0);
6064 }
6165
6266 m_applicationManager = value;
6367
64− if (m_applicationManager) {
65− connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
66− this, [this](const QModelIndex &/*parent*/, int first, int last) {
67− for (int i = first; i <= last; ++i) {
68− auto application = m_applicationManager->get(i);
69− addApplication(application);
70− }
71− });
68+ if (m_applicationManager && m_workspace) {
7269
73− connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
74− this, [this](const QModelIndex &/*parent*/, int first, int last) {
75− for (int i = first; i <= last; ++i) {
76− auto application = m_applicationManager->get(i);
77− removeApplication(application);
78− }
79− });
70+ if (m_workspace->isActive()) {
71+ connectApplicationManager();
72+ }
8073
81− for (int i = 0; i < m_applicationManager->rowCount(); ++i) {
82− auto application = m_applicationManager->get(i);
83− addApplication(application);
74+ if (m_surfaceManager) {
75+ refreshWindows();
8476 }
8577 }
8678
79+ Q_EMIT applicationManagerChanged(m_applicationManager);
80+
8781 endResetModel();
8882 m_modelState = IdleState;
8983}
@@ -96,6 +90,11 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
9690
9791 DEBUG_MSG << "(" << surfaceManager << ")";
9892
93+ Q_ASSERT(m_modelState == IdleState);
94+ m_modelState = ResettingState;
95+
96+ beginResetModel();
97+
9998 if (m_surfaceManager) {
10099 disconnect(m_surfaceManager, 0, this, 0);
101100 }
@@ -107,9 +106,68 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
107106 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
108107 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
109108 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
109+
110+ connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesAddedToWorkspace,
111+ this, &TopLevelWindowModel::onSurfacesAddedToWorkspace);
112+
113+ if (m_workspace && m_applicationManager) {
114+ refreshWindows();
115+ }
110116 }
111117
112118 Q_EMIT surfaceManagerChanged(m_surfaceManager);
119+
120+ endResetModel();
121+ m_modelState = IdleState;
122+}
123+
124+void TopLevelWindowModel::setWorkspace(Workspace *workspace)
125+{
126+ if (workspace == m_workspace) {
127+ return;
128+ }
129+
130+ DEBUG_MSG << "(" << workspace << ")";
131+
132+ Q_ASSERT(m_modelState == IdleState);
133+ m_modelState = ResettingState;
134+
135+ beginResetModel();
136+
137+ if (m_workspace) {
138+ m_windowModel.clear();
139+ if (m_applicationManager) {
140+ disconnect(m_applicationManager, 0, this, 0);
141+ }
142+ }
143+
144+ disconnect(m_applicationManager, 0 ,this, 0);
145+
146+ m_workspace = workspace;
147+
148+ if (m_workspace) {
149+ connect(m_workspace, &Workspace::activeChanged, this, [this](bool active) {
150+ if (m_applicationManager) {
151+ if (!active) disconnect(m_applicationManager, 0, this, 0);
152+ else {
153+ connectApplicationManager();
154+ }
155+ }
156+ });
157+
158+ if (m_applicationManager && m_workspace->isActive()) {
159+ connectApplicationManager();
160+ }
161+
162+ if (m_surfaceManager && m_applicationManager) {
163+ refreshWindows();
164+ }
165+ }
166+
167+ Q_EMIT workspaceChanged(workspace);
168+
169+ endResetModel();
170+ m_modelState = IdleState;
113171}
114172
115173void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
@@ -328,33 +386,43 @@ Window *TopLevelWindowModel::createWindow(unityapi::MirSurfaceInterface *surface
328386 return qmlWindow;
329387}
330388
331−void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
389+
390+void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface */*surface*/)
332391{
333− DEBUG_MSG << "(" << surface << ")";
392+}
334393
335− if (surface->parentSurface()) {
336− // Wrap it in a Window so that we keep focusedWindow() up to date.
337− Window *window = createWindow(surface);
338− connect(surface, &QObject::destroyed, window, [=](){
339− window->setSurface(nullptr);
340− window->deleteLater();
341− });
342− } else {
343− if (surface->type() == Mir::InputMethodType) {
344− setInputMethodWindow(createWindow(surface));
394+void TopLevelWindowModel::onSurfacesAddedToWorkspace(const std::shared_ptr<miral::Workspace>& workspace,
395+ const QVector<unity::shell::application::MirSurfaceInterface*> surfaces)
396+{
397+ if (workspace != m_workspace->workspace()) return;
398+
399+ Q_FOREACH(auto surface, surfaces) {
400+ DEBUG_MSG << "(" << surface << ")";
401+
402+ if (surface->parentSurface()) {
403+ // Wrap it in a Window so that we keep focusedWindow() up to date.
404+ Window *window = createWindow(surface);
405+ connect(surface, &QObject::destroyed, window, [=](){
406+ window->setSurface(nullptr);
407+ window->deleteLater();
408+ });
345409 } else {
346− auto *application = m_applicationManager->findApplicationWithSurface(surface);
347− if (application) {
348− prependSurface(surface, application);
410+ if (surface->type() == Mir::InputMethodType) {
411+ setInputMethodWindow(createWindow(surface));
349412 } else {
350− // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
351− // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
352− // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
353− Window *promptWindow = createWindow(surface);
354− connect(surface, &QObject::destroyed, promptWindow, [=](){
355− promptWindow->setSurface(nullptr);
356− promptWindow->deleteLater();
357− });
413+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
414+ if (application) {
415+ prependSurface(surface, application);
416+ } else {
417+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
418+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
419+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
420+ Window *promptWindow = createWindow(surface);
421+ connect(surface, &QObject::destroyed, promptWindow, [=](){
422+ promptWindow->setSurface(nullptr);
423+ promptWindow->deleteLater();
424+ });
425+ }
358426 }
359427 }
360428 }
@@ -444,6 +512,26 @@ QVariant TopLevelWindowModel::data(const QModelIndex& index, int role) const
444512 }
445513}
446514
515+void TopLevelWindowModel::connectApplicationManager()
516+{
517+ connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
518+ this, [this](const QModelIndex &/*parent*/, int first, int last) {
519+ for (int i = first; i <= last; ++i) {
520+ auto application = m_applicationManager->get(i);
521+ addApplication(application);
522+ }
523+ });
524+
525+ connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
526+ this, [this](const QModelIndex &/*parent*/, int first, int last) {
527+ for (int i = first; i <= last; ++i) {
528+ auto application = m_applicationManager->get(i);
529+ removeApplication(application);
530+ }
531+ });
532+}
533+
534+
447535int TopLevelWindowModel::findIndexOf(const unityapi::MirSurfaceInterface *surface) const
448536{
449537 for (int i=0; i<m_windowModel.count(); i++) {
@@ -674,3 +762,39 @@ void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
674762 }
675763 }
676764}
765+
766+void TopLevelWindowModel::refreshWindows()
767+{
768+ m_windowModel.clear();
769+ WindowManagementPolicy::instance()->forEachWindowInWorkspace(m_workspace->workspace(), [this](const miral::Window &window) {
770+ auto surface = m_surfaceManager->surfaceFor(window);
771+ if (surface) {
772+ if (surface->parentSurface()) {
773+ // Wrap it in a Window so that we keep focusedWindow() up to date.
774+ Window *window = createWindow(surface);
775+ connect(surface, &QObject::destroyed, window, [=](){
776+ window->setSurface(nullptr);
777+ window->deleteLater();
778+ });
779+ } else {
780+ if (surface->type() == Mir::InputMethodType) {
781+ setInputMethodWindow(createWindow(surface));
782+ } else {
783+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
784+ if (application) {
785+ prependSurface(surface, application);
786+ } else {
787+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
788+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
789+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
790+ Window *promptWindow = createWindow(surface);
791+ connect(surface, &QObject::destroyed, promptWindow, [=](){
792+ promptWindow->setSurface(nullptr);
793+ promptWindow->deleteLater();
794+ });
795+ }
796+ }
797+ }
798+ }
799+ });
800+}