@@ -15,6 +15,7 @@
17#include "TopLevelWindowModel.h"
17#include "TopLevelWindowModel.h"
18+#include "WindowManagerObjects.h"
19// unity-api
20// unity-api
20#include <unity/shell/application/ApplicationInfoInterface.h>
21#include <unity/shell/application/ApplicationInfoInterface.h>
@@ -24,11 +25,16 @@
24#include <unity/shell/application/SurfaceManagerInterface.h>
25#include <unity/shell/application/SurfaceManagerInterface.h>
27−#include <QGuiApplication>
28#include <QDebug>
28#include <QDebug>
31#include "Window.h"
31#include "Window.h"
32+#include "Workspace.h"
33+#include "wmpolicyinterface.h"
36+#include <qtmir/mirserverapplication.h>
37+#include <qtmir/windowmodelnotifier.h>
33Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
39Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
@@ -37,8 +43,16 @@ Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
38namespace unityapi = unity::shell::application;
44namespace unityapi = unity::shell::application;
40−TopLevelWindowModel::TopLevelWindowModel()
46+TopLevelWindowModel::TopLevelWindowModel(Workspace* workspace)
47+ : m_workspace(workspace)
49+ connect(WindowManagerObjects::instance(), &WindowManagerObjects::applicationManagerChanged,
50+ this, &TopLevelWindowModel::setApplicationManager);
51+ connect(WindowManagerObjects::instance(), &WindowManagerObjects::surfaceManagerChanged,
52+ this, &TopLevelWindowModel::setSurfaceManager);
54+ setApplicationManager(WindowManagerObjects::instance()->applicationManager());
55+ setSurfaceManager(WindowManagerObjects::instance()->surfaceManager());
44void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInterface* value)
58void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInterface* value)
@@ -55,7 +69,6 @@ void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInte
55 beginResetModel();
69 beginResetModel();
57 if (m_applicationManager) {
71 if (m_applicationManager) {
58− m_windowModel.clear();
59 disconnect(m_applicationManager, 0, this, 0);
72 disconnect(m_applicationManager, 0, this, 0);
@@ -64,26 +77,26 @@ void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInte
64 if (m_applicationManager) {
77 if (m_applicationManager) {
65 connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
78 connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
66 this, [this](const QModelIndex &/*parent*/, int first, int last) {
79 this, [this](const QModelIndex &/*parent*/, int first, int last) {
80+ if (!m_workspace || !m_workspace->isActive())
67− for (int i = first; i <= last; ++i) {
83+ for (int i = first; i <= last; ++i) {
68− auto application = m_applicationManager->get(i);
84+ auto application = m_applicationManager->get(i);
69− addApplication(application);
85+ addApplication(application);
73 connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
89 connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
74 this, [this](const QModelIndex &/*parent*/, int first, int last) {
90 this, [this](const QModelIndex &/*parent*/, int first, int last) {
75− for (int i = first; i <= last; ++i) {
91+ for (int i = first; i <= last; ++i) {
76− auto application = m_applicationManager->get(i);
92+ auto application = m_applicationManager->get(i);
77− removeApplication(application);
93+ removeApplication(application);
81− for (int i = 0; i < m_applicationManager->rowCount(); ++i) {
82− auto application = m_applicationManager->get(i);
83− addApplication(application);
87 endResetModel();
100 endResetModel();
88 m_modelState = IdleState;
101 m_modelState = IdleState;
@@ -96,6 +109,11 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
97 DEBUG_MSG << "(" << surfaceManager << ")";
110 DEBUG_MSG << "(" << surfaceManager << ")";
112+ Q_ASSERT(m_modelState == IdleState);
113+ m_modelState = ResettingState;
99 if (m_surfaceManager) {
117 if (m_surfaceManager) {
100 disconnect(m_surfaceManager, 0, this, 0);
118 disconnect(m_surfaceManager, 0, this, 0);
@@ -107,9 +125,17 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
107 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
125 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
108 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
126 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
109 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
127 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
129+ connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesAddedToWorkspace,
130+ this, &TopLevelWindowModel::onSurfacesAddedToWorkspace);
131+ connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesAboutToBeRemovedFromWorkspace,
132+ this, &TopLevelWindowModel::onSurfacesAboutToBeRemovedFromWorkspace);
112− Q_EMIT surfaceManagerChanged(m_surfaceManager);
135+ refreshWindows();
138+ m_modelState = IdleState;
115void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
141void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
@@ -153,6 +179,7 @@ void TopLevelWindowModel::prependSurface(unityapi::MirSurfaceInterface *surface,
153 ModelEntry &entry = m_windowModel[i];
179 ModelEntry &entry = m_windowModel[i];
154 if (entry.application == application && entry.window->surface() == nullptr) {
180 if (entry.application == application && entry.window->surface() == nullptr) {
155 entry.window->setSurface(surface);
181 entry.window->setSurface(surface);
182+ m_allSurfaces.insert(surface);
156 connectSurface(surface);
183 connectSurface(surface);
157 INFO_MSG << " appId=" << application->appId() << " surface=" << surface
184 INFO_MSG << " appId=" << application->appId() << " surface=" << surface
158 << ", filling out placeholder. after: " << toString();
185 << ", filling out placeholder. after: " << toString();
@@ -180,6 +207,7 @@ void TopLevelWindowModel::prependSurfaceHelper(unityapi::MirSurfaceInterface *su
181 m_windowModel.prepend(ModelEntry(window, application));
208 m_windowModel.prepend(ModelEntry(window, application));
182 if (surface) {
209 if (surface) {
210+ m_allSurfaces.insert(surface);
183 connectSurface(surface);
211 connectSurface(surface);
@@ -207,15 +235,14 @@ void TopLevelWindowModel::connectWindow(Window *window)
208 connect(window, &Window::focusedChanged, this, [this, window](bool focused) {
236 connect(window, &Window::focusedChanged, this, [this, window](bool focused) {
209 if (window->surface()) {
237 if (window->surface()) {
210− // Condense changes to the focused window
211− // eg: Do focusedWindow=A to focusedWindow=B instead of
212− // focusedWindow=A to focusedWindow=null to focusedWindow=B
213 if (focused) {
238 if (focused) {
214− Q_ASSERT(m_newlyFocusedWindow == nullptr);
239+ setFocusedWindow(window);
215− m_focusedWindowChanged = true;
240+ m_focusedWindowCleared = false;
216− m_newlyFocusedWindow = window;
217 } else if (m_focusedWindow == window) {
241 } else if (m_focusedWindow == window) {
218− m_focusedWindowChanged = true;
242+ // Condense changes to the focused window
243+ // eg: Do focusedWindow=A to focusedWindow=B instead of
244+ // focusedWindow=A to focusedWindow=null to focusedWindow=B
245+ m_focusedWindowCleared = true;
220 // don't clear the focused window if you were not there in the first place
247 // don't clear the focused window if you were not there in the first place
221 // happens when a filled window gets replaced with an empty one (no surface) as the focused window.
248 // happens when a filled window gets replaced with an empty one (no surface) as the focused window.
@@ -313,6 +340,7 @@ void TopLevelWindowModel::onSurfaceDestroyed(unityapi::MirSurfaceInterface *surf
313 auto window = m_windowModel[i].window;
340 auto window = m_windowModel[i].window;
314 window->setSurface(nullptr);
341 window->setSurface(nullptr);
315 window->setFocused(false);
342 window->setFocused(false);
343+ m_allSurfaces.remove(surface);
316 INFO_MSG << " Removed surface from entry. After: " << toString();
344 INFO_MSG << " Removed surface from entry. After: " << toString();
@@ -328,39 +356,103 @@ Window *TopLevelWindowModel::createWindow(unityapi::MirSurfaceInterface *surface
328 return qmlWindow;
356 return qmlWindow;
331−void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
360+void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface */*surface*/)
333− DEBUG_MSG << "(" << surface << ")";
362+}
364+void TopLevelWindowModel::onSurfacesAddedToWorkspace(const std::shared_ptr<miral::Workspace>& workspace,
365+ const QVector<unity::shell::application::MirSurfaceInterface*> surfaces)
367+ if (!m_workspace || !m_applicationManager) return;
368+ if (workspace != m_workspace->workspace()) return;
370+ Q_FOREACH(auto surface, surfaces) {
371+ if (m_allSurfaces.contains(surface)) continue;
335− if (surface->parentSurface()) {
373+ if (surface->parentSurface()) {
336− // Wrap it in a Window so that we keep focusedWindow() up to date.
374+ // Wrap it in a Window so that we keep focusedWindow() up to date.
337− Window *window = createWindow(surface);
375+ Window *window = createWindow(surface);
338− connect(surface, &QObject::destroyed, window, [=](){
376+ connect(surface, &QObject::destroyed, window, [=](){
339− window->setSurface(nullptr);
377+ window->setSurface(nullptr);
340− window->deleteLater();
378+ window->deleteLater();
343− if (surface->type() == Mir::InputMethodType) {
344− connectSurface(surface);
345− setInputMethodWindow(createWindow(surface));
347− auto *application = m_applicationManager->findApplicationWithSurface(surface);
381+ if (surface->type() == Mir::InputMethodType) {
348− if (application) {
382+ connectSurface(surface);
349− prependSurface(surface, application);
383+ setInputMethodWindow(createWindow(surface));
385+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
387+ prependSurface(surface, application);
351− // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
389+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
352− // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
390+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
353− // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
391+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
354− Window *promptWindow = createWindow(surface);
392+ Window *promptWindow = createWindow(surface);
355− connect(surface, &QObject::destroyed, promptWindow, [=](){
393+ connect(surface, &QObject::destroyed, promptWindow, [=](){
356− promptWindow->setSurface(nullptr);
394+ promptWindow->setSurface(nullptr);
357− promptWindow->deleteLater();
395+ promptWindow->deleteLater();
403+void TopLevelWindowModel::onSurfacesAboutToBeRemovedFromWorkspace(const std::shared_ptr<miral::Workspace> &workspace,
404+ const QVector<unity::shell::application::MirSurfaceInterface *> surfaces)
406+ if (!m_workspace || workspace != m_workspace->workspace()) return;
410+ for (auto iter = surfaces.constBegin(); iter != surfaces.constEnd();) {
411+ auto surface = *iter;
414+ // Do removals in adjacent blocks.
415+ start = end = indexOf(surface);
417+ // probably a child surface
418+ m_allSurfaces.remove(surface);
421+ while(iter != surfaces.constEnd()) {
422+ int index = indexOf(*iter);
423+ if (index != end+1) {
430+ if (m_modelState == IdleState) {
431+ beginRemoveRows(QModelIndex(), start, end);
432+ m_modelState = RemovingState;
434+ Q_ASSERT(m_modelState == ResettingState);
435+ // No point in signaling anything if we're resetting the whole model
438+ for (int index = start; index <= end; index++) {
439+ auto window = m_windowModel[start].window;
440+ window->setSurface(nullptr);
441+ window->setFocused(false);
443+ m_windowModel.removeAt(start);
444+ m_allSurfaces.remove(surface);
447+ if (m_modelState == RemovingState) {
449+ Q_EMIT countChanged();
450+ Q_EMIT listChanged();
451+ m_modelState = IdleState;
364void TopLevelWindowModel::removeAt(int index)
456void TopLevelWindowModel::removeAt(int index)
366 if (m_modelState == IdleState) {
458 if (m_modelState == IdleState) {
@@ -372,11 +464,13 @@ void TopLevelWindowModel::removeAt(int index)
374 auto window = m_windowModel[index].window;
466 auto window = m_windowModel[index].window;
467+ auto surface = window->surface();
376 window->setSurface(nullptr);
469 window->setSurface(nullptr);
377 window->setFocused(false);
470 window->setFocused(false);
379 m_windowModel.removeAt(index);
472 m_windowModel.removeAt(index);
473+ m_allSurfaces.remove(surface);
381 if (m_modelState == RemovingState) {
475 if (m_modelState == RemovingState) {
382 endRemoveRows();
476 endRemoveRows();
@@ -388,6 +482,7 @@ void TopLevelWindowModel::removeAt(int index)
388 disconnect(window, 0, this, 0);
482 disconnect(window, 0, this, 0);
389 if (m_focusedWindow == window) {
483 if (m_focusedWindow == window) {
390 setFocusedWindow(nullptr);
484 setFocusedWindow(nullptr);
485+ m_focusedWindowCleared = false;
392 delete window;
487 delete window;
@@ -656,12 +751,11 @@ void TopLevelWindowModel::onModificationsStarted()
657void TopLevelWindowModel::onModificationsEnded()
752void TopLevelWindowModel::onModificationsEnded()
659− if (m_focusedWindowChanged) {
754+ if (m_focusedWindowCleared) {
660− setFocusedWindow(m_newlyFocusedWindow);
755+ setFocusedWindow(nullptr);
663− m_focusedWindowChanged = false;
758+ m_focusedWindowCleared = false;
664− m_newlyFocusedWindow = nullptr;
667void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
761void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
@@ -675,3 +769,54 @@ void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
773+void TopLevelWindowModel::refreshWindows()
778+ if (!m_workspace || !m_applicationManager || !m_surfaceManager) return;
780+ m_surfaceManager->forEachSurfaceInWorkspace(m_workspace->workspace(), [this](unity::shell::application::MirSurfaceInterface* surface) {
781+ if (surface->parentSurface()) {
782+ // Wrap it in a Window so that we keep focusedWindow() up to date.
783+ Window *window = createWindow(surface);
784+ connect(surface, &QObject::destroyed, window, [=](){
785+ window->setSurface(nullptr);
786+ window->deleteLater();
789+ if (surface->type() == Mir::InputMethodType) {
790+ setInputMethodWindow(createWindow(surface));
792+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
794+ prependSurface(surface, application);
796+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
797+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
798+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
799+ Window *promptWindow = createWindow(surface);
800+ connect(surface, &QObject::destroyed, promptWindow, [=](){
801+ promptWindow->setSurface(nullptr);
802+ promptWindow->deleteLater();
810+void TopLevelWindowModel::clear()
814+ while(m_windowModel.count() > 0) {
815+ ModelEntry entry = m_windowModel.takeAt(0);
816+ disconnect(entry.window, 0, this, 0);
817+ delete entry.window;
819+ m_allSurfaces.clear();
820+ setFocusedWindow(nullptr);
821+ m_focusedWindowCleared = false;