@@ -15,6 +15,7 @@
1515 */
1616
1717#include "TopLevelWindowModel.h"
18+#include "WindowManagerObjects.h"
1819
1920// unity-api
2021#include <unity/shell/application/ApplicationInfoInterface.h>
@@ -24,11 +25,11 @@
2425#include <unity/shell/application/SurfaceManagerInterface.h>
2526
2627// Qt
27−#include <QGuiApplication>
2828#include <QDebug>
2929
3030// local
3131#include "Window.h"
32+#include "Workspace.h"
3233
3334Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
3435
@@ -37,7 +38,19 @@ Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
3738
3839namespace unityapi = unity::shell::application;
3940
40−TopLevelWindowModel::TopLevelWindowModel()
41+TopLevelWindowModel::TopLevelWindowModel(Workspace* workspace)
42+ : m_workspace(workspace)
43+{
44+ connect(WindowManagerObjects::instance(), &WindowManagerObjects::applicationManagerChanged,
45+ this, &TopLevelWindowModel::setApplicationManager);
46+ connect(WindowManagerObjects::instance(), &WindowManagerObjects::surfaceManagerChanged,
47+ this, &TopLevelWindowModel::setSurfaceManager);
48+
49+ setApplicationManager(WindowManagerObjects::instance()->applicationManager());
50+ setSurfaceManager(WindowManagerObjects::instance()->surfaceManager());
51+}
52+
53+TopLevelWindowModel::~TopLevelWindowModel()
4154{
4255}
4356
@@ -55,7 +68,6 @@ void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInte
5568 beginResetModel();
5669
5770 if (m_applicationManager) {
58− m_windowModel.clear();
5971 disconnect(m_applicationManager, 0, this, 0);
6072 }
6173
@@ -64,26 +76,26 @@ void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInte
6476 if (m_applicationManager) {
6577 connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
6678 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− });
79+ if (!m_workspace || !m_workspace->isActive())
80+ return;
81+
82+ for (int i = first; i <= last; ++i) {
83+ auto application = m_applicationManager->get(i);
84+ addApplication(application);
85+ }
86+ });
7287
7388 connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
7489 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− });
80−
81− for (int i = 0; i < m_applicationManager->rowCount(); ++i) {
82− auto application = m_applicationManager->get(i);
83− addApplication(application);
84− }
90+ for (int i = first; i <= last; ++i) {
91+ auto application = m_applicationManager->get(i);
92+ removeApplication(application);
93+ }
94+ });
8595 }
8696
97+ refreshWindows();
98+
8799 endResetModel();
88100 m_modelState = IdleState;
89101}
@@ -96,6 +108,11 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
96108
97109 DEBUG_MSG << "(" << surfaceManager << ")";
98110
111+ Q_ASSERT(m_modelState == IdleState);
112+ m_modelState = ResettingState;
113+
114+ beginResetModel();
115+
99116 if (m_surfaceManager) {
100117 disconnect(m_surfaceManager, 0, this, 0);
101118 }
@@ -103,13 +120,16 @@ void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *s
103120 m_surfaceManager = surfaceManager;
104121
105122 if (m_surfaceManager) {
106− connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfaceCreated, this, &TopLevelWindowModel::onSurfaceCreated);
123+ connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesAddedToWorkspace, this, &TopLevelWindowModel::onSurfacesAddedToWorkspace);
107124 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
108125 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
109126 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
110127 }
111128
112− Q_EMIT surfaceManagerChanged(m_surfaceManager);
129+ refreshWindows();
130+
131+ endResetModel();
132+ m_modelState = IdleState;
113133}
114134
115135void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
@@ -149,6 +169,7 @@ void TopLevelWindowModel::prependSurface(unityapi::MirSurfaceInterface *surface,
149169 Q_ASSERT(surface != nullptr);
150170
151171 connectSurface(surface);
172+ m_allSurfaces.insert(surface);
152173
153174 bool filledPlaceholder = false;
154175 for (int i = 0; i < m_windowModel.count() && !filledPlaceholder; ++i) {
@@ -225,15 +246,14 @@ void TopLevelWindowModel::connectWindow(Window *window)
225246
226247 connect(window, &Window::focusedChanged, this, [this, window](bool focused) {
227248 if (window->surface()) {
228− // Condense changes to the focused window
229− // eg: Do focusedWindow=A to focusedWindow=B instead of
230− // focusedWindow=A to focusedWindow=null to focusedWindow=B
231249 if (focused) {
232− Q_ASSERT(m_newlyFocusedWindow == nullptr);
233− m_focusedWindowChanged = true;
234− m_newlyFocusedWindow = window;
250+ setFocusedWindow(window);
251+ m_focusedWindowCleared = false;
235252 } else if (m_focusedWindow == window) {
236− m_focusedWindowChanged = true;
253+ // Condense changes to the focused window
254+ // eg: Do focusedWindow=A to focusedWindow=B instead of
255+ // focusedWindow=A to focusedWindow=null to focusedWindow=B
256+ m_focusedWindowCleared = true;
237257 } else {
238258 // don't clear the focused window if you were not there in the first place
239259 // happens when a filled window gets replaced with an empty one (no surface) as the focused window.
@@ -338,6 +358,7 @@ void TopLevelWindowModel::onSurfaceDestroyed(unityapi::MirSurfaceInterface *surf
338358 auto window = m_windowModel[i].window;
339359 window->setSurface(nullptr);
340360 window->setFocused(false);
361+ m_allSurfaces.remove(surface);
341362 INFO_MSG << " Removed surface from entry. After: " << toString();
342363 }
343364}
@@ -353,48 +374,107 @@ Window *TopLevelWindowModel::createWindow(unityapi::MirSurfaceInterface *surface
353374 return qmlWindow;
354375}
355376
356−void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
377+void TopLevelWindowModel::onSurfacesAddedToWorkspace(const std::shared_ptr<miral::Workspace>& workspace,
378+ const QVector<unity::shell::application::MirSurfaceInterface*> surfaces)
357379{
358− DEBUG_MSG << "(" << surface << ")";
380+ if (!m_workspace || !m_applicationManager) return;
381+ if (workspace != m_workspace->workspace()) {
382+ removeSurfaces(surfaces);
383+ return;
384+ }
359385
360− if (surface->parentSurface()) {
361− // Wrap it in a Window so that we keep focusedWindow() up to date.
362− Window *window = createWindow(surface);
363− connect(surface, &QObject::destroyed, window, [=](){
364− window->setSurface(nullptr);
365− window->deleteLater();
366− });
367− } else {
368− if (surface->type() == Mir::InputMethodType) {
369− connectSurface(surface);
370− setInputMethodWindow(createWindow(surface));
386+ Q_FOREACH(auto surface, surfaces) {
387+ if (m_allSurfaces.contains(surface)) continue;
388+
389+ if (surface->parentSurface()) {
390+ // Wrap it in a Window so that we keep focusedWindow() up to date.
391+ Window *window = createWindow(surface);
392+ connect(surface, &QObject::destroyed, window, [=](){
393+ window->setSurface(nullptr);
394+ window->deleteLater();
395+ });
371396 } else {
372− auto *application = m_applicationManager->findApplicationWithSurface(surface);
373− if (application) {
374− if (surface->state() == Mir::HiddenState) {
375− // Ignore it until it's finally shown
376− connect(surface, &unityapi::MirSurfaceInterface::stateChanged, this, [=](Mir::State newState) {
377− Q_ASSERT(newState != Mir::HiddenState);
378− disconnect(surface, &unityapi::MirSurfaceInterface::stateChanged, this, 0);
397+ if (surface->type() == Mir::InputMethodType) {
398+ connectSurface(surface);
399+ setInputMethodWindow(createWindow(surface));
400+ } else {
401+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
402+ if (application) {
403+ if (surface->state() == Mir::HiddenState) {
404+ // Ignore it until it's finally shown
405+ connect(surface, &unityapi::MirSurfaceInterface::stateChanged, this, [=](Mir::State newState) {
406+ Q_ASSERT(newState != Mir::HiddenState);
407+ disconnect(surface, &unityapi::MirSurfaceInterface::stateChanged, this, 0);
408+ prependSurface(surface, application);
409+ });
410+ } else {
379411 prependSurface(surface, application);
380− });
412+ }
381413 } else {
382− prependSurface(surface, application);
414+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
415+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
416+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
417+ Window *promptWindow = createWindow(surface);
418+ connect(surface, &QObject::destroyed, promptWindow, [=](){
419+ promptWindow->setSurface(nullptr);
420+ promptWindow->deleteLater();
421+ });
383422 }
384− } else {
385− // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
386− // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
387− // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
388− Window *promptWindow = createWindow(surface);
389− connect(surface, &QObject::destroyed, promptWindow, [=](){
390− promptWindow->setSurface(nullptr);
391− promptWindow->deleteLater();
392− });
393423 }
394424 }
395425 }
396426}
397427
428+void TopLevelWindowModel::removeSurfaces(const QVector<unity::shell::application::MirSurfaceInterface *> surfaces)
429+{
430+ int start = -1;
431+ int end = -1;
432+ for (auto iter = surfaces.constBegin(); iter != surfaces.constEnd();) {
433+ auto surface = *iter;
434+ iter++;
435+
436+ // Do removals in adjacent blocks.
437+ start = end = indexOf(surface);
438+ if (start == -1) {
439+ // could be a child surface
440+ m_allSurfaces.remove(surface);
441+ continue;
442+ }
443+ while(iter != surfaces.constEnd()) {
444+ int index = indexOf(*iter);
445+ if (index != end+1) {
446+ break;
447+ }
448+ end++;
449+ iter++;
450+ }
451+
452+ if (m_modelState == IdleState) {
453+ beginRemoveRows(QModelIndex(), start, end);
454+ m_modelState = RemovingState;
455+ } else {
456+ Q_ASSERT(m_modelState == ResettingState);
457+ // No point in signaling anything if we're resetting the whole model
458+ }
459+
460+ for (int index = start; index <= end; index++) {
461+ auto window = m_windowModel[start].window;
462+ window->setSurface(nullptr);
463+ window->setFocused(false);
464+
465+ m_windowModel.removeAt(start);
466+ m_allSurfaces.remove(surface);
467+ }
468+
469+ if (m_modelState == RemovingState) {
470+ endRemoveRows();
471+ Q_EMIT countChanged();
472+ Q_EMIT listChanged();
473+ m_modelState = IdleState;
474+ }
475+ }
476+}
477+
398478void TopLevelWindowModel::deleteAt(int index)
399479{
400480 auto window = m_windowModel[index].window;
@@ -417,12 +497,14 @@ void TopLevelWindowModel::removeAt(int index)
417497 }
418498
419499 auto window = m_windowModel[index].window;
500+ auto surface = window->surface();
420501
421502 if (!window->surface()) {
422503 window->setFocused(false);
423504 }
424505
425506 m_windowModel.removeAt(index);
507+ m_allSurfaces.remove(surface);
426508
427509 if (m_modelState == RemovingState) {
428510 endRemoveRows();
@@ -433,6 +515,7 @@ void TopLevelWindowModel::removeAt(int index)
433515
434516 if (m_focusedWindow == window) {
435517 setFocusedWindow(nullptr);
518+ m_focusedWindowCleared = false;
436519 }
437520
438521 INFO_MSG << " after " << toString();
@@ -451,6 +534,15 @@ void TopLevelWindowModel::setInputMethodWindow(Window *window)
451534void TopLevelWindowModel::removeInputMethodWindow()
452535{
453536 if (m_inputMethodWindow) {
537+ auto surface = m_inputMethodWindow->surface();
538+ if (surface) {
539+ m_allSurfaces.remove(surface);
540+ }
541+ if (m_focusedWindow == m_inputMethodWindow) {
542+ setFocusedWindow(nullptr);
543+ m_focusedWindowCleared = false;
544+ }
545+
454546 delete m_inputMethodWindow;
455547 m_inputMethodWindow = nullptr;
456548 Q_EMIT inputMethodSurfaceChanged(nullptr);
@@ -462,7 +554,7 @@ void TopLevelWindowModel::onSurfacesRaised(const QVector<unityapi::MirSurfaceInt
462554 DEBUG_MSG << "(" << surfaces << ")";
463555 const int raiseCount = surfaces.size();
464556 for (int i = 0; i < raiseCount; i++) {
465− int fromIndex = findIndexOf(surfaces[i]);
557+ int fromIndex = indexOf(surfaces[i]);
466558 if (fromIndex != -1) {
467559 move(fromIndex, 0);
468560 }
@@ -489,16 +581,6 @@ QVariant TopLevelWindowModel::data(const QModelIndex& index, int role) const
489581 }
490582}
491583
492−int TopLevelWindowModel::findIndexOf(const unityapi::MirSurfaceInterface *surface) const
493−{
494− for (int i=0; i<m_windowModel.count(); i++) {
495− if (m_windowModel[i].window->surface() == surface) {
496− return i;
497− }
498− }
499− return -1;
500−}
501−
502584int TopLevelWindowModel::generateId()
503585{
504586 int id = m_nextId;
@@ -700,12 +782,11 @@ void TopLevelWindowModel::onModificationsStarted()
700782
701783void TopLevelWindowModel::onModificationsEnded()
702784{
703− if (m_focusedWindowChanged) {
704− setFocusedWindow(m_newlyFocusedWindow);
785+ if (m_focusedWindowCleared) {
786+ setFocusedWindow(nullptr);
705787 }
706788 // reset
707− m_focusedWindowChanged = false;
708− m_newlyFocusedWindow = nullptr;
789+ m_focusedWindowCleared = false;
709790}
710791
711792void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
@@ -719,3 +800,54 @@ void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
719800 }
720801 }
721802}
803+
804+void TopLevelWindowModel::refreshWindows()
805+{
806+ DEBUG_MSG << "()";
807+ clear();
808+
809+ if (!m_workspace || !m_applicationManager || !m_surfaceManager) return;
810+
811+ m_surfaceManager->forEachSurfaceInWorkspace(m_workspace->workspace(), [this](unity::shell::application::MirSurfaceInterface* surface) {
812+ if (surface->parentSurface()) {
813+ // Wrap it in a Window so that we keep focusedWindow() up to date.
814+ Window *window = createWindow(surface);
815+ connect(surface, &QObject::destroyed, window, [=](){
816+ window->setSurface(nullptr);
817+ window->deleteLater();
818+ });
819+ } else {
820+ if (surface->type() == Mir::InputMethodType) {
821+ setInputMethodWindow(createWindow(surface));
822+ } else {
823+ auto *application = m_applicationManager->findApplicationWithSurface(surface);
824+ if (application) {
825+ prependSurface(surface, application);
826+ } else {
827+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
828+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
829+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
830+ Window *promptWindow = createWindow(surface);
831+ connect(surface, &QObject::destroyed, promptWindow, [=](){
832+ promptWindow->setSurface(nullptr);
833+ promptWindow->deleteLater();
834+ });
835+ }
836+ }
837+ }
838+ });
839+}
840+
841+void TopLevelWindowModel::clear()
842+{
843+ DEBUG_MSG << "()";
844+
845+ while(m_windowModel.count() > 0) {
846+ ModelEntry entry = m_windowModel.takeAt(0);
847+ disconnect(entry.window, 0, this, 0);
848+ delete entry.window;
849+ }
850+ m_allSurfaces.clear();
851+ setFocusedWindow(nullptr);
852+ m_focusedWindowCleared = false;
853+}