diff --git a/libtaskmanager/abstracttasksmodel.h b/libtaskmanager/abstracttasksmodel.h --- a/libtaskmanager/abstracttasksmodel.h +++ b/libtaskmanager/abstracttasksmodel.h @@ -91,6 +91,11 @@ itself. DO NOT use this for destructive actions such as closing the application. The intended use case is to try and (smartly) gather more information about the task when needed. */ + StackingOrder, /**< A window task's index in the window stacking order. Care must be + taken not to assume this index to be unique when iterating over + model contents due to the asynchronous nature of the windowing + system. */ + LastActivated, /**< The timestamp of the last time a task was the active task. */ }; Q_ENUM(AdditionalRoles) diff --git a/libtaskmanager/taskgroupingproxymodel.cpp b/libtaskmanager/taskgroupingproxymodel.cpp --- a/libtaskmanager/taskgroupingproxymodel.cpp +++ b/libtaskmanager/taskgroupingproxymodel.cpp @@ -1009,13 +1009,26 @@ } else { const bool goalState = !index.data(AbstractTasksModel::IsMaximized).toBool(); - for (int i = 0; i < rowCount(index); ++i) { - const QModelIndex &child = index.child(i, 0); + QModelIndexList inStackingOrder; - if (child.data(AbstractTasksModel::IsMaximized).toBool() != goalState) { - d->abstractTasksSourceModel->requestToggleMaximized(mapToSource(child)); - } - } + for (int i = 0; i < rowCount(index); ++i) { + const QModelIndex &child = index.child(i, 0); + + if (child.data(AbstractTasksModel::IsMaximized).toBool() != goalState) { + inStackingOrder << mapToSource(child); + } + } + + std::sort(inStackingOrder.begin(), inStackingOrder.end(), + [](const QModelIndex &a, const QModelIndex &b) { + return (a.data(AbstractTasksModel::StackingOrder).toInt() + < b.data(AbstractTasksModel::StackingOrder).toInt()); + } + ); + + for (const QModelIndex &sourceChild : inStackingOrder) { + d->abstractTasksSourceModel->requestToggleMaximized(sourceChild); + } } } diff --git a/libtaskmanager/xwindowtasksmodel.cpp b/libtaskmanager/xwindowtasksmodel.cpp --- a/libtaskmanager/xwindowtasksmodel.cpp +++ b/libtaskmanager/xwindowtasksmodel.cpp @@ -65,6 +65,8 @@ QHash appDataCache; QHash delegateGeometries; QSet usingFallbackIcon; + QHash lastActivated; + QList cachedStackingOrder; WId activeWindow = -1; KSharedConfig::Ptr rulesConfig; KDirWatch *configWatcher = nullptr; @@ -120,6 +122,8 @@ AbstractTasksModel::SkipTaskbar}); }; + cachedStackingOrder = KWindowSystem::stackingOrder(); + sycocaChangeTimer.setSingleShot(true); sycocaChangeTimer.setInterval(100); @@ -177,6 +181,7 @@ [this](WId window) { const WId oldActiveWindow = activeWindow; activeWindow = window; + lastActivated[activeWindow] = QTime::currentTime(); int row = windows.indexOf(oldActiveWindow); @@ -192,6 +197,14 @@ } ); + QObject::connect(KWindowSystem::self(), &KWindowSystem::stackingOrderChanged, q, + [this]() { + cachedStackingOrder = KWindowSystem::stackingOrder(); + q->dataChanged(q->index(0, 0), q->index(q->rowCount() - 1, 0), + QVector{StackingOrder}); + } + ); + activeWindow = KWindowSystem::activeWindow(); // Add existing windows. @@ -255,8 +268,9 @@ transientsDemandingAttention.remove(window); delete windowInfoCache.take(window); appDataCache.remove(window); - usingFallbackIcon.remove(window); delegateGeometries.remove(window); + usingFallbackIcon.remove(window); + lastActivated.remove(window); q->endRemoveRows(); } else { // Could be a transient. // Removing a transient might change the demands attention state of the leader. @@ -653,6 +667,12 @@ return d->windowInfo(window)->hasState(NET::SkipPager); } else if (role == AppPid) { return d->windowInfo(window)->pid(); + } else if (role == StackingOrder) { + return d->cachedStackingOrder.indexOf(window); + } else if (role == LastActivated) { + if (d->lastActivated.contains(window)) { + return d->lastActivated.value(window); + } } return QVariant();