@@ -24,11 +24,16 @@
24#include <unity/shell/application/SurfaceManagerInterface.h>
24#include <unity/shell/application/SurfaceManagerInterface.h>
27−#include <QGuiApplication>
28#include <QDebug>
27#include <QDebug>
31#include "Window.h"
30#include "Window.h"
31+#include "Workspace.h"
32+#include "wmpolicyinterface.h"
35+#include <qtmir/mirserverapplication.h>
36+#include <qtmir/windowmodelnotifier.h>
33Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
38Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
@@ -55,7 +60,6 @@ void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInte
55 beginResetModel();
60 beginResetModel();
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);
@@ -64,26 +68,27 @@ void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInte
64 if (m_applicationManager) {
68 if (m_applicationManager) {
65 connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
69 connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
66 this, [this](const QModelIndex &/*parent*/, int first, int last) {
70 this, [this](const QModelIndex &/*parent*/, int first, int last) {
71+ if (!m_workspace || !m_workspace->isActive())
67− for (int i = first; i <= last; ++i) {
74+ for (int i = first; i <= last; ++i) {
68− auto application = m_applicationManager->get(i);
75+ auto application = m_applicationManager->get(i);
69− addApplication(application);
76+ addApplication(application);
73 connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
80 connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
74 this, [this](const QModelIndex &/*parent*/, int first, int last) {
81 this, [this](const QModelIndex &/*parent*/, int first, int last) {
75− for (int i = first; i <= last; ++i) {
82+ for (int i = first; i <= last; ++i) {
76− auto application = m_applicationManager->get(i);
83+ auto application = m_applicationManager->get(i);
77− removeApplication(application);
84+ removeApplication(application);
81− for (int i = 0; i < m_applicationManager->rowCount(); ++i) {
82− auto application = m_applicationManager->get(i);
83− addApplication(application);
89+ Q_EMIT applicationManagerChanged(m_applicationManager);
87 endResetModel();
92 endResetModel();
88 m_modelState = IdleState;
93 m_modelState = IdleState;
@@ -96,6 +101,11 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
97 DEBUG_MSG << "(" << surfaceManager << ")";
102 DEBUG_MSG << "(" << surfaceManager << ")";
104+ Q_ASSERT(m_modelState == IdleState);
105+ m_modelState = ResettingState;
99 if (m_surfaceManager) {
109 if (m_surfaceManager) {
100 disconnect(m_surfaceManager, 0, this, 0);
110 disconnect(m_surfaceManager, 0, this, 0);
@@ -107,9 +117,44 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
107 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
117 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
108 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
118 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
109 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
119 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
121+ connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesAddedToWorkspace,
122+ this, &TopLevelWindowModel::onSurfacesAddedToWorkspace);
123+ connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesAboutToBeRemovedFromWorkspace,
124+ this, &TopLevelWindowModel::onSurfacesAboutToBeRemovedFromWorkspace);
112 Q_EMIT surfaceManagerChanged(m_surfaceManager);
128 Q_EMIT surfaceManagerChanged(m_surfaceManager);
131+ m_modelState = IdleState;
134+void TopLevelWindowModel::setWorkspace(Workspace *workspace)
136+ if (workspace == m_workspace) {
140+ DEBUG_MSG << "(" << workspace << ")";
142+ Q_ASSERT(m_modelState == IdleState);
143+ m_modelState = ResettingState;
148+ disconnect(m_workspace, 0, this, 0);
151+ m_workspace = workspace;
154+ Q_EMIT workspaceChanged(workspace);
157+ m_modelState = IdleState;
115void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
160void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
@@ -153,6 +198,7 @@ void TopLevelWindowModel::prependSurface(unityapi::MirSurfaceInterface *surface,
153 ModelEntry &entry = m_windowModel[i];
198 ModelEntry &entry = m_windowModel[i];
154 if (entry.application == application && entry.window->surface() == nullptr) {
199 if (entry.application == application && entry.window->surface() == nullptr) {
155 entry.window->setSurface(surface);
200 entry.window->setSurface(surface);
201+ m_allSurfaces.insert(surface);
156 connectSurface(surface);
202 connectSurface(surface);
157 INFO_MSG << " appId=" << application->appId() << " surface=" << surface
203 INFO_MSG << " appId=" << application->appId() << " surface=" << surface
158 << ", filling out placeholder. after: " << toString();
204 << ", filling out placeholder. after: " << toString();
@@ -180,6 +226,7 @@ void TopLevelWindowModel::prependSurfaceHelper(unityapi::MirSurfaceInterface *su
181 m_windowModel.prepend(ModelEntry(window, application));
227 m_windowModel.prepend(ModelEntry(window, application));
182 if (surface) {
228 if (surface) {
229+ m_allSurfaces.insert(surface);
183 connectSurface(surface);
230 connectSurface(surface);
@@ -211,7 +258,6 @@ void TopLevelWindowModel::connectWindow(Window *window)
211 // eg: Do focusedWindow=A to focusedWindow=B instead of
258 // eg: Do focusedWindow=A to focusedWindow=B instead of
212 // focusedWindow=A to focusedWindow=null to focusedWindow=B
259 // focusedWindow=A to focusedWindow=null to focusedWindow=B
213 if (focused) {
260 if (focused) {
214− Q_ASSERT(m_newlyFocusedWindow == nullptr);
215 m_focusedWindowChanged = true;
261 m_focusedWindowChanged = true;
216 m_newlyFocusedWindow = window;
262 m_newlyFocusedWindow = window;
217 } else if (m_focusedWindow == window) {
263 } else if (m_focusedWindow == window) {
@@ -313,6 +359,7 @@ void TopLevelWindowModel::onSurfaceDestroyed(unityapi::MirSurfaceInterface *surf
313 auto window = m_windowModel[i].window;
359 auto window = m_windowModel[i].window;
314 window->setSurface(nullptr);
360 window->setSurface(nullptr);
315 window->setFocused(false);
361 window->setFocused(false);
362+ m_allSurfaces.remove(surface);
316 INFO_MSG << " Removed surface from entry. After: " << toString();
363 INFO_MSG << " Removed surface from entry. After: " << toString();
@@ -328,38 +375,102 @@ Window *TopLevelWindowModel::createWindow(unityapi::MirSurfaceInterface *surface
328 return qmlWindow;
375 return qmlWindow;
331−void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
379+void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface */*surface*/)
333− DEBUG_MSG << "(" << surface << ")";
381+}
383+void TopLevelWindowModel::onSurfacesAddedToWorkspace(const std::shared_ptr<miral::Workspace>& workspace,
384+ const QVector<unity::shell::application::MirSurfaceInterface*> surfaces)
386+ if (!m_workspace || !m_applicationManager) return;
387+ if (workspace != m_workspace->workspace()) return;
389+ Q_FOREACH(auto surface, surfaces) {
390+ if (m_allSurfaces.contains(surface)) continue;
335− if (surface->parentSurface()) {
392+ if (surface->parentSurface()) {
336− // Wrap it in a Window so that we keep focusedWindow() up to date.
393+ // Wrap it in a Window so that we keep focusedWindow() up to date.
337− Window *window = createWindow(surface);
394+ Window *window = createWindow(surface);
338− connect(surface, &QObject::destroyed, window, [=](){
395+ connect(surface, &QObject::destroyed, window, [=](){
339− window->setSurface(nullptr);
396+ window->setSurface(nullptr);
340− window->deleteLater();
397+ window->deleteLater();
343− if (surface->type() == Mir::InputMethodType) {
344− setInputMethodWindow(createWindow(surface));
346− auto *application = m_applicationManager->findApplicationWithSurface(surface);
400+ if (surface->type() == Mir::InputMethodType) {
347− if (application) {
401+ setInputMethodWindow(createWindow(surface));
348− prependSurface(surface, application);
403+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
405+ prependSurface(surface, application);
350− // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
407+ // 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.
408+ // 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.
409+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
353− Window *promptWindow = createWindow(surface);
410+ Window *promptWindow = createWindow(surface);
354− connect(surface, &QObject::destroyed, promptWindow, [=](){
411+ connect(surface, &QObject::destroyed, promptWindow, [=](){
355− promptWindow->setSurface(nullptr);
412+ promptWindow->setSurface(nullptr);
356− promptWindow->deleteLater();
413+ promptWindow->deleteLater();
421+void TopLevelWindowModel::onSurfacesAboutToBeRemovedFromWorkspace(const std::shared_ptr<miral::Workspace> &workspace,
422+ const QVector<unity::shell::application::MirSurfaceInterface *> surfaces)
424+ if (!m_workspace || workspace != m_workspace->workspace()) return;
428+ for (auto iter = surfaces.constBegin(); iter != surfaces.constEnd();) {
429+ auto surface = *iter;
432+ // Do removals in adjacent blocks.
433+ start = end = indexOf(surface);
435+ // probably a child surface
436+ m_allSurfaces.remove(surface);
439+ while(iter != surfaces.constEnd()) {
440+ int index = indexOf(*iter);
441+ if (index != end+1) {
448+ if (m_modelState == IdleState) {
449+ beginRemoveRows(QModelIndex(), start, end);
450+ m_modelState = RemovingState;
452+ Q_ASSERT(m_modelState == ResettingState);
453+ // No point in signaling anything if we're resetting the whole model
456+ for (int index = start; index <= end; index++) {
457+ auto window = m_windowModel[start].window;
458+ window->setSurface(nullptr);
459+ window->setFocused(false);
461+ m_windowModel.removeAt(start);
462+ m_allSurfaces.remove(surface);
465+ if (m_modelState == RemovingState) {
467+ Q_EMIT countChanged();
468+ Q_EMIT listChanged();
469+ m_modelState = IdleState;
363void TopLevelWindowModel::removeAt(int index)
474void TopLevelWindowModel::removeAt(int index)
365 if (m_modelState == IdleState) {
476 if (m_modelState == IdleState) {
@@ -371,11 +482,13 @@ void TopLevelWindowModel::removeAt(int index)
373 auto window = m_windowModel[index].window;
484 auto window = m_windowModel[index].window;
485+ auto surface = window->surface();
375 window->setSurface(nullptr);
487 window->setSurface(nullptr);
376 window->setFocused(false);
488 window->setFocused(false);
378 m_windowModel.removeAt(index);
490 m_windowModel.removeAt(index);
491+ m_allSurfaces.remove(surface);
380 if (m_modelState == RemovingState) {
493 if (m_modelState == RemovingState) {
381 endRemoveRows();
494 endRemoveRows();
@@ -388,6 +501,10 @@ void TopLevelWindowModel::removeAt(int index)
388 if (m_focusedWindow == window) {
501 if (m_focusedWindow == window) {
389 setFocusedWindow(nullptr);
502 setFocusedWindow(nullptr);
504+ if (m_newlyFocusedWindow == window) {
505+ m_focusedWindowChanged = false;
506+ m_newlyFocusedWindow = nullptr;
391 delete window;
508 delete window;
393 INFO_MSG << " after " << toString();
510 INFO_MSG << " after " << toString();
@@ -674,3 +791,55 @@ void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
795+void TopLevelWindowModel::refreshWindows()
800+ if (!m_workspace || !m_applicationManager || !m_surfaceManager) return;
802+ m_surfaceManager->forEachSurfaceInWorkspace(m_workspace->workspace(), [this](unity::shell::application::MirSurfaceInterface* surface) {
803+ if (surface->parentSurface()) {
804+ // Wrap it in a Window so that we keep focusedWindow() up to date.
805+ Window *window = createWindow(surface);
806+ connect(surface, &QObject::destroyed, window, [=](){
807+ window->setSurface(nullptr);
808+ window->deleteLater();
811+ if (surface->type() == Mir::InputMethodType) {
812+ setInputMethodWindow(createWindow(surface));
814+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
816+ prependSurface(surface, application);
818+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
819+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
820+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
821+ Window *promptWindow = createWindow(surface);
822+ connect(surface, &QObject::destroyed, promptWindow, [=](){
823+ promptWindow->setSurface(nullptr);
824+ promptWindow->deleteLater();
832+void TopLevelWindowModel::clear()
836+ while(m_windowModel.count() > 0) {
837+ ModelEntry entry = m_windowModel.takeAt(0);
838+ disconnect(entry.window, 0, this, 0);
839+ delete entry.window;
841+ m_allSurfaces.clear();
842+ setFocusedWindow(nullptr);
843+ m_focusedWindowChanged = false;
844+ m_newlyFocusedWindow = nullptr;