Unity 8
TopLevelWindowModel.cpp
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 "TopLevelWindowModel.h"
18 
19 // unity-api
20 #include <unity/shell/application/ApplicationInfoInterface.h>
21 #include <unity/shell/application/ApplicationManagerInterface.h>
22 #include <unity/shell/application/MirSurfaceInterface.h>
23 #include <unity/shell/application/MirSurfaceListInterface.h>
24 #include <unity/shell/application/SurfaceManagerInterface.h>
25 
26 // Qt
27 #include <QGuiApplication>
28 #include <QDebug>
29 
30 // local
31 #include "Window.h"
32 
33 Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
34 
35 #define DEBUG_MSG qCDebug(TOPLEVELWINDOWMODEL).nospace().noquote() << __func__
36 #define INFO_MSG qCInfo(TOPLEVELWINDOWMODEL).nospace().noquote() << __func__
37 
39 
40 TopLevelWindowModel::TopLevelWindowModel()
41 {
42 }
43 
44 void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInterface* value)
45 {
46  if (m_applicationManager == value) {
47  return;
48  }
49 
50  DEBUG_MSG << "(" << value << ")";
51 
52  Q_ASSERT(m_modelState == IdleState);
53  m_modelState = ResettingState;
54 
55  beginResetModel();
56 
57  if (m_applicationManager) {
58  m_windowModel.clear();
59  disconnect(m_applicationManager, 0, this, 0);
60  }
61 
62  m_applicationManager = value;
63 
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  });
72 
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  });
80 
81  for (int i = 0; i < m_applicationManager->rowCount(); ++i) {
82  auto application = m_applicationManager->get(i);
83  addApplication(application);
84  }
85  }
86 
87  endResetModel();
88  m_modelState = IdleState;
89 }
90 
91 void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *surfaceManager)
92 {
93  if (surfaceManager == m_surfaceManager) {
94  return;
95  }
96 
97  DEBUG_MSG << "(" << surfaceManager << ")";
98 
99  if (m_surfaceManager) {
100  disconnect(m_surfaceManager, 0, this, 0);
101  }
102 
103  m_surfaceManager = surfaceManager;
104 
105  if (m_surfaceManager) {
106  connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfaceCreated, this, &TopLevelWindowModel::onSurfaceCreated);
107  connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
108  connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
109  connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
110  }
111 
112  Q_EMIT surfaceManagerChanged(m_surfaceManager);
113 }
114 
115 void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
116 {
117  DEBUG_MSG << "(" << application->appId() << ")";
118 
119  if (application->state() != unityapi::ApplicationInfoInterface::Stopped && application->surfaceList()->count() == 0) {
120  prependPlaceholder(application);
121  }
122 }
123 
124 void TopLevelWindowModel::removeApplication(unityapi::ApplicationInfoInterface *application)
125 {
126  DEBUG_MSG << "(" << application->appId() << ")";
127 
128  Q_ASSERT(m_modelState == IdleState);
129 
130  int i = 0;
131  while (i < m_windowModel.count()) {
132  if (m_windowModel.at(i).application == application) {
133  deleteAt(i);
134  } else {
135  ++i;
136  }
137  }
138 }
139 
140 void TopLevelWindowModel::prependPlaceholder(unityapi::ApplicationInfoInterface *application)
141 {
142  INFO_MSG << "(" << application->appId() << ")";
143 
144  prependSurfaceHelper(nullptr, application);
145 }
146 
147 void TopLevelWindowModel::prependSurface(unityapi::MirSurfaceInterface *surface, unityapi::ApplicationInfoInterface *application)
148 {
149  Q_ASSERT(surface != nullptr);
150 
151  connectSurface(surface);
152 
153  bool filledPlaceholder = false;
154  for (int i = 0; i < m_windowModel.count() && !filledPlaceholder; ++i) {
155  ModelEntry &entry = m_windowModel[i];
156  if (entry.application == application && entry.window->surface() == nullptr) {
157  entry.window->setSurface(surface);
158  INFO_MSG << " appId=" << application->appId() << " surface=" << surface
159  << ", filling out placeholder. after: " << toString();
160  filledPlaceholder = true;
161  }
162  }
163 
164  if (!filledPlaceholder) {
165  INFO_MSG << " appId=" << application->appId() << " surface=" << surface << ", adding new row";
166  prependSurfaceHelper(surface, application);
167  }
168 }
169 
170 void TopLevelWindowModel::prependSurfaceHelper(unityapi::MirSurfaceInterface *surface, unityapi::ApplicationInfoInterface *application)
171 {
172 
173  Window *window = createWindow(surface);
174 
175  connect(window, &Window::stateChanged, this, [=](Mir::State newState) {
176  if (newState == Mir::HiddenState) {
177  // Comply, removing it from our model. Just as if it didn't exist anymore.
178  removeAt(indexForId(window->id()));
179  } else {
180  if (indexForId(window->id()) == -1) {
181  // was probably hidden before. put it back on the list
182  auto *application = m_applicationManager->findApplicationWithSurface(window->surface());
183  Q_ASSERT(application);
184  prependWindow(window, application);
185  }
186  }
187  });
188 
189  prependWindow(window, application);
190 
191  if (!surface) {
192  activateEmptyWindow(window);
193  }
194 
195  INFO_MSG << " after " << toString();
196 }
197 
198 void TopLevelWindowModel::prependWindow(Window *window, unityapi::ApplicationInfoInterface *application)
199 {
200  if (m_modelState == IdleState) {
201  m_modelState = InsertingState;
202  beginInsertRows(QModelIndex(), 0 /*first*/, 0 /*last*/);
203  } else {
204  Q_ASSERT(m_modelState == ResettingState);
205  // No point in signaling anything if we're resetting the whole model
206  }
207 
208  m_windowModel.prepend(ModelEntry(window, application));
209 
210  if (m_modelState == InsertingState) {
211  endInsertRows();
212  Q_EMIT countChanged();
213  Q_EMIT listChanged();
214  m_modelState = IdleState;
215  }
216 }
217 
218 void TopLevelWindowModel::connectWindow(Window *window)
219 {
220  connect(window, &Window::focusRequested, this, [this, window]() {
221  if (!window->surface()) {
222  activateEmptyWindow(window);
223  }
224  });
225 
226  connect(window, &Window::focusedChanged, this, [this, window](bool focused) {
227  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
231  if (focused) {
232  Q_ASSERT(m_newlyFocusedWindow == nullptr);
233  m_focusedWindowChanged = true;
234  m_newlyFocusedWindow = window;
235  } else if (m_focusedWindow == window) {
236  m_focusedWindowChanged = true;
237  } else {
238  // don't clear the focused window if you were not there in the first place
239  // happens when a filled window gets replaced with an empty one (no surface) as the focused window.
240  }
241  }
242  });
243 
244  connect(window, &Window::closeRequested, this, [this, window]() {
245  if (!window->surface()) {
246  // do things ourselves as miral doesn't know about this window
247  int id = window->id();
248  int index = indexForId(id);
249  bool focusOther = false;
250  Q_ASSERT(index >= 0);
251  if (window->focused()) {
252  focusOther = true;
253  }
254  m_windowModel[index].application->close();
255  if (focusOther) {
256  activateTopMostWindowWithoutId(id);
257  }
258  }
259  });
260 
261  connect(window, &Window::emptyWindowActivated, this, [this, window]() {
262  activateEmptyWindow(window);
263  });
264 
265  connect(window, &Window::liveChanged, this, [this, window](bool isAlive) {
266  if (!isAlive && window->state() == Mir::HiddenState) {
267  // Hidden windows are not in the model. So just delete it right away.
268  delete window;
269  }
270  });
271 }
272 
273 void TopLevelWindowModel::activateEmptyWindow(Window *window)
274 {
275  Q_ASSERT(!window->surface());
276  DEBUG_MSG << "(" << window << ")";
277 
278  // miral doesn't know about empty windows (ie, windows that are not backed up by MirSurfaces)
279  // So we have to activate them ourselves (instead of asking SurfaceManager to do it for us).
280 
281  window->setFocused(true);
282  raiseId(window->id());
283  Window *previousWindow = m_focusedWindow;
284  setFocusedWindow(window);
285  if (previousWindow && previousWindow->surface() && previousWindow->surface()->focused()) {
286  m_surfaceManager->activate(nullptr);
287  }
288 }
289 
290 void TopLevelWindowModel::connectSurface(unityapi::MirSurfaceInterface *surface)
291 {
292  connect(surface, &unityapi::MirSurfaceInterface::liveChanged, this, [this, surface](bool live){
293  if (!live) {
294  onSurfaceDied(surface);
295  }
296  });
297  connect(surface, &QObject::destroyed, this, [this, surface](){ this->onSurfaceDestroyed(surface); });
298 }
299 
300 void TopLevelWindowModel::onSurfaceDied(unityapi::MirSurfaceInterface *surface)
301 {
302  if (surface->type() == Mir::InputMethodType) {
303  removeInputMethodWindow();
304  return;
305  }
306 
307  int i = indexOf(surface);
308  if (i == -1) {
309  return;
310  }
311 
312  auto application = m_windowModel[i].application;
313 
314  // can't be starting if it already has a surface
315  Q_ASSERT(application->state() != unityapi::ApplicationInfoInterface::Starting);
316 
317  if (application->state() == unityapi::ApplicationInfoInterface::Running) {
318  m_windowModel[i].removeOnceSurfaceDestroyed = true;
319  } else {
320  // assume it got killed by the out-of-memory daemon.
321  //
322  // So leave entry in the model and only remove its surface, so shell can display a screenshot
323  // in its place.
324  m_windowModel[i].removeOnceSurfaceDestroyed = false;
325  }
326 }
327 
328 void TopLevelWindowModel::onSurfaceDestroyed(unityapi::MirSurfaceInterface *surface)
329 {
330  int i = indexOf(surface);
331  if (i == -1) {
332  return;
333  }
334 
335  if (m_windowModel[i].removeOnceSurfaceDestroyed) {
336  deleteAt(i);
337  } else {
338  auto window = m_windowModel[i].window;
339  window->setSurface(nullptr);
340  window->setFocused(false);
341  INFO_MSG << " Removed surface from entry. After: " << toString();
342  }
343 }
344 
345 Window *TopLevelWindowModel::createWindow(unityapi::MirSurfaceInterface *surface)
346 {
347  int id = generateId();
348  Window *qmlWindow = new Window(id, this);
349  connectWindow(qmlWindow);
350  if (surface) {
351  qmlWindow->setSurface(surface);
352  }
353  return qmlWindow;
354 }
355 
356 void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
357 {
358  DEBUG_MSG << "(" << surface << ")";
359 
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));
371  } 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);
379  prependSurface(surface, application);
380  });
381  } else {
382  prependSurface(surface, application);
383  }
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  });
393  }
394  }
395  }
396 }
397 
398 void TopLevelWindowModel::deleteAt(int index)
399 {
400  auto window = m_windowModel[index].window;
401 
402  removeAt(index);
403 
404  window->setSurface(nullptr);
405 
406  delete window;
407 }
408 
409 void TopLevelWindowModel::removeAt(int index)
410 {
411  if (m_modelState == IdleState) {
412  beginRemoveRows(QModelIndex(), index, index);
413  m_modelState = RemovingState;
414  } else {
415  Q_ASSERT(m_modelState == ResettingState);
416  // No point in signaling anything if we're resetting the whole model
417  }
418 
419  auto window = m_windowModel[index].window;
420 
421  if (!window->surface()) {
422  window->setFocused(false);
423  }
424 
425  m_windowModel.removeAt(index);
426 
427  if (m_modelState == RemovingState) {
428  endRemoveRows();
429  Q_EMIT countChanged();
430  Q_EMIT listChanged();
431  m_modelState = IdleState;
432  }
433 
434  if (m_focusedWindow == window) {
435  setFocusedWindow(nullptr);
436  }
437 
438  INFO_MSG << " after " << toString();
439 }
440 
441 void TopLevelWindowModel::setInputMethodWindow(Window *window)
442 {
443  if (m_inputMethodWindow) {
444  qWarning("Multiple Input Method Surfaces created, removing the old one!");
445  delete m_inputMethodWindow;
446  }
447  m_inputMethodWindow = window;
448  Q_EMIT inputMethodSurfaceChanged(m_inputMethodWindow->surface());
449 }
450 
451 void TopLevelWindowModel::removeInputMethodWindow()
452 {
453  if (m_inputMethodWindow) {
454  delete m_inputMethodWindow;
455  m_inputMethodWindow = nullptr;
456  Q_EMIT inputMethodSurfaceChanged(nullptr);
457  }
458 }
459 
460 void TopLevelWindowModel::onSurfacesRaised(const QVector<unityapi::MirSurfaceInterface*> &surfaces)
461 {
462  DEBUG_MSG << "(" << surfaces << ")";
463  const int raiseCount = surfaces.size();
464  for (int i = 0; i < raiseCount; i++) {
465  int fromIndex = findIndexOf(surfaces[i]);
466  if (fromIndex != -1) {
467  move(fromIndex, 0);
468  }
469  }
470 }
471 
472 int TopLevelWindowModel::rowCount(const QModelIndex &/*parent*/) const
473 {
474  return m_windowModel.count();
475 }
476 
477 QVariant TopLevelWindowModel::data(const QModelIndex& index, int role) const
478 {
479  if (index.row() < 0 || index.row() >= m_windowModel.size())
480  return QVariant();
481 
482  if (role == WindowRole) {
483  Window *window = m_windowModel.at(index.row()).window;
484  return QVariant::fromValue(window);
485  } else if (role == ApplicationRole) {
486  return QVariant::fromValue(m_windowModel.at(index.row()).application);
487  } else {
488  return QVariant();
489  }
490 }
491 
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 
502 int TopLevelWindowModel::generateId()
503 {
504  int id = m_nextId;
505  m_nextId = nextFreeId(nextId(id), id);
506  return id;
507 }
508 
509 int TopLevelWindowModel::nextId(int id) const
510 {
511  if (id == m_maxId) {
512  return id = 1;
513  } else {
514  return id + 1;
515  }
516 }
517 
518 int TopLevelWindowModel::nextFreeId(int candidateId, const int latestId)
519 {
520  int firstCandidateId = candidateId;
521 
522  while (indexForId(candidateId) != -1 || candidateId == latestId) {
523  candidateId = nextId(candidateId);
524 
525  if (candidateId == firstCandidateId) {
526  qFatal("TopLevelWindowModel: run out of window ids.");
527  }
528  }
529 
530  return candidateId;
531 }
532 
533 QString TopLevelWindowModel::toString()
534 {
535  QString str;
536  for (int i = 0; i < m_windowModel.count(); ++i) {
537  auto item = m_windowModel.at(i);
538 
539  QString itemStr = QString("(index=%1,appId=%2,surface=0x%3,id=%4)")
540  .arg(QString::number(i),
541  item.application->appId(),
542  QString::number((qintptr)item.window->surface(), 16),
543  QString::number(item.window->id()));
544 
545  if (i > 0) {
546  str.append(",");
547  }
548  str.append(itemStr);
549  }
550  return str;
551 }
552 
553 int TopLevelWindowModel::indexOf(unityapi::MirSurfaceInterface *surface)
554 {
555  for (int i = 0; i < m_windowModel.count(); ++i) {
556  if (m_windowModel.at(i).window->surface() == surface) {
557  return i;
558  }
559  }
560  return -1;
561 }
562 
564 {
565  for (int i = 0; i < m_windowModel.count(); ++i) {
566  if (m_windowModel[i].window->id() == id) {
567  return i;
568  }
569  }
570  return -1;
571 }
572 
574 {
575  if (index >=0 && index < m_windowModel.count()) {
576  return m_windowModel[index].window;
577  } else {
578  return nullptr;
579  }
580 }
581 
582 unityapi::MirSurfaceInterface *TopLevelWindowModel::surfaceAt(int index) const
583 {
584  if (index >=0 && index < m_windowModel.count()) {
585  return m_windowModel[index].window->surface();
586  } else {
587  return nullptr;
588  }
589 }
590 
591 unityapi::ApplicationInfoInterface *TopLevelWindowModel::applicationAt(int index) const
592 {
593  if (index >=0 && index < m_windowModel.count()) {
594  return m_windowModel[index].application;
595  } else {
596  return nullptr;
597  }
598 }
599 
600 int TopLevelWindowModel::idAt(int index) const
601 {
602  if (index >=0 && index < m_windowModel.count()) {
603  return m_windowModel[index].window->id();
604  } else {
605  return 0;
606  }
607 }
608 
610 {
611  if (m_modelState == IdleState) {
612  DEBUG_MSG << "(id=" << id << ") - do it now.";
613  doRaiseId(id);
614  } else {
615  DEBUG_MSG << "(id=" << id << ") - Model busy (modelState=" << m_modelState << "). Try again in the next event loop.";
616  // The model has just signalled some change. If we have a Repeater responding to this update, it will get nuts
617  // if we perform yet another model change straight away.
618  //
619  // A bad sympton of this problem is a Repeater.itemAt(index) call returning null event though Repeater.count says
620  // the index is definitely within bounds.
621  QMetaObject::invokeMethod(this, "raiseId", Qt::QueuedConnection, Q_ARG(int, id));
622  }
623 }
624 
625 void TopLevelWindowModel::doRaiseId(int id)
626 {
627  int fromIndex = indexForId(id);
628  // can't raise something that doesn't exist or that it's already on top
629  if (fromIndex != -1 && fromIndex != 0) {
630  auto surface = m_windowModel[fromIndex].window->surface();
631  if (surface) {
632  m_surfaceManager->raise(surface);
633  } else {
634  // move it ourselves. Since there's no mir::scene::Surface/miral::Window, there's nothing
635  // miral can do about it.
636  move(fromIndex, 0);
637  }
638  }
639 }
640 
641 void TopLevelWindowModel::setFocusedWindow(Window *window)
642 {
643  if (window != m_focusedWindow) {
644  INFO_MSG << "(" << window << ")";
645 
646  Window* previousWindow = m_focusedWindow;
647 
648  m_focusedWindow = window;
649  Q_EMIT focusedWindowChanged(m_focusedWindow);
650 
651  if (previousWindow && previousWindow->focused() && !previousWindow->surface()) {
652  // do it ourselves. miral doesn't know about this window
653  previousWindow->setFocused(false);
654  }
655  }
656 }
657 
658 unityapi::MirSurfaceInterface* TopLevelWindowModel::inputMethodSurface() const
659 {
660  return m_inputMethodWindow ? m_inputMethodWindow->surface() : nullptr;
661 }
662 
664 {
665  return m_focusedWindow;
666 }
667 
668 void TopLevelWindowModel::move(int from, int to)
669 {
670  if (from == to) return;
671  DEBUG_MSG << " from=" << from << " to=" << to;
672 
673  if (from >= 0 && from < m_windowModel.size() && to >= 0 && to < m_windowModel.size()) {
674  QModelIndex parent;
675  /* When moving an item down, the destination index needs to be incremented
676  by one, as explained in the documentation:
677  http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
678 
679  Q_ASSERT(m_modelState == IdleState);
680  m_modelState = MovingState;
681 
682  beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
683 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
684  const auto &window = m_windowModel.takeAt(from);
685  m_windowModel.insert(to, window);
686 #else
687  m_windowModel.move(from, to);
688 #endif
689  endMoveRows();
690 
691  Q_EMIT listChanged();
692  m_modelState = IdleState;
693 
694  INFO_MSG << " after " << toString();
695  }
696 }
697 void TopLevelWindowModel::onModificationsStarted()
698 {
699 }
700 
701 void TopLevelWindowModel::onModificationsEnded()
702 {
703  if (m_focusedWindowChanged) {
704  setFocusedWindow(m_newlyFocusedWindow);
705  }
706  // reset
707  m_focusedWindowChanged = false;
708  m_newlyFocusedWindow = nullptr;
709 }
710 
711 void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
712 {
713  DEBUG_MSG << "(" << forbiddenId << ")";
714 
715  for (int i = 0; i < m_windowModel.count(); ++i) {
716  Window *window = m_windowModel[i].window;
717  if (window->id() != forbiddenId) {
718  window->activate();
719  }
720  }
721 }
Q_INVOKABLE Window * windowAt(int index) const
Returns the window at the given index.
A slightly higher concept than MirSurface.
Definition: Window.h:47
void focusRequested()
Emitted when focus for this window is requested by an external party.
Mir::State state
State of the surface.
Definition: Window.h:64
void listChanged()
Emitted when the list changes.
Q_INVOKABLE int indexForId(int id) const
Returns the index where the row with the given id is located.
void activate()
Focuses and raises the window.
Definition: Window.cpp:136
unity::shell::application::MirSurfaceInterface surface
Surface backing up this window It might be null if a surface hasn&#39;t been created yet (application is ...
Definition: Window.h:92
bool focused
Whether the surface is focused.
Definition: Window.h:71
int id
A unique identifier for this window. Useful for telling windows apart in a list model as they get mov...
Definition: Window.h:84
unity::shell::application::MirSurfaceInterface inputMethodSurface
The input method surface, if any.
Window focusedWindow
The currently focused window, if any.
Q_INVOKABLE unity::shell::application::MirSurfaceInterface * surfaceAt(int index) const
Returns the surface at the given index.
Q_INVOKABLE unity::shell::application::ApplicationInfoInterface * applicationAt(int index) const
Returns the application at the given index.
Q_INVOKABLE int idAt(int index) const
Returns the unique id of the element at the given index.
Q_INVOKABLE void raiseId(int id)
Raises the row with the given id to the top of the window stack (index == count-1) ...