17 #include "TopLevelSurfaceList.h" 20 #include <unity/shell/application/ApplicationInfoInterface.h> 21 #include <unity/shell/application/MirSurfaceInterface.h> 22 #include <unity/shell/application/MirSurfaceListInterface.h> 24 #include <QMetaObject> 26 Q_LOGGING_CATEGORY(UNITY_TOPSURFACELIST,
"unity.topsurfacelist", QtDebugMsg)
28 #define DEBUG_MSG qCDebug(UNITY_TOPSURFACELIST).nospace().noquote() << __func__ 32 TopLevelSurfaceList::TopLevelSurfaceList(QObject *parent) :
33 QAbstractListModel(parent)
38 TopLevelSurfaceList::~TopLevelSurfaceList()
43 int TopLevelSurfaceList::rowCount(
const QModelIndex &parent)
const 45 return !parent.isValid() ? m_surfaceList.size() : 0;
48 QVariant TopLevelSurfaceList::data(
const QModelIndex& index,
int role)
const 50 if (index.row() < 0 || index.row() >= m_surfaceList.size())
53 if (role == SurfaceRole) {
54 MirSurfaceInterface *surface = m_surfaceList.at(index.row()).surface;
55 return QVariant::fromValue(surface);
56 }
else if (role == ApplicationRole) {
57 return QVariant::fromValue(m_surfaceList.at(index.row()).application);
58 }
else if (role == IdRole) {
59 return QVariant::fromValue(m_surfaceList.at(index.row()).
id);
65 void TopLevelSurfaceList::raise(MirSurfaceInterface *surface)
70 DEBUG_MSG <<
"(MirSurface[" << (
void*)surface <<
"])";
72 int i = indexOf(surface);
74 raiseId(m_surfaceList.at(i).id);
78 void TopLevelSurfaceList::appendPlaceholder(ApplicationInfoInterface *application)
80 DEBUG_MSG <<
"(" << application->appId() <<
")";
82 appendSurfaceHelper(
nullptr, application);
85 void TopLevelSurfaceList::appendSurface(MirSurfaceInterface *surface, ApplicationInfoInterface *application)
87 Q_ASSERT(surface !=
nullptr);
89 bool filledPlaceholder =
false;
90 for (
int i = 0; i < m_surfaceList.count() && !filledPlaceholder; ++i) {
91 ModelEntry &entry = m_surfaceList[i];
92 if (entry.application == application && entry.surface ==
nullptr) {
93 entry.surface = surface;
94 connectSurface(surface);
95 DEBUG_MSG <<
" appId=" << application->appId() <<
" surface=" << surface
96 <<
", filling out placeholder. after: " << toString();
97 Q_EMIT dataChanged(index(i) , index(i) , QVector<int>() << SurfaceRole);
98 filledPlaceholder =
true;
102 if (!filledPlaceholder) {
103 DEBUG_MSG <<
" appId=" << application->appId() <<
" surface=" << surface <<
", adding new row";
104 appendSurfaceHelper(surface, application);
108 void TopLevelSurfaceList::appendSurfaceHelper(MirSurfaceInterface *surface, ApplicationInfoInterface *application)
110 if (m_modelState == IdleState) {
111 m_modelState = InsertingState;
112 beginInsertRows(QModelIndex(), m_surfaceList.size() , m_surfaceList.size() );
114 Q_ASSERT(m_modelState == ResettingState);
118 int id = generateId();
119 m_surfaceList.append(ModelEntry(surface, application,
id));
121 connectSurface(surface);
124 if (m_modelState == InsertingState) {
126 Q_EMIT countChanged();
127 Q_EMIT listChanged();
128 m_modelState = IdleState;
131 DEBUG_MSG <<
" after " << toString();
134 void TopLevelSurfaceList::connectSurface(MirSurfaceInterface *surface)
136 connect(surface, &MirSurfaceInterface::focusedChanged,
this, [
this, surface](
bool focused){
138 this->
raise(surface);
141 connect(surface, &MirSurfaceInterface::liveChanged,
this, [
this, surface](
bool live){
143 onSurfaceDied(surface);
146 connect(surface, &QObject::destroyed,
this, [
this, surface](){ this->onSurfaceDestroyed(surface); });
149 void TopLevelSurfaceList::onSurfaceDied(MirSurfaceInterface *surface)
151 int i = indexOf(surface);
156 auto application = m_surfaceList[i].application;
159 Q_ASSERT(application->state() != ApplicationInfoInterface::Starting);
161 if (application->state() == ApplicationInfoInterface::Running) {
162 m_surfaceList[i].removeOnceSurfaceDestroyed =
true;
168 m_surfaceList[i].removeOnceSurfaceDestroyed =
false;
172 void TopLevelSurfaceList::onSurfaceDestroyed(MirSurfaceInterface *surface)
174 int i = indexOf(surface);
179 if (m_surfaceList[i].removeOnceSurfaceDestroyed) {
182 m_surfaceList[i].surface =
nullptr;
183 Q_EMIT dataChanged(index(i) , index(i) , QVector<int>() << SurfaceRole);
184 DEBUG_MSG <<
" Removed surface from entry. After: " << toString();
188 void TopLevelSurfaceList::removeAt(
int index)
190 if (m_modelState == IdleState) {
191 beginRemoveRows(QModelIndex(), index, index);
192 m_modelState = RemovingState;
194 Q_ASSERT(m_modelState == ResettingState);
198 m_surfaceList.removeAt(index);
200 if (m_modelState == RemovingState) {
202 Q_EMIT countChanged();
203 Q_EMIT listChanged();
204 m_modelState = IdleState;
207 DEBUG_MSG <<
" after " << toString();
210 int TopLevelSurfaceList::indexOf(MirSurfaceInterface *surface)
212 for (
int i = 0; i < m_surfaceList.count(); ++i) {
213 if (m_surfaceList.at(i).surface == surface) {
220 void TopLevelSurfaceList::move(
int from,
int to)
222 if (from == to)
return;
223 DEBUG_MSG <<
" from=" << from <<
" to=" << to;
225 if (from >= 0 && from < m_surfaceList.size() && to >= 0 && to < m_surfaceList.size()) {
231 Q_ASSERT(m_modelState == IdleState);
232 m_modelState = MovingState;
234 beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
235 m_surfaceList.move(from, to);
237 Q_EMIT listChanged();
239 m_modelState = IdleState;
241 DEBUG_MSG <<
" after " << toString();
247 if (index >=0 && index < m_surfaceList.count()) {
248 return m_surfaceList[index].surface;
256 if (index >=0 && index < m_surfaceList.count()) {
257 return m_surfaceList[index].application;
265 if (index >=0 && index < m_surfaceList.count()) {
266 return m_surfaceList[index].id;
274 for (
int i = 0; i < m_surfaceList.count(); ++i) {
275 if (m_surfaceList[i].
id ==
id) {
282 void TopLevelSurfaceList::doRaiseId(
int id)
284 int fromIndex = indexForId(
id);
285 if (fromIndex != -1) {
292 if (m_modelState == IdleState) {
293 DEBUG_MSG <<
"(id=" <<
id <<
") - do it now.";
296 DEBUG_MSG <<
"(id=" <<
id <<
") - Model busy (modelState=" << m_modelState <<
"). Try again in the next event loop.";
302 QMetaObject::invokeMethod(
this,
"raiseId", Qt::QueuedConnection, Q_ARG(
int,
id));
306 int TopLevelSurfaceList::generateId()
309 m_nextId = nextFreeId(m_nextId + 1);
310 Q_EMIT nextIdChanged();
314 int TopLevelSurfaceList::nextFreeId(
int candidateId)
316 if (candidateId > m_maxId) {
317 return nextFreeId(1);
319 if (indexForId(candidateId) == -1) {
323 return nextFreeId(candidateId + 1);
328 QString TopLevelSurfaceList::toString()
331 for (
int i = 0; i < m_surfaceList.count(); ++i) {
332 auto item = m_surfaceList.at(i);
334 QString itemStr = QString(
"(index=%1,appId=%2,surface=0x%3,id=%4)")
336 .arg(item.application->appId())
337 .arg((qintptr)item.surface, 0, 16)
348 void TopLevelSurfaceList::addApplication(ApplicationInfoInterface *application)
350 DEBUG_MSG <<
"(" << application->appId() <<
")";
351 Q_ASSERT(!m_applications.contains(application));
352 m_applications.append(application);
354 MirSurfaceListInterface *surfaceList = application->surfaceList();
356 if (application->state() != ApplicationInfoInterface::Stopped) {
357 if (surfaceList->count() == 0) {
358 appendPlaceholder(application);
360 for (
int i = 0; i < surfaceList->count(); ++i) {
361 appendSurface(surfaceList->get(i), application);
366 connect(surfaceList, &QAbstractItemModel::rowsInserted,
this,
367 [
this, application, surfaceList](
const QModelIndex & ,
int first,
int last)
369 for (
int i = last; i >= first; --i) {
370 this->appendSurface(surfaceList->get(i), application);
375 void TopLevelSurfaceList::removeApplication(ApplicationInfoInterface *application)
377 DEBUG_MSG <<
"(" << application->appId() <<
")";
378 Q_ASSERT(m_applications.contains(application));
380 MirSurfaceListInterface *surfaceList = application->surfaceList();
382 disconnect(surfaceList, 0,
this, 0);
384 Q_ASSERT(m_modelState == IdleState);
385 m_modelState = RemovingState;
388 while (i < m_surfaceList.count()) {
389 if (m_surfaceList.at(i).application == application) {
390 beginRemoveRows(QModelIndex(), i, i);
391 m_surfaceList.removeAt(i);
393 Q_EMIT countChanged();
394 Q_EMIT listChanged();
400 m_modelState = IdleState;
402 DEBUG_MSG <<
" after " << toString();
404 m_applications.removeAll(application);
409 return m_applicationsModel;
412 void TopLevelSurfaceList::setApplicationsModel(QAbstractListModel* value)
414 if (m_applicationsModel == value) {
418 DEBUG_MSG <<
"(" << value <<
")";
420 Q_ASSERT(m_modelState == IdleState);
421 m_modelState = ResettingState;
425 if (m_applicationsModel) {
426 m_surfaceList.clear();
427 m_applications.clear();
428 disconnect(m_applicationsModel, 0,
this, 0);
431 m_applicationsModel = value;
433 if (m_applicationsModel) {
434 findApplicationRole();
436 connect(m_applicationsModel, &QAbstractItemModel::rowsInserted,
437 this, [
this](
const QModelIndex &,
int first,
int last) {
438 for (
int i = first; i <= last; ++i) {
439 auto application = getApplicationFromModelAt(i);
440 addApplication(application);
444 connect(m_applicationsModel, &QAbstractItemModel::rowsAboutToBeRemoved,
445 this, [
this](
const QModelIndex &,
int first,
int last) {
446 for (
int i = first; i <= last; ++i) {
447 auto application = getApplicationFromModelAt(i);
448 removeApplication(application);
452 for (
int i = 0; i < m_applicationsModel->rowCount(); ++i) {
453 auto application = getApplicationFromModelAt(i);
454 addApplication(application);
459 m_modelState = IdleState;
462 ApplicationInfoInterface *TopLevelSurfaceList::getApplicationFromModelAt(
int index)
464 QModelIndex modelIndex = m_applicationsModel->index(index);
466 QVariant variant = m_applicationsModel->data(modelIndex, m_applicationRole);
469 return static_cast<ApplicationInfoInterface*
>(variant.value<QObject*>());
472 void TopLevelSurfaceList::findApplicationRole()
474 QHash<int, QByteArray> namesHash = m_applicationsModel->roleNames();
476 m_applicationRole = -1;
477 for (
auto i = namesHash.begin(); i != namesHash.end() && m_applicationRole == -1; ++i) {
478 if (i.value() ==
"application") {
479 m_applicationRole = i.key();
483 if (m_applicationRole == -1) {
484 qFatal(
"TopLevelSurfaceList: applicationsModel must have a \"application\" role.");
unity::shell::application::MirSurfaceInterface * surfaceAt(int index) const
Returns the surface at the given index.
int idAt(int index) const
Returns the unique id of the element at the given index.
int indexForId(int id) const
Returns the index where the row with the given id is located.
unity::shell::application::ApplicationInfoInterface * applicationAt(int index) const
Returns the application at the given index.
void raiseId(int id)
Raises the row with the given id to index 0.
QAbstractListModel applicationsModel
A list model of applications.