diff --git a/desktoppackage/contents/activitymanager/ActivityItem.qml b/desktoppackage/contents/activitymanager/ActivityItem.qml --- a/desktoppackage/contents/activitymanager/ActivityItem.qml +++ b/desktoppackage/contents/activitymanager/ActivityItem.qml @@ -24,6 +24,7 @@ property alias title : title.text property alias icon : icon.source + property alias hasWindows : hasWindowsIndicator.visible z : current ? 10 : selected ? 5 : 0 @@ -206,12 +207,10 @@ } } - Item { + Column { id: statsBar - height: lastUsedDate.height + - // stats.height + - units.smallSpacing + height: childrenRect.height + units.smallSpacing anchors { bottom : controlBar.top @@ -223,25 +222,25 @@ bottomMargin : units.smallSpacing } + PlasmaCore.IconItem { + id : hasWindowsIndicator + source : "window-duplicate" + width : 16 + height : width + opacity : .6 + visible : false + } + Text { id: lastUsedDate color : "white" elide : Text.ElideRight opacity : .6 - // text: root.current ? - // i18nd("plasma_shell_org.kde.plasma.desktop", "Currently being used") : - // ActivitySwitcher.Backend.lastTimeUsedString(root.activityId) text: root.current ? i18nd("plasma_shell_org.kde.plasma.desktop", "Currently being used") : model.lastTimeUsedString - - anchors { - top : parent.top - left : parent.left - right : parent.right - } } // Text { diff --git a/desktoppackage/contents/activitymanager/ActivityList.qml b/desktoppackage/contents/activitymanager/ActivityList.qml --- a/desktoppackage/contents/activitymanager/ActivityList.qml +++ b/desktoppackage/contents/activitymanager/ActivityList.qml @@ -131,6 +131,7 @@ icon : model.iconSource background : model.background current : model.isCurrent + hasWindows : model.hasWindows innerPadding : 2 * units.smallSpacing stoppable : activitiesList.count > 1 diff --git a/imports/activitymanager/CMakeLists.txt b/imports/activitymanager/CMakeLists.txt --- a/imports/activitymanager/CMakeLists.txt +++ b/imports/activitymanager/CMakeLists.txt @@ -9,6 +9,7 @@ find_package (KF5GuiAddons ${KF5_DEP_VERSION} CONFIG REQUIRED) find_package (KF5KIO ${KF5_DEP_VERSION} CONFIG REQUIRED) find_package (KF5Activities ${KF5_DEP_VERSION} CONFIG REQUIRED) +find_package (KF5WindowSystem ${KF5_DEP_VERSION} CONFIG REQUIRED) find_package (X11) set_package_properties ( @@ -44,6 +45,7 @@ KF5::GuiAddons KF5::KIOCore KF5::KIOWidgets + KF5::WindowSystem ${X11_X11_LIB} ) diff --git a/imports/activitymanager/sortedactivitiesmodel.h b/imports/activitymanager/sortedactivitiesmodel.h --- a/imports/activitymanager/sortedactivitiesmodel.h +++ b/imports/activitymanager/sortedactivitiesmodel.h @@ -22,12 +22,26 @@ // Qt #include +#include //For WId +// KDE #include #include +// TODO: Remove after 5.6 #include "backport/switcheractivitiesmodel.h" +#include + +#if HAVE_X11 +#include +#else +namespace NET { + typedef int Properties; + typedef int Properties2; +} // namespace NET +#endif + class SortedActivitiesModel : public QSortFilterProxyModel { Q_OBJECT @@ -50,7 +64,9 @@ enum AdditionalRoles { LastTimeUsed = KActivitiesBackport::ActivitiesModel::UserRole, - LastTimeUsedString = KActivitiesBackport::ActivitiesModel::UserRole + 1 + LastTimeUsedString = KActivitiesBackport::ActivitiesModel::UserRole + 1, + WindowCount = KActivitiesBackport::ActivitiesModel::UserRole + 2, + HasWindows = KActivitiesBackport::ActivitiesModel::UserRole + 3 }; public Q_SLOTS: @@ -64,10 +80,15 @@ void onCurrentActivityChanged(const QString ¤tActivity); QString activityIdForRow(int row) const; + QString activityIdForIndex(const QModelIndex &index) const; int rowForActivityId(const QString &activity) const; void rowChanged(int row, const QVector &roles); + void onWindowAdded(WId window); + void onWindowRemoved(WId window); + void onWindowChanged(WId window, NET::Properties properties, NET::Properties2 properties2); + Q_SIGNALS: void sortByLastUsedTimeChanged(bool sortByLastUsedTime); void inhibitUpdatesChanged(bool inhibitUpdates); @@ -80,6 +101,12 @@ KActivitiesBackport::ActivitiesModel *m_activitiesModel; KActivities::Consumer *m_activities; + + QHash> m_activitiesWindows; + +#if HAVE_X11 + bool m_isOnX11; +#endif }; #endif // SORTED_ACTIVITY_MODEL diff --git a/imports/activitymanager/sortedactivitiesmodel.cpp b/imports/activitymanager/sortedactivitiesmodel.cpp --- a/imports/activitymanager/sortedactivitiesmodel.cpp +++ b/imports/activitymanager/sortedactivitiesmodel.cpp @@ -22,14 +22,22 @@ // Qt #include +#include // KDE #include #include #include #include #include +#define KWINDOWSYSTEM_NO_DEPRECATED + +#if HAVE_X11 +#include +#include +#endif + namespace { class BackgroundCache { @@ -171,14 +179,43 @@ , m_sortByLastUsedTime(true) , m_activitiesModel(new KActivitiesBackport::ActivitiesModel(states, this)) , m_activities(new KActivities::Consumer(this)) +#if HAVE_X11 + , m_isOnX11(QX11Info::isPlatformX11()) +#endif { setSourceModel(m_activitiesModel); setDynamicSortFilter(true); setSortRole(LastTimeUsed); sort(0, Qt::DescendingOrder); backgrounds().subscribe(this); + + +#if HAVE_X11 + if (m_isOnX11) { + const QList windows = KWindowSystem::stackingOrder(); + + for (const auto& window: windows) { + KWindowInfo info(window, NET::WMVisibleName, NET::WM2Activities); + const QStringList activities = info.activities(); + + if (activities.isEmpty() || activities.contains("00000000-0000-0000-0000-000000000000")) continue; + + for (const auto& activity: activities) { + m_activitiesWindows[activity] << window; + } + } + + connect(KWindowSystem::self(), &KWindowSystem::windowAdded, + this, &SortedActivitiesModel::onWindowAdded); + connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, + this, &SortedActivitiesModel::onWindowRemoved); + connect(KWindowSystem::self(), SIGNAL(windowChanged(WId, NET::Properties, NET::Properties2)), + this, SLOT(onWindowChanged(WId, NET::Properties, NET::Properties2))); + } +#endif + } SortedActivitiesModel::~SortedActivitiesModel() @@ -260,21 +297,21 @@ roleNames[LastTimeUsed] = "lastTimeUsed"; roleNames[LastTimeUsedString] = "lastTimeUsedString"; + roleNames[WindowCount] = "windowCount"; + roleNames[HasWindows] = "hasWindows"; return roleNames; } QVariant SortedActivitiesModel::data(const QModelIndex &index, int role) const { if (role == KActivitiesBackport::ActivitiesModel::ActivityBackground) { - const auto activity = - QSortFilterProxyModel::data(index, Qt::UserRole).toString(); + const auto activity = activityIdForIndex(index); return backgrounds().forActivity[activity]; } else if (role == LastTimeUsed || role == LastTimeUsedString) { - const auto activity = - QSortFilterProxyModel::data(index, Qt::UserRole).toString(); + const auto activity = activityIdForIndex(index); const auto time = lastUsedTime(activity); @@ -305,14 +342,29 @@ } + } else if (role == HasWindows || role == WindowCount) { + const auto activity = activityIdForIndex(index); + + if (role == HasWindows) { + return (m_activitiesWindows[activity].size() > 0); + } else { + return m_activitiesWindows[activity].size(); + } + + } else { return QSortFilterProxyModel::data(index, role); } } +QString SortedActivitiesModel::activityIdForIndex(const QModelIndex &index) const +{ + return data(index, KActivitiesBackport::ActivitiesModel::ActivityId).toString(); +} + QString SortedActivitiesModel::activityIdForRow(int row) const { - return data(index(row, 0), KActivitiesBackport::ActivitiesModel::ActivityId).toString(); + return activityIdForIndex(index(row, 0)); } int SortedActivitiesModel::rowForActivityId(const QString &activity) const @@ -368,6 +420,59 @@ } } +void SortedActivitiesModel::onWindowAdded(WId window) +{ +#if HAVE_X11 + if (!m_isOnX11) return; + + KWindowInfo info(window, 0, NET::WM2Activities); + const QStringList activities = info.activities(); + + if (activities.isEmpty() || activities.contains("00000000-0000-0000-0000-000000000000")) return; + + for (const auto& activity: activities) { + if (!m_activitiesWindows[activity].contains(window)) { + m_activitiesWindows[activity] << window; + + rowChanged(rowForActivityId(activity), + m_activitiesWindows.size() == 1 + ? QVector{WindowCount, HasWindows} + : QVector{WindowCount}); + } + } +#endif +} + +void SortedActivitiesModel::onWindowRemoved(WId window) +{ +#if HAVE_X11 + if (!m_isOnX11) return; + + for (const auto& activity: m_activitiesWindows.keys()) { + if (m_activitiesWindows[activity].contains(window)) { + m_activitiesWindows[activity].removeAll(window); + + rowChanged(rowForActivityId(activity), + m_activitiesWindows.size() == 0 + ? QVector{WindowCount, HasWindows} + : QVector{WindowCount}); + } + } +#endif +} + +void SortedActivitiesModel::onWindowChanged(WId window, NET::Properties properties, NET::Properties2 properties2) +{ +#if HAVE_X11 + if (!m_isOnX11) return; + + if (properties2 & NET::WM2Activities) { + onWindowRemoved(window); + onWindowAdded(window); + } +#endif +} + void SortedActivitiesModel::rowChanged(int row, const QVector &roles) { if (row == -1) return;