summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Hein <[email protected]>2018-12-18 16:46:31 +0900
committerEike Hein <[email protected]>2018-12-18 16:46:49 +0900
commit52d760c57c2433a25c2c3b375ae8a51328271d00 (patch)
treec321575458c52ffe0a520c39a36fdba7ec5e0c91
parent743e5583ced054b507267bf4451b29ebe9e7ea52 (diff)
Implement support for virtual desktops on Wayland
Summary: Includes, among other things: * A refactoring towards supporting more than one desktop per window, for an eventual virtual desktops / activities merge * A scheme for process-internal window ids on Wayland as DND payload so DND in and to the Pager works in the shell * Implemented various previously missing behavior in WaylandTasksModel such as implicit moves of windows to the current desktop on various actions * Expanded VirtualDesktopInfo API so the Pager can better abstract over windowing systems * Implicit internal sharing of VirtualDesktopInfo since there are many more instances now * Various cleanups Still missing: * Fixing the VirtualDesktops data role in the grouping proxy * The protocol doesn't have desktop creation/destruction yet, so some of the related logic is still missing * Some FIXME TODOs in the code when I was unhappy with the current KWayland API This code is largely untested and subject to change. Depends on D12820 and relates to T4457. Reviewers: mart, mvourlakos, davidedmundson Reviewed By: davidedmundson Subscribers: alexde, anthonyfieroni, zzag, ngraham, abetts, plasma-devel Tags: #plasma Maniphest Tasks: T4457 Differential Revision: https://phabricator.kde.org/D13745
-rw-r--r--libtaskmanager/CMakeLists.txt1
-rw-r--r--libtaskmanager/abstracttasksmodel.cpp9
-rw-r--r--libtaskmanager/abstracttasksmodel.h36
-rw-r--r--libtaskmanager/abstracttasksmodeliface.h30
-rw-r--r--libtaskmanager/abstracttasksproxymodeliface.cpp19
-rw-r--r--libtaskmanager/abstracttasksproxymodeliface.h30
-rw-r--r--libtaskmanager/launchertasksmodel.cpp2
-rw-r--r--libtaskmanager/startuptasksmodel.cpp6
-rw-r--r--libtaskmanager/taskfilterproxymodel.cpp23
-rw-r--r--libtaskmanager/taskfilterproxymodel.h19
-rw-r--r--libtaskmanager/taskgroupingproxymodel.cpp85
-rw-r--r--libtaskmanager/taskgroupingproxymodel.h30
-rw-r--r--libtaskmanager/tasksmodel.cpp101
-rw-r--r--libtaskmanager/tasksmodel.h47
-rw-r--r--libtaskmanager/virtualdesktopinfo.cpp425
-rw-r--r--libtaskmanager/virtualdesktopinfo.h78
-rw-r--r--libtaskmanager/waylandtasksmodel.cpp216
-rw-r--r--libtaskmanager/waylandtasksmodel.h40
-rw-r--r--libtaskmanager/windowtasksmodel.cpp1
-rw-r--r--libtaskmanager/windowtasksmodel.h3
-rw-r--r--libtaskmanager/xwindowtasksmodel.cpp61
-rw-r--r--libtaskmanager/xwindowtasksmodel.h31
22 files changed, 1065 insertions, 228 deletions
diff --git a/libtaskmanager/CMakeLists.txt b/libtaskmanager/CMakeLists.txt
index c92567f..d65ec43 100644
--- a/libtaskmanager/CMakeLists.txt
+++ b/libtaskmanager/CMakeLists.txt
@@ -46,6 +46,7 @@ target_link_libraries(taskmanager
Qt5::DBus
KF5::Activities
KF5::ConfigCore
+ KF5::I18n
KF5::KIOCore
KF5::KIOWidgets
KF5::ProcessCore
diff --git a/libtaskmanager/abstracttasksmodel.cpp b/libtaskmanager/abstracttasksmodel.cpp
index 4952e0b..7d5e62c 100644
--- a/libtaskmanager/abstracttasksmodel.cpp
+++ b/libtaskmanager/abstracttasksmodel.cpp
@@ -113,10 +113,15 @@ void AbstractTasksModel::requestToggleShaded(const QModelIndex &index)
Q_UNUSED(index)
}
-void AbstractTasksModel::requestVirtualDesktop(const QModelIndex &index, qint32 desktop)
+void AbstractTasksModel::requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops)
+{
+ Q_UNUSED(index)
+ Q_UNUSED(desktops)
+}
+
+void AbstractTasksModel::requestNewVirtualDesktop(const QModelIndex &index)
{
Q_UNUSED(index)
- Q_UNUSED(desktop)
}
void AbstractTasksModel::requestActivities(const QModelIndex &index, const QStringList &activities)
diff --git a/libtaskmanager/abstracttasksmodel.h b/libtaskmanager/abstracttasksmodel.h
index ad12655..320a2e8 100644
--- a/libtaskmanager/abstracttasksmodel.h
+++ b/libtaskmanager/abstracttasksmodel.h
@@ -52,7 +52,7 @@ public:
GenericName, /**< Generic application name. */
LauncherUrl, /**< URL that can be used to launch this application (.desktop or executable). */
LauncherUrlWithoutIcon, /**< Special path to get a launcher URL while skipping fallback icon encoding. Used as speed optimization. */
- LegacyWinIdList, /**< X11 window ids. Stopgap until we have something better. */
+ WinIdList, /**< NOTE: On Wayland, these ids are only useful within the same process. On X11, they are global window ids. */
MimeType, /**< MIME type for this task (window, window group), needed for DND. */
MimeData, /**< Data for MimeType. */
IsWindow, /**< This is a window task. */
@@ -76,8 +76,8 @@ public:
IsFullScreen, /**< Task (i.e. window) is fullscreen. */
IsShadeable, /**< requestToggleShade (see below) available. */
IsShaded, /**< Task (i.e. window) is shaded. */
- IsVirtualDesktopChangeable, /**< requestVirtualDesktop (see below) available. */
- VirtualDesktop, /**< Virtual desktop for the task (i.e. window). */
+ IsVirtualDesktopsChangeable, /**< requestVirtualDesktop (see below) available. */
+ VirtualDesktops, /**< Virtual desktops for the task (i.e. window). */
IsOnAllVirtualDesktops, /**< Task is on all virtual desktops. */
Geometry, /**< The task's geometry (i.e. the window's). */
ScreenGeometry, /**< Screen geometry for the task (i.e. the window's screen). */
@@ -239,18 +239,32 @@ public:
void requestToggleShaded(const QModelIndex &index) override;
/**
- * Request moving the task at the given index to the specified virtual
- * desktop.
+ * Request entering the window at the given index on the specified virtual desktops,
+ * leaving any other desktops.
*
- * This is meant for tasks that have an associated window, and may be
- * a no-op when there is no window.
+ * On Wayland, virtual desktop ids are QStrings. On X11, they are uint >0.
*
- * This base implementation does nothing.
+ * An empty list has a special meaning: The window is entered on all virtual desktops
+ * in the session.
*
- * @param index An index in this tasks model.
- * @param desktop A virtual desktop number.
+ * On X11, a window can only be on one or all virtual desktops. Therefore, only the
+ * first list entry is actually used.
+ *
+ * On X11, the id 0 has a special meaning: The window is entered on all virtual
+ * desktops in the session.
+ *
+ * @param index An index in this window tasks model.
+ * @param desktops A list of virtual desktop ids.
+ **/
+ void requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops) override;
+
+ /**
+ * Request entering the window at the given index on a new virtual desktop,
+ * which is created in response to this request.
+ *
+ * @param index An index in this window tasks model.
**/
- void requestVirtualDesktop(const QModelIndex &index, qint32 desktop) override;
+ void requestNewVirtualDesktop(const QModelIndex &index) override;
/**
* Request moving the task at the given index to the specified activities.
diff --git a/libtaskmanager/abstracttasksmodeliface.h b/libtaskmanager/abstracttasksmodeliface.h
index 7881101..d4d6fc8 100644
--- a/libtaskmanager/abstracttasksmodeliface.h
+++ b/libtaskmanager/abstracttasksmodeliface.h
@@ -157,16 +157,32 @@ public:
virtual void requestToggleShaded(const QModelIndex &index) = 0;
/**
- * Request moving the task at the given index to the specified virtual
- * desktop.
+ * Request entering the window at the given index on the specified virtual desktops,
+ * leaving any other desktops.
*
- * This is meant for tasks that have an associated window, and may be
- * a no-op when there is no window.
+ * On Wayland, virtual desktop ids are QStrings. On X11, they are uint >0.
*
- * @param index An index in this tasks model.
- * @param desktop A virtual desktop number.
+ * An empty list has a special meaning: The window is entered on all virtual desktops
+ * in the session.
+ *
+ * On X11, a window can only be on one or all virtual desktops. Therefore, only the
+ * first list entry is actually used.
+ *
+ * On X11, the id 0 has a special meaning: The window is entered on all virtual
+ * desktops in the session.
+ *
+ * @param index An index in this window tasks model.
+ * @param desktops A list of virtual desktop ids.
+ **/
+ virtual void requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops) = 0;
+
+ /**
+ * Request entering the window at the given index on a new virtual desktop,
+ * which is created in response to this request.
+ *
+ * @param index An index in this window tasks model.
**/
- virtual void requestVirtualDesktop(const QModelIndex &index, qint32 desktop = -1) = 0;
+ virtual void requestNewVirtualDesktop(const QModelIndex &index) = 0;
/**
* Request moving the task at the given index to the specified virtual
diff --git a/libtaskmanager/abstracttasksproxymodeliface.cpp b/libtaskmanager/abstracttasksproxymodeliface.cpp
index 2f85d08..2ece293 100644
--- a/libtaskmanager/abstracttasksproxymodeliface.cpp
+++ b/libtaskmanager/abstracttasksproxymodeliface.cpp
@@ -193,7 +193,7 @@ void AbstractTasksProxyModelIface::requestToggleShaded(const QModelIndex &index)
}
}
-void AbstractTasksProxyModelIface::requestVirtualDesktop(const QModelIndex &index, qint32 desktop)
+void AbstractTasksProxyModelIface::requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops)
{
if (!index.isValid()) {
return;
@@ -203,7 +203,21 @@ void AbstractTasksProxyModelIface::requestVirtualDesktop(const QModelIndex &inde
const AbstractTasksModelIface *m = dynamic_cast<const AbstractTasksModelIface *>(sourceIndex.model());
if (m) {
- const_cast<AbstractTasksModelIface *>(m)->requestVirtualDesktop(sourceIndex, desktop);
+ const_cast<AbstractTasksModelIface *>(m)->requestVirtualDesktops(sourceIndex, desktops);
+ }
+}
+
+void AbstractTasksProxyModelIface::requestNewVirtualDesktop(const QModelIndex &index)
+{
+ if (!index.isValid()) {
+ return;
+ }
+
+ const QModelIndex &sourceIndex = mapIfaceToSource(index);
+ const AbstractTasksModelIface *m = dynamic_cast<const AbstractTasksModelIface *>(sourceIndex.model());
+
+ if (m) {
+ const_cast<AbstractTasksModelIface *>(m)->requestNewVirtualDesktop(sourceIndex);
}
}
@@ -221,7 +235,6 @@ void AbstractTasksProxyModelIface::requestActivities(const QModelIndex &index, c
}
}
-
void AbstractTasksProxyModelIface::requestPublishDelegateGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate)
{
if (!index.isValid()) {
diff --git a/libtaskmanager/abstracttasksproxymodeliface.h b/libtaskmanager/abstracttasksproxymodeliface.h
index 84467b9..810329b 100644
--- a/libtaskmanager/abstracttasksproxymodeliface.h
+++ b/libtaskmanager/abstracttasksproxymodeliface.h
@@ -158,16 +158,32 @@ public:
void requestToggleShaded(const QModelIndex &index) override;
/**
- * Request moving the task at the given index to the specified virtual
- * desktop.
+ * Request entering the window at the given index on the specified virtual desktops,
+ * leaving any other desktops.
*
- * This is meant for tasks that have an associated window, and may be
- * a no-op when there is no window.
+ * On Wayland, virtual desktop ids are QStrings. On X11, they are uint >0.
*
- * @param index An index in this tasks model.
- * @param desktop A virtual desktop number.
+ * An empty list has a special meaning: The window is entered on all virtual desktops
+ * in the session.
+ *
+ * On X11, a window can only be on one or all virtual desktops. Therefore, only the
+ * first list entry is actually used.
+ *
+ * On X11, the id 0 has a special meaning: The window is entered on all virtual
+ * desktops in the session.
+ *
+ * @param index An index in this window tasks model.
+ * @param desktops A list of virtual desktop ids.
+ **/
+ void requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops) override;
+
+ /**
+ * Request entering the window at the given index on a new virtual desktop,
+ * which is created in response to this request.
+ *
+ * @param index An index in this window tasks model.
**/
- void requestVirtualDesktop(const QModelIndex &index, qint32 desktop = -1) override;
+ void requestNewVirtualDesktop(const QModelIndex &index) override;
/**
* Request moving the task at the given index to the specified activities.
diff --git a/libtaskmanager/launchertasksmodel.cpp b/libtaskmanager/launchertasksmodel.cpp
index defcd8a..b31e9b7 100644
--- a/libtaskmanager/launchertasksmodel.cpp
+++ b/libtaskmanager/launchertasksmodel.cpp
@@ -351,6 +351,8 @@ QVariant LauncherTasksModel::data(const QModelIndex &index, int role) const
return url;
} else if (role == IsLauncher) {
return true;
+ } else if (role == IsVirtualDesktopsChangeable) {
+ return false;
} else if (role == IsOnAllVirtualDesktops) {
return true;
} else if (role == Activities) {
diff --git a/libtaskmanager/startuptasksmodel.cpp b/libtaskmanager/startuptasksmodel.cpp
index 595ad7c..6a5401c 100644
--- a/libtaskmanager/startuptasksmodel.cpp
+++ b/libtaskmanager/startuptasksmodel.cpp
@@ -265,8 +265,10 @@ QVariant StartupTasksModel::data(const QModelIndex &index, int role) const
return d->launcherUrls.value(id);
} else if (role == IsStartup) {
return true;
- } else if (role == VirtualDesktop) {
- return data.desktop();
+ } else if (role == IsVirtualDesktopsChangeable) {
+ return false;
+ } else if (role == VirtualDesktops) {
+ return QVariantList() << QVariant(data.desktop());
} else if (role == IsOnAllVirtualDesktops) {
return (data.desktop() == 0);
}
diff --git a/libtaskmanager/taskfilterproxymodel.cpp b/libtaskmanager/taskfilterproxymodel.cpp
index 49afe55..071c1a2 100644
--- a/libtaskmanager/taskfilterproxymodel.cpp
+++ b/libtaskmanager/taskfilterproxymodel.cpp
@@ -33,7 +33,7 @@ public:
AbstractTasksModelIface *sourceTasksModel = nullptr;
- uint virtualDesktop = 0;
+ QVariant virtualDesktop;
QRect screenGeometry;
QString activity;
@@ -68,15 +68,15 @@ void TaskFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
QSortFilterProxyModel::setSourceModel(sourceModel);
}
-uint TaskFilterProxyModel::virtualDesktop() const
+QVariant TaskFilterProxyModel::virtualDesktop() const
{
return d->virtualDesktop;
}
-void TaskFilterProxyModel::setVirtualDesktop(uint virtualDesktop)
+void TaskFilterProxyModel::setVirtualDesktop(const QVariant &desktop)
{
- if (d->virtualDesktop != virtualDesktop) {
- d->virtualDesktop = virtualDesktop;
+ if (d->virtualDesktop != desktop) {
+ d->virtualDesktop = desktop;
if (d->filterByVirtualDesktop) {
invalidateFilter();
@@ -258,18 +258,13 @@ bool TaskFilterProxyModel::acceptsRow(int sourceRow) const
}
// Filter by virtual desktop.
- if (d->filterByVirtualDesktop && d->virtualDesktop != 0) {
+ if (d->filterByVirtualDesktop && !d->virtualDesktop.isNull()) {
if (!sourceIdx.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool()
&& (!d->demandingAttentionSkipsFilters || !sourceIdx.data(AbstractTasksModel::IsDemandingAttention).toBool())) {
- const QVariant &virtualDesktop = sourceIdx.data(AbstractTasksModel::VirtualDesktop);
+ const QVariantList &virtualDesktops = sourceIdx.data(AbstractTasksModel::VirtualDesktops).toList();
- if (!virtualDesktop.isNull()) {
- bool ok = false;
- const uint i = virtualDesktop.toUInt(&ok);
-
- if (ok && i != d->virtualDesktop) {
- return false;
- }
+ if (!virtualDesktops.isEmpty() && !virtualDesktops.contains(d->virtualDesktop)) {
+ return false;
}
}
}
diff --git a/libtaskmanager/taskfilterproxymodel.h b/libtaskmanager/taskfilterproxymodel.h
index b54bad5..62e119d 100644
--- a/libtaskmanager/taskfilterproxymodel.h
+++ b/libtaskmanager/taskfilterproxymodel.h
@@ -45,7 +45,7 @@ class TASKMANAGER_EXPORT TaskFilterProxyModel : public QSortFilterProxyModel, pu
{
Q_OBJECT
- Q_PROPERTY(int virtualDesktop READ virtualDesktop WRITE setVirtualDesktop NOTIFY virtualDesktopChanged)
+ Q_PROPERTY(QVariant virtualDesktop READ virtualDesktop WRITE setVirtualDesktop NOTIFY virtualDesktopChanged)
Q_PROPERTY(QRect screenGeometry READ screenGeometry WRITE setScreenGeometry NOTIFY screenGeometryChanged)
Q_PROPERTY(QString activity READ activity WRITE setActivity NOTIFY activityChanged)
@@ -65,26 +65,25 @@ public:
void setSourceModel(QAbstractItemModel *sourceModel) override;
/**
- * The number of the virtual desktop used in filtering by virtual
- * desktop. Usually set to the number of the current virtual desktop.
- * Defaults to @c 0 (virtual desktop numbers start at 1).
+ * The id of the virtual desktop used in filtering by virtual
+ * desktop. Usually set to the id of the current virtual desktop.
+ * Defaults to empty.
*
* @see setVirtualDesktop
* @returns the number of the virtual desktop used in filtering.
**/
- uint virtualDesktop() const;
+ QVariant virtualDesktop() const;
/**
- * Set the number of the virtual desktop to use in filtering by virtual
+ * Set the id of the virtual desktop to use in filtering by virtual
* desktop.
*
- * If set to 0 (virtual desktop numbers start at 1), filtering by virtual
- * desktop is disabled.
+ * If set to an empty id, filtering by virtual desktop is disabled.
*
* @see virtualDesktop
- * @param virtualDesktop A virtual desktop number.
+ * @param desktop A virtual desktop id (QString on Wayland; uint >0 on X11).
**/
- void setVirtualDesktop(uint virtualDesktop);
+ void setVirtualDesktop(const QVariant &desktop = QVariant());
/**
* The geometry of the screen used in filtering by screen. Defaults
diff --git a/libtaskmanager/taskgroupingproxymodel.cpp b/libtaskmanager/taskgroupingproxymodel.cpp
index ab84978..8ef6322 100644
--- a/libtaskmanager/taskgroupingproxymodel.cpp
+++ b/libtaskmanager/taskgroupingproxymodel.cpp
@@ -671,16 +671,15 @@ QVariant TaskGroupingProxyModel::data(const QModelIndex &proxyIndex, int role) c
}
return appName;
- } else if (role == AbstractTasksModel::LegacyWinIdList) {
+ } else if (role == AbstractTasksModel::WinIdList) {
QVariantList winIds;
for (int i = 0; i < rowCount(proxyIndex); ++i) {
- winIds.append(proxyIndex.child(i, 0).data(AbstractTasksModel::LegacyWinIdList).toList());
+ winIds.append(proxyIndex.child(i, 0).data(AbstractTasksModel::WinIdList).toList());
}
return winIds;
} else if (role == AbstractTasksModel::MimeType) {
- // FIXME: Legacy X11 stuff, but it's what we have for now.
return QStringLiteral("windowsystem/multiple-winids");
} else if (role == AbstractTasksModel::MimeData) {
// FIXME TODO: Implement.
@@ -719,22 +718,17 @@ QVariant TaskGroupingProxyModel::data(const QModelIndex &proxyIndex, int role) c
return d->all(proxyIndex, AbstractTasksModel::IsShadeable);
} else if (role == AbstractTasksModel::IsShaded) {
return d->all(proxyIndex, AbstractTasksModel::IsShaded);
- } else if (role == AbstractTasksModel::IsVirtualDesktopChangeable) {
- return d->all(proxyIndex, AbstractTasksModel::IsVirtualDesktopChangeable);
- } else if (role == AbstractTasksModel::VirtualDesktop) {
- // Returns the lowest virtual desktop id among all children of the
- // group.
- int virtualDesktop = INT_MAX;
+ } else if (role == AbstractTasksModel::IsVirtualDesktopsChangeable) {
+ return d->all(proxyIndex, AbstractTasksModel::IsVirtualDesktopsChangeable);
+ } else if (role == AbstractTasksModel::VirtualDesktops) {
+ QStringList desktops;
for (int i = 0; i < rowCount(proxyIndex); ++i) {
- const int childVirtualDesktop = proxyIndex.child(i, 0).data(AbstractTasksModel::VirtualDesktop).toInt();
-
- if (childVirtualDesktop < virtualDesktop) {
- virtualDesktop = childVirtualDesktop;
- }
+ desktops.append(proxyIndex.child(i, 0).data(AbstractTasksModel::VirtualDesktops).toStringList());
}
- return virtualDesktop;
+ desktops.removeDuplicates();
+ return desktops;
} else if (role == AbstractTasksModel::ScreenGeometry) {
// TODO: Nothing needs this for now and it would add complexity to
// make it a list; skip it until needed. Once it is, do it similarly
@@ -1109,24 +1103,53 @@ void TaskGroupingProxyModel::requestToggleShaded(const QModelIndex &index)
}
}
-void TaskGroupingProxyModel::requestVirtualDesktop(const QModelIndex &index, qint32 desktop)
+void TaskGroupingProxyModel::requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops)
{
if (!d->abstractTasksSourceModel || !index.isValid() || index.model() != this) {
return;
}
if (index.parent().isValid() || !d->isGroup(index.row())) {
- d->abstractTasksSourceModel->requestVirtualDesktop(mapToSource(index), desktop);
+ d->abstractTasksSourceModel->requestVirtualDesktops(mapToSource(index), desktops);
} else {
- const int row = index.row();
+ QVector<QModelIndex> groupChildren;
- for (int i = (rowCount(index) - 1); i >= 1; --i) {
- const QModelIndex &sourceChild = mapToSource(index.child(i, 0));
- d->abstractTasksSourceModel->requestVirtualDesktop(sourceChild, desktop);
+ const int childCount = rowCount(index);
+
+ groupChildren.reserve(childCount);
+
+ for (int i = (childCount - 1); i >= 0; --i) {
+ groupChildren.append(mapToSource(index.child(i, 0)));
+ }
+
+ for (const QModelIndex &idx : groupChildren) {
+ d->abstractTasksSourceModel->requestVirtualDesktops(idx, desktops);
+ }
+ }
+}
+
+void TaskGroupingProxyModel::requestNewVirtualDesktop(const QModelIndex &index)
+{
+ if (!d->abstractTasksSourceModel || !index.isValid() || index.model() != this) {
+ return;
+ }
+
+ if (index.parent().isValid() || !d->isGroup(index.row())) {
+ d->abstractTasksSourceModel->requestNewVirtualDesktop(mapToSource(index));
+ } else {
+ QVector<QModelIndex> groupChildren;
+
+ const int childCount = rowCount(index);
+
+ groupChildren.reserve(childCount);
+
+ for (int i = (childCount - 1); i >= 0; --i) {
+ groupChildren.append(mapToSource(index.child(i, 0)));
}
- d->abstractTasksSourceModel->requestVirtualDesktop(mapToSource(TaskGroupingProxyModel::index(row, 0)),
- desktop);
+ for (const QModelIndex &idx : groupChildren) {
+ d->abstractTasksSourceModel->requestNewVirtualDesktop(idx);
+ }
}
}
@@ -1139,15 +1162,19 @@ void TaskGroupingProxyModel::requestActivities(const QModelIndex &index, const Q
if (index.parent().isValid() || !d->isGroup(index.row())) {
d->abstractTasksSourceModel->requestActivities(mapToSource(index), activities);
} else {
- const int row = index.row();
+ QVector<QModelIndex> groupChildren;
- for (int i = (rowCount(index) - 1); i >= 1; --i) {
- const QModelIndex &sourceChild = mapToSource(index.child(i, 0));
- d->abstractTasksSourceModel->requestActivities(sourceChild, activities);
+ const int childCount = rowCount(index);
+
+ groupChildren.reserve(childCount);
+
+ for (int i = (childCount - 1); i >= 0; --i) {
+ groupChildren.append(mapToSource(index.child(i, 0)));
}
- d->abstractTasksSourceModel->requestActivities(mapToSource(TaskGroupingProxyModel::index(row, 0)),
- activities);
+ for (const QModelIndex &idx : groupChildren) {
+ d->abstractTasksSourceModel->requestActivities(idx, activities);
+ }
}
}
diff --git a/libtaskmanager/taskgroupingproxymodel.h b/libtaskmanager/taskgroupingproxymodel.h
index 8d0c363..6089bc5 100644
--- a/libtaskmanager/taskgroupingproxymodel.h
+++ b/libtaskmanager/taskgroupingproxymodel.h
@@ -314,16 +314,32 @@ public:
void requestToggleShaded(const QModelIndex &index) override;
/**
- * Request moving the task at the given index to the specified virtual
- * desktop.
+ * Request entering the window at the given index on the specified virtual desktops,
+ * leaving any other desktops.
*
- * This is meant for tasks that have an associated window, and may be
- * a no-op when there is no window.
+ * On Wayland, virtual desktop ids are QStrings. On X11, they are uint >0.
*
- * @param index An index in this tasks model.
- * @param desktop A virtual desktop number.
+ * An empty list has a special meaning: The window is entered on all virtual desktops
+ * in the session.
+ *
+ * On X11, a window can only be on one or all virtual desktops. Therefore, only the
+ * first list entry is actually used.
+ *
+ * On X11, the id 0 has a special meaning: The window is entered on all virtual
+ * desktops in the session.
+ *
+ * @param index An index in this window tasks model.
+ * @param desktops A list of virtual desktop ids.
+ **/
+ void requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops) override;
+
+ /**
+ * Request entering the window at the given index on a new virtual desktop,
+ * which is created in response to this request.
+ *
+ * @param index An index in this window tasks model.
**/
- void requestVirtualDesktop(const QModelIndex &index, qint32 desktop) override;
+ void requestNewVirtualDesktop(const QModelIndex &index) override;
/**
* Request moving the task at the given index to the specified activities.
diff --git a/libtaskmanager/tasksmodel.cpp b/libtaskmanager/tasksmodel.cpp
index ffb43d5..261b371 100644
--- a/libtaskmanager/tasksmodel.cpp
+++ b/libtaskmanager/tasksmodel.cpp
@@ -25,6 +25,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "taskfilterproxymodel.h"
#include "taskgroupingproxymodel.h"
#include "tasktools.h"
+#include "virtualdesktopinfo.h"
#include "launchertasksmodel.h"
#include "startuptasksmodel.h"
@@ -61,9 +62,6 @@ public:
bool anyTaskDemandsAttention = false;
int launcherCount = 0;
- int virtualDesktop = -1;
- int screen = -1;
- QString activity;
SortMode sortMode = SortAlpha;
bool separateLaunchers = true;
@@ -75,6 +73,8 @@ public:
QVector<int> sortRowInsertQueue;
bool sortRowInsertQueueStale = false;
QHash<QString, int> activityTaskCounts;
+ static VirtualDesktopInfo *virtualDesktopInfo;
+ static int virtualDesktopInfoUsers;
static ActivityInfo* activityInfo;
static int activityInfoUsers;
@@ -122,6 +122,8 @@ private:
int TasksModel::Private::instanceCount = 0;
WindowTasksModel* TasksModel::Private::windowTasksModel = nullptr;
StartupTasksModel* TasksModel::Private::startupTasksModel = nullptr;
+VirtualDesktopInfo* TasksModel::Private::virtualDesktopInfo = nullptr;
+int TasksModel::Private::virtualDesktopInfoUsers = 0;
ActivityInfo* TasksModel::Private::activityInfo = nullptr;
int TasksModel::Private::activityInfoUsers = 0;
@@ -144,6 +146,8 @@ TasksModel::Private::~Private()
windowTasksModel = nullptr;
delete startupTasksModel;
startupTasksModel = nullptr;
+ delete virtualDesktopInfo;
+ virtualDesktopInfo = nullptr;
delete activityInfo;
activityInfo = nullptr;
}
@@ -877,21 +881,50 @@ bool TasksModel::Private::lessThan(const QModelIndex &left, const QModelIndex &r
// Sort other cases by sort mode.
switch (sortMode) {
case SortVirtualDesktop: {
- const QVariant &leftDesktopVariant = left.data(AbstractTasksModel::VirtualDesktop);
- bool leftOk = false;
- const int leftDesktop = leftDesktopVariant.toInt(&leftOk);
+ const bool leftAll = left.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool();
+ const bool rightAll = right.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool();
- const QVariant &rightDesktopVariant = right.data(AbstractTasksModel::VirtualDesktop);
- bool rightOk = false;
- const int rightDesktop = rightDesktopVariant.toInt(&rightOk);
+ if (leftAll && !rightAll) {
+ return true;
+ } else if (rightAll && !leftAll) {
+ return true;
+ }
+
+ const QVariantList &leftDesktops = left.data(AbstractTasksModel::VirtualDesktops).toList();
+ QVariant leftDesktop;
+ int leftDesktopPos = virtualDesktopInfo->numberOfDesktops();
+
+ for (const QVariant &desktop : leftDesktops) {
+ const int desktopPos = virtualDesktopInfo->position(desktop);
+
+ if (desktopPos < leftDesktopPos) {
+ leftDesktop = desktop;
+ leftDesktopPos = desktopPos;
+ }
+ }
- if (leftOk && rightOk && (leftDesktop != rightDesktop)) {
- return (leftDesktop < rightDesktop);
- } else if (leftOk && !rightOk) {
+ const QVariantList &rightDesktops = right.data(AbstractTasksModel::VirtualDesktops).toList();
+ QVariant rightDesktop;
+ int rightDesktopPos = virtualDesktopInfo->numberOfDesktops();
+
+ for (const QVariant &desktop : rightDesktops) {
+ const int desktopPos = virtualDesktopInfo->position(desktop);
+
+ if (desktopPos < rightDesktopPos) {
+ rightDesktop = desktop;
+ rightDesktopPos = desktopPos;
+ }
+ }
+
+ if (!leftDesktop.isNull() && !rightDesktop.isNull() && (leftDesktop != rightDesktop)) {
+ return (virtualDesktopInfo->position(leftDesktop) < virtualDesktopInfo->position(rightDesktop));
+ } else if (!leftDesktop.isNull() && rightDesktop.isNull()) {
return false;
- } else if (!leftOk && rightOk) {
+ } else if (leftDesktop.isNull() && !rightDesktop.isNull()) {
return true;
}
+
+ return false;
}
case SortActivity: {
// updateActivityTaskCounts() counts the number of window tasks on each
@@ -934,6 +967,8 @@ bool TasksModel::Private::lessThan(const QModelIndex &left, const QModelIndex &r
}
}
// Fall through to source order if sorting is disabled or manual, or alphabetical by app name otherwise.
+ // This marker comment makes gcc/clang happy:
+ // fall through
default: {
if (sortMode == SortDisabled) {
return (left.row() < right.row());
@@ -1039,11 +1074,11 @@ QVariant TasksModel::data(const QModelIndex &proxyIndex, int role) const
return false;
}
- } else if (rowCount(proxyIndex) && role == AbstractTasksModel::LegacyWinIdList) {
+ } else if (rowCount(proxyIndex) && role == AbstractTasksModel::WinIdList) {
QVariantList winIds;
for (int i = 0; i < rowCount(proxyIndex); ++i) {
- winIds.append(proxyIndex.child(i, 0).data(AbstractTasksModel::LegacyWinIdList).toList());
+ winIds.append(proxyIndex.child(i, 0).data(AbstractTasksModel::WinIdList).toList());
}
return winIds;
@@ -1082,14 +1117,14 @@ bool TasksModel::anyTaskDemandsAttention() const
return d->anyTaskDemandsAttention;
}
-int TasksModel::virtualDesktop() const
+QVariant TasksModel::virtualDesktop() const
{
return d->filterProxyModel->virtualDesktop();
}
-void TasksModel::setVirtualDesktop(int virtualDesktop)
+void TasksModel::setVirtualDesktop(const QVariant &desktop)
{
- d->filterProxyModel->setVirtualDesktop(virtualDesktop);
+ d->filterProxyModel->setVirtualDesktop(desktop);
}
QRect TasksModel::screenGeometry() const
@@ -1166,6 +1201,25 @@ void TasksModel::setSortMode(SortMode mode)
d->sortedPreFilterRows.clear();
}
+ if (mode == SortVirtualDesktop) {
+ if (!d->virtualDesktopInfo) {
+ d->virtualDesktopInfo = new VirtualDesktopInfo();
+ }
+
+ ++d->virtualDesktopInfoUsers;
+
+ setSortRole(AbstractTasksModel::VirtualDesktops);
+ } else if (d->sortMode == SortVirtualDesktop) {
+ --d->virtualDesktopInfoUsers;
+
+ if (!d->virtualDesktopInfoUsers) {
+ delete d->virtualDesktopInfo;
+ d->virtualDesktopInfo = nullptr;
+ }
+
+ setSortRole(Qt::DisplayRole);
+ }
+
if (mode == SortActivity) {
if (!d->activityInfo) {
d->activityInfo = new ActivityInfo();
@@ -1505,10 +1559,17 @@ void TasksModel::requestToggleShaded(const QModelIndex &index)
}
}
-void TasksModel::requestVirtualDesktop(const QModelIndex &index, qint32 desktop)
+void TasksModel::requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops)
+{
+ if (index.isValid() && index.model() == this) {
+ d->abstractTasksSourceModel->requestVirtualDesktops(mapToSource(index), desktops);
+ }
+}
+
+void TasksModel::requestNewVirtualDesktop(const QModelIndex &index)
{
if (index.isValid() && index.model() == this) {
- d->abstractTasksSourceModel->requestVirtualDesktop(mapToSource(index), desktop);
+ d->abstractTasksSourceModel->requestNewVirtualDesktop(mapToSource(index));
}
}
diff --git a/libtaskmanager/tasksmodel.h b/libtaskmanager/tasksmodel.h
index fef0924..1b71e6e 100644
--- a/libtaskmanager/tasksmodel.h
+++ b/libtaskmanager/tasksmodel.h
@@ -66,7 +66,7 @@ class TASKMANAGER_EXPORT TasksModel : public QSortFilterProxyModel, public Abstr
Q_PROPERTY(bool anyTaskDemandsAttention READ anyTaskDemandsAttention NOTIFY anyTaskDemandsAttentionChanged)
- Q_PROPERTY(int virtualDesktop READ virtualDesktop WRITE setVirtualDesktop NOTIFY virtualDesktopChanged)
+ Q_PROPERTY(QVariant virtualDesktop READ virtualDesktop WRITE setVirtualDesktop NOTIFY virtualDesktopChanged)
Q_PROPERTY(QRect screenGeometry READ screenGeometry WRITE setScreenGeometry NOTIFY screenGeometryChanged)
Q_PROPERTY(QString activity READ activity WRITE setActivity NOTIFY activityChanged)
@@ -150,25 +150,25 @@ public:
bool anyTaskDemandsAttention() const;
/**
- * The number of the virtual desktop used in filtering by virtual
- * desktop. Usually set to the number of the current virtual desktop.
- * Defaults to @c -1.
+ * The id of the virtual desktop used in filtering by virtual
+ * desktop. Usually set to the id of the current virtual desktop.
+ * Defaults to empty.
*
* @see setVirtualDesktop
* @returns the number of the virtual desktop used in filtering.
**/
- int virtualDesktop() const;
+ QVariant virtualDesktop() const;
/**
- * Set the number of the virtual desktop to use in filtering by virtual
+ * Set the id of the virtual desktop to use in filtering by virtual
* desktop.
*
- * If set to @c -1, filtering by virtual desktop is disabled.
+ * If set to an empty id, filtering by virtual desktop is disabled.
*
* @see virtualDesktop
- * @param virtualDesktop A virtual desktop number.
+ * @param desktop A virtual desktop id (QString on Wayland; uint >0 on X11).
**/
- void setVirtualDesktop(int virtualDesktop);
+ void setVirtualDesktop(const QVariant &desktop = QVariant());
/**
* The geometry of the screen used in filtering by screen. Defaults
@@ -712,16 +712,31 @@ public:
Q_INVOKABLE void requestToggleShaded(const QModelIndex &index) override;
/**
- * Request moving the task at the given index to the specified virtual
- * desktop.
+ * Request entering the window at the given index on the specified virtual desktops.
*
- * This is meant for tasks that have an associated window, and may be
- * a no-op when there is no window.
+ * On Wayland, virtual desktop ids are QStrings. On X11, they are uint >0.
*
- * @param index An index in this tasks model.
- * @param desktop A virtual desktop number.
+ * An empty list has a special meaning: The window is entered on all virtual desktops
+ * in the session.
+ *
+ * On X11, a window can only be on one or all virtual desktops. Therefore, only the
+ * first list entry is actually used.
+ *
+ * On X11, the id 0 has a special meaning: The window is entered on all virtual
+ * desktops in the session.
+ *
+ * @param index An index in this window tasks model.
+ * @param desktops A list of virtual desktop ids.
+ **/
+ Q_INVOKABLE void requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops) override;
+
+ /**
+ * Request entering the window at the given index on a new virtual desktop,
+ * which is created in response to this request.
+ *
+ * @param index An index in this window tasks model.
**/
- Q_INVOKABLE void requestVirtualDesktop(const QModelIndex &index, qint32 desktop) override;
+ Q_INVOKABLE void requestNewVirtualDesktop(const QModelIndex &index) override;
/**
* Request moving the task at the given index to the specified activities.
diff --git a/libtaskmanager/virtualdesktopinfo.cpp b/libtaskmanager/virtualdesktopinfo.cpp
index 3087855..2cc659c 100644
--- a/libtaskmanager/virtualdesktopinfo.cpp
+++ b/libtaskmanager/virtualdesktopinfo.cpp
@@ -20,6 +20,10 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "virtualdesktopinfo.h"
+#include <KLocalizedString>
+#include <KWayland/Client/connection_thread.h>
+#include <KWayland/Client/plasmavirtualdesktop.h>
+#include <KWayland/Client/registry.h>
#include <KWindowSystem>
#include <QDBusConnection>
@@ -33,42 +37,105 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
namespace TaskManager
{
+class Q_DECL_HIDDEN VirtualDesktopInfo::Private : public QObject
+{
+ Q_OBJECT
-VirtualDesktopInfo::VirtualDesktopInfo(QObject *parent) : QObject(parent)
+public:
+ Private(VirtualDesktopInfo *q);
+ virtual ~Private() {}
+
+ uint refCount = 1;
+
+ virtual void init() = 0;
+ virtual QVariant currentDesktop() const = 0;
+ virtual int numberOfDesktops() const = 0;
+ virtual QVariantList desktopIds() const = 0;
+ virtual QStringList desktopNames() const = 0;
+ virtual quint32 position(const QVariant &desktop) const = 0;
+ virtual int desktopLayoutRows() const = 0;
+ virtual void requestActivate(const QVariant &desktop) = 0;
+ virtual void requestCreateDesktop(quint32 position) = 0;
+ virtual void requestRemoveDesktop(quint32 position) = 0;
+
+Q_SIGNALS:
+ void currentDesktopChanged() const;
+ void numberOfDesktopsChanged() const;
+ void desktopIdsChanged() const;
+ void desktopNamesChanged() const;
+ void desktopLayoutRowsChanged() const;
+
+protected:
+ VirtualDesktopInfo *q;
+};
+
+VirtualDesktopInfo::Private::Private(VirtualDesktopInfo *q)
+ : q(q)
+{
+}
+
+#if HAVE_X11
+class Q_DECL_HIDDEN VirtualDesktopInfo::XWindowPrivate : public VirtualDesktopInfo::Private
+{
+public:
+ XWindowPrivate(VirtualDesktopInfo *q);
+
+ void init() override;
+ QVariant currentDesktop() const override;
+ int numberOfDesktops() const override;
+ QVariantList desktopIds() const override;
+ QStringList desktopNames() const override;
+ quint32 position(const QVariant &desktop) const override;
+ int desktopLayoutRows() const override;
+ void requestActivate(const QVariant &desktop) override;
+ void requestCreateDesktop(quint32 position) override;
+ void requestRemoveDesktop(quint32 position) override;
+};
+
+VirtualDesktopInfo::XWindowPrivate::XWindowPrivate(VirtualDesktopInfo *q)
+ : VirtualDesktopInfo::Private(q)
+{
+ init();
+}
+
+void VirtualDesktopInfo::XWindowPrivate::init()
{
connect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged,
- this, &VirtualDesktopInfo::currentDesktopChanged);
+ this, &VirtualDesktopInfo::XWindowPrivate::currentDesktopChanged);
connect(KWindowSystem::self(), &KWindowSystem::numberOfDesktopsChanged,
- this, &VirtualDesktopInfo::numberOfDesktopsChanged);
+ this, &VirtualDesktopInfo::XWindowPrivate::numberOfDesktopsChanged);
connect(KWindowSystem::self(), &KWindowSystem::desktopNamesChanged,
- this, &VirtualDesktopInfo::desktopNamesChanged);
+ this, &VirtualDesktopInfo::XWindowPrivate::desktopNamesChanged);
-#if HAVE_X11
- if (KWindowSystem::isPlatformX11()) {
- QDBusConnection dbus = QDBusConnection::sessionBus();
- dbus.connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"),
- this, SIGNAL(desktopLayoutRowsChanged()));
- }
-#endif
+ QDBusConnection dbus = QDBusConnection::sessionBus();
+ dbus.connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"),
+ this, SIGNAL(desktopLayoutRowsChanged()));
}
-VirtualDesktopInfo::~VirtualDesktopInfo()
+QVariant VirtualDesktopInfo::XWindowPrivate::currentDesktop() const
{
+ return KWindowSystem::currentDesktop();
}
-int VirtualDesktopInfo::currentDesktop() const
+int VirtualDesktopInfo::XWindowPrivate::numberOfDesktops() const
{
- return KWindowSystem::currentDesktop();
+ return KWindowSystem::numberOfDesktops();
}
-int VirtualDesktopInfo::numberOfDesktops() const
+QVariantList VirtualDesktopInfo::XWindowPrivate::desktopIds() const
{
- return KWindowSystem::numberOfDesktops();
+ QVariantList ids;
+
+ for (int i = 1; i <= KWindowSystem::numberOfDesktops(); ++i) {
+ ids << i;
+ }
+
+ return ids;
}
-QStringList VirtualDesktopInfo::desktopNames() const
+QStringList VirtualDesktopInfo::XWindowPrivate::desktopNames() const
{
QStringList names;
@@ -80,16 +147,330 @@ QStringList VirtualDesktopInfo::desktopNames() const
return names;
}
-int VirtualDesktopInfo::desktopLayoutRows() const
+quint32 VirtualDesktopInfo::XWindowPrivate::position(const QVariant &desktop) const
{
-#if HAVE_X11
- if (KWindowSystem::isPlatformX11()) {
- const NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames, NET::WM2DesktopLayout);
- return info.desktopLayoutColumnsRows().height();
+ bool ok = false;
+
+ const quint32 desktopNumber = desktop.toUInt(&ok);
+
+ if (!ok) {
+ return -1;
+ }
+
+ return desktopNumber;
+}
+
+int VirtualDesktopInfo::XWindowPrivate::desktopLayoutRows() const
+{
+ const NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames, NET::WM2DesktopLayout);
+ return info.desktopLayoutColumnsRows().height();
+}
+
+void VirtualDesktopInfo::XWindowPrivate::requestActivate(const QVariant &desktop)
+{
+ bool ok = false;
+ const int desktopNumber = desktop.toInt(&ok);
+
+ // Virtual desktop numbers start at 1.
+ if (ok && desktopNumber > 0 && desktopNumber <= KWindowSystem::numberOfDesktops()) {
+ KWindowSystem::setCurrentDesktop(desktopNumber);
}
+}
+
+void VirtualDesktopInfo::XWindowPrivate::requestCreateDesktop(quint32 position)
+{
+ Q_UNUSED(position)
+
+ NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops);
+ info.setNumberOfDesktops(info.numberOfDesktops() + 1);
+}
+
+void VirtualDesktopInfo::XWindowPrivate::requestRemoveDesktop(quint32 position)
+{
+ Q_UNUSED(position)
+
+ NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops);
+
+ if (info.numberOfDesktops() > 1) {
+ info.setNumberOfDesktops(info.numberOfDesktops() - 1);
+ }
+}
#endif
+class Q_DECL_HIDDEN VirtualDesktopInfo::WaylandPrivate : public VirtualDesktopInfo::Private
+{
+public:
+ WaylandPrivate(VirtualDesktopInfo *q);
+
+ QVariant currentVirtualDesktop;
+ QStringList virtualDesktops;
+ KWayland::Client::PlasmaVirtualDesktopManagement *virtualDesktopManagement = nullptr;
+
+ void init() override;
+ void addDesktop(const QString &id, quint32 position);
+ QVariant currentDesktop() const override;
+ int numberOfDesktops() const override;
+ QVariantList desktopIds() const override;
+ QStringList desktopNames() const override;
+ quint32 position(const QVariant &desktop) const override;
+ int desktopLayoutRows() const override;
+ void requestActivate(const QVariant &desktop) override;
+ void requestCreateDesktop(quint32 position) override;
+ void requestRemoveDesktop(quint32 position) override;
+};
+
+VirtualDesktopInfo::WaylandPrivate::WaylandPrivate(VirtualDesktopInfo *q)
+ : VirtualDesktopInfo::Private(q)
+{
+ init();
+}
+
+void VirtualDesktopInfo::WaylandPrivate::init()
+{
+ if (!KWindowSystem::isPlatformWayland()) {
+ return;
+ }
+
+ KWayland::Client::ConnectionThread *connection = KWayland::Client::ConnectionThread::fromApplication(q);
+
+ if (!connection) {
+ return;
+ }
+
+ KWayland::Client::Registry *registry = new KWayland::Client::Registry(q);
+ registry->create(connection);
+
+ QObject::connect(registry, &KWayland::Client::Registry::plasmaVirtualDesktopManagementAnnounced,
+ [this, registry] (quint32 name, quint32 version) {
+ virtualDesktopManagement = registry->createPlasmaVirtualDesktopManagement(name, version, q);
+
+ const QList<KWayland::Client::PlasmaVirtualDesktop *> &desktops = virtualDesktopManagement->desktops();
+
+ /* FIXME: PlasmaVirtualDesktopManagement doesn't have this ...?
+ QObject::connect(virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::interfaceAboutToBeReleased, q,
+ [this] {
+ virtualDesktops.clear();
+ emit numberOfDesktopsChanged();
+ emit currentDesktopChanged();
+ emit desktopIdsChanged();
+ emit desktopNamesChanged();
+ emit desktopLayoutRowsChanged();
+ }
+ );
+ */
+
+ QObject::connect(virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopCreated, q,
+ [this](const QString &id, quint32 position) {
+ addDesktop(id, position);
+ }
+ );
+
+ QObject::connect(virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopRemoved, q,
+ [this](const QString &id) {
+ virtualDesktops.removeOne(id);
+
+ emit numberOfDesktopsChanged();
+ emit desktopIdsChanged();
+ emit desktopNamesChanged();
+
+ if (currentVirtualDesktop == id) {
+ currentVirtualDesktop.clear();
+ emit currentDesktopChanged();
+ }
+ }
+ );
+ }
+ );
+
+ registry->setup();
+}
+
+void VirtualDesktopInfo::WaylandPrivate::addDesktop(const QString &id, quint32 position)
+{
+ if (virtualDesktops.indexOf(id) != -1) {
+ return;
+ }
+
+ virtualDesktops.insert(position, id);
+
+ emit numberOfDesktopsChanged();
+ emit desktopIdsChanged();
+ emit desktopNamesChanged();
+
+ const KWayland::Client::PlasmaVirtualDesktop *desktop = virtualDesktopManagement->getVirtualDesktop(id);
+
+ QObject::connect(desktop, &KWayland::Client::PlasmaVirtualDesktop::activated, q,
+ [desktop, this]() {
+ currentVirtualDesktop = desktop->id();
+ emit currentDesktopChanged();
+ }
+ );
+
+ if (desktop->isActive()) {
+ currentVirtualDesktop = id;
+ emit currentDesktopChanged();
+ }
+}
+
+QVariant VirtualDesktopInfo::WaylandPrivate::currentDesktop() const
+{
+ return currentVirtualDesktop;
+}
+
+int VirtualDesktopInfo::WaylandPrivate::numberOfDesktops() const
+{
+ return virtualDesktops.count();
+}
+
+quint32 VirtualDesktopInfo::WaylandPrivate::position(const QVariant &desktop) const
+{
+ return virtualDesktops.indexOf(desktop.toString());
+}
+
+QVariantList VirtualDesktopInfo::WaylandPrivate::desktopIds() const
+{
+ QVariantList ids;
+
+ foreach (const QString &id, virtualDesktops) {
+ ids << id;
+ }
+
+ return ids;
+}
+
+QStringList VirtualDesktopInfo::WaylandPrivate::desktopNames() const
+{
+ QStringList names;
+
+ foreach(const QString &id, virtualDesktops) {
+ const KWayland::Client::PlasmaVirtualDesktop *desktop = virtualDesktopManagement->getVirtualDesktop(id);
+
+ if (desktop) {
+ names << desktop->name();
+ }
+ }
+
+ return names;
+}
+
+int VirtualDesktopInfo::WaylandPrivate::desktopLayoutRows() const
+{
+ // TODO FIXME: We don't have virtual desktop layout information in the Wayland
+ // protocol yet.
return 0;
}
+void VirtualDesktopInfo::WaylandPrivate::requestActivate(const QVariant &desktop)
+{
+ KWayland::Client::PlasmaVirtualDesktop *desktopObj = virtualDesktopManagement->getVirtualDesktop(desktop.toString());
+
+ if (desktopObj) {
+ desktopObj->requestActivate();
+ }
+}
+
+void VirtualDesktopInfo::WaylandPrivate::requestCreateDesktop(quint32 position)
+{
+ virtualDesktopManagement->requestCreateVirtualDesktop(i18n("New Desktop"), position);
+}
+
+void VirtualDesktopInfo::WaylandPrivate::requestRemoveDesktop(quint32 position)
+{
+ if (virtualDesktops.count() == 1) {
+ return;
+ }
+
+ if (position > ((quint32)virtualDesktops.count() - 1)) {
+ return;
+ }
+
+ virtualDesktopManagement->requestRemoveVirtualDesktop(virtualDesktops.at(position));
}
+
+VirtualDesktopInfo::Private* VirtualDesktopInfo::d = nullptr;
+
+VirtualDesktopInfo::VirtualDesktopInfo(QObject *parent) : QObject(parent)
+{
+ if (!d) {
+ #if HAVE_X11
+ if (KWindowSystem::isPlatformX11()) {
+ d = new VirtualDesktopInfo::XWindowPrivate(this);
+ } else
+ #endif
+ {
+ d = new VirtualDesktopInfo::WaylandPrivate(this);
+ }
+ } else {
+ ++d->refCount;
+ }
+
+ connect(d, &VirtualDesktopInfo::Private::currentDesktopChanged,
+ this, &VirtualDesktopInfo::currentDesktopChanged);
+ connect(d, &VirtualDesktopInfo::Private::numberOfDesktopsChanged,
+ this, &VirtualDesktopInfo::numberOfDesktopsChanged);
+ connect(d, &VirtualDesktopInfo::Private::desktopIdsChanged,
+ this, &VirtualDesktopInfo::desktopIdsChanged);
+ connect(d, &VirtualDesktopInfo::Private::desktopNamesChanged,
+ this, &VirtualDesktopInfo::desktopNamesChanged);
+ connect(d, &VirtualDesktopInfo::Private::desktopLayoutRowsChanged,
+ this, &VirtualDesktopInfo::desktopLayoutRowsChanged);
+}
+
+VirtualDesktopInfo::~VirtualDesktopInfo()
+{
+ --d->refCount;
+
+ if (!d->refCount) {
+ delete d;
+ d = nullptr;
+ }
+}
+
+QVariant VirtualDesktopInfo::currentDesktop() const
+{
+ return d->currentDesktop();
+}
+
+int VirtualDesktopInfo::numberOfDesktops() const
+{
+ return d->numberOfDesktops();
+}
+
+QVariantList VirtualDesktopInfo::desktopIds() const
+{
+ return d->desktopIds();
+}
+
+QStringList VirtualDesktopInfo::desktopNames() const
+{
+ return d->desktopNames();
+}
+
+quint32 VirtualDesktopInfo::position(const QVariant &desktop) const
+{
+ return d->position(desktop);
+}
+
+int VirtualDesktopInfo::desktopLayoutRows() const
+{
+ return d->desktopLayoutRows();
+}
+
+void VirtualDesktopInfo::requestActivate(const QVariant &desktop)
+{
+ d->requestActivate(desktop);
+}
+
+void VirtualDesktopInfo::requestCreateDesktop(quint32 position)
+{
+ return d->requestCreateDesktop(position);
+}
+
+void VirtualDesktopInfo::requestRemoveDesktop(quint32 position)
+{
+ return d->requestRemoveDesktop(position);
+}
+
+}
+
+#include "virtualdesktopinfo.moc"
diff --git a/libtaskmanager/virtualdesktopinfo.h b/libtaskmanager/virtualdesktopinfo.h
index dd52310..2dc6ceb 100644
--- a/libtaskmanager/virtualdesktopinfo.h
+++ b/libtaskmanager/virtualdesktopinfo.h
@@ -29,17 +29,12 @@ namespace TaskManager
{
/**
- * @short Provides basic virtual desktop information.
+ * @short Provides basic virtual desktop information. The underlying windowing
+ * system is abstracted away.
*
* This class provides basic information about the virtual desktops present
* in the session as a set of notifiable properties.
*
- * @NOTE: This is a placeholder, to be moved into KWindowSystem (which it
- * wraps) or the Task Manager applet backend (which used to fill this role
- * in the past).
- *
- * @see KWindowSystem
- *
* @author Eike Hein <[email protected]>
**/
@@ -47,8 +42,9 @@ class TASKMANAGER_EXPORT VirtualDesktopInfo : public QObject
{
Q_OBJECT
- Q_PROPERTY(int currentDesktop READ currentDesktop NOTIFY currentDesktopChanged)
+ Q_PROPERTY(QVariant currentDesktop READ currentDesktop NOTIFY currentDesktopChanged)
Q_PROPERTY(int numberOfDesktops READ numberOfDesktops NOTIFY numberOfDesktopsChanged)
+ Q_PROPERTY(QVariantList desktopIds READ desktopIds NOTIFY desktopIdsChanged)
Q_PROPERTY(QStringList desktopNames READ desktopNames NOTIFY desktopNamesChanged)
Q_PROPERTY(int desktopLayoutRows READ desktopLayoutRows NOTIFY desktopLayoutRowsChanged)
@@ -59,9 +55,10 @@ public:
/**
* The currently active virtual desktop.
*
- * @returns the number of the currently active virtual desktop.
+ * @returns the id of the currently active virtual desktop. QString on
+ * Wayland; uint >0 on X11.
**/
- int currentDesktop() const;
+ QVariant currentDesktop() const;
/**
* The number of virtual desktops present in the session.
@@ -71,27 +68,80 @@ public:
int numberOfDesktops() const;
/**
- * The names of all virtual desktops present in the session. Note that
- * virtual desktops are indexed starting at 1, so the name for virtual
- * desktop 1 is at index 0 in this list.
+ * The ids of all virtual desktops present in the session.
+ *
+ * On Wayland, the ids are QString. On X11, they are uint >0.
+ *
+ * @returns a the list of ids of the virtual desktops present in the
+ * session.
+ **/
+ QVariantList desktopIds() const;
+
+ /**
+ * The names of all virtual desktops present in the session.
+ *
+ * Note that on X11, virtual desktops are indexed starting at 1, so
+ * the name for virtual desktop 1 is at index 0 in this list.
*
- * @returns a the list of names for the virtual desktops present in the
+ * @returns the list of names of the virtual desktops present in the
* session.
**/
QStringList desktopNames() const;
/**
+ * Returns the position of the passed-in virtual desktop.
+ * @param desktop A virtual desktop id (QString on Wayland; uint >0 on X11).
+ * @returns the position of the virtual desktop, or -1 if the desktop
+ * id is not valid.
+ **/
+ quint32 position(const QVariant &desktop) const;
+
+ /**
* The number of rows in the virtual desktop layout.
*
* @returns the number of rows in the virtual desktop layout.
**/
int desktopLayoutRows() const;
+ /**
+ * Request activating the passed-in virtual desktop.
+ *
+ * @param desktop A virtual desktop id (QString on Wayland; uint >0 on X11).
+ **/
+ void requestActivate(const QVariant &desktop);
+
+ /**
+ * Request adding a new virtual desktop at the specified position.
+ *
+ * On X11, the position parameter is ignored and the new desktop is always
+ * created at the end of the list.
+ *
+ * @param position The position of the requested new virtual desktop (ignored on X11).
+ **/
+ void requestCreateDesktop(quint32 position);
+
+ /**
+ * Request removing the virtual desktop at the specified position.
+ *
+ * On X11, the position parameter is ignored and the last desktop in the list
+ * is always the one removed.
+ *
+ * @param position The position of the virtual desktop to remove (ignored on X11).
+ **/
+ void requestRemoveDesktop(quint32 position);
+
Q_SIGNALS:
void currentDesktopChanged() const;
void numberOfDesktopsChanged() const;
+ void desktopIdsChanged() const;
void desktopNamesChanged() const;
void desktopLayoutRowsChanged() const;
+
+private:
+ class Private;
+ class XWindowPrivate;
+ class WaylandPrivate;
+ static Private *d;
};
}
diff --git a/libtaskmanager/waylandtasksmodel.cpp b/libtaskmanager/waylandtasksmodel.cpp
index ffc2367..43f5692 100644
--- a/libtaskmanager/waylandtasksmodel.cpp
+++ b/libtaskmanager/waylandtasksmodel.cpp
@@ -20,6 +20,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "waylandtasksmodel.h"
#include "tasktools.h"
+#include "virtualdesktopinfo.h"
#include <KActivities/ResourceInstance>
#include <KDirWatch>
@@ -33,10 +34,12 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include <KWindowSystem>
#include <QGuiApplication>
+#include <QMimeData>
#include <QQuickItem>
#include <QQuickWindow>
#include <QSet>
#include <QUrl>
+#include <QUuid>
#include <QWindow>
namespace TaskManager
@@ -51,6 +54,8 @@ public:
KWayland::Client::PlasmaWindowManagement *windowManagement = nullptr;
KSharedConfig::Ptr rulesConfig;
KDirWatch *configWatcher = nullptr;
+ VirtualDesktopInfo *virtualDesktopInfo = nullptr;
+ static QUuid uuid;
void init();
void initWayland();
@@ -60,6 +65,9 @@ public:
QIcon icon(KWayland::Client::PlasmaWindow *window);
+ static QString mimeType();
+ static QString groupMimeType();
+
void dataChanged(KWayland::Client::PlasmaWindow *window, int role);
void dataChanged(KWayland::Client::PlasmaWindow *window, const QVector<int> &roles);
@@ -67,6 +75,8 @@ private:
WaylandTasksModel *q;
};
+QUuid WaylandTasksModel::Private::uuid = QUuid::createUuid();
+
WaylandTasksModel::Private::Private(WaylandTasksModel *q)
: q(q)
{
@@ -106,6 +116,8 @@ void WaylandTasksModel::Private::init()
QObject::connect(configWatcher, &KDirWatch::created, rulesConfigChange);
QObject::connect(configWatcher, &KDirWatch::deleted, rulesConfigChange);
+ virtualDesktopInfo = new VirtualDesktopInfo(q);
+
initWayland();
}
@@ -260,16 +272,33 @@ void WaylandTasksModel::Private::addWindow(KWayland::Client::PlasmaWindow *windo
[window, this] { this->dataChanged(window, IsShadeable); }
);
- QObject::connect(window, &KWayland::Client::PlasmaWindow::virtualDesktopChangeableChanged, q,
- [window, this] { this->dataChanged(window, IsVirtualDesktopChangeable); }
- );
+// FIXME
+// QObject::connect(window, &KWayland::Client::PlasmaWindow::virtualDesktopChangeableChanged, q,
+// // TODO: This is marked deprecated in KWayland, but (IMHO) shouldn't be.
+// [window, this] { this->dataChanged(window, IsVirtualDesktopsChangeable); }
+// );
+
+ QObject::connect(window, &KWayland::Client::PlasmaWindow::plasmaVirtualDesktopEntered, q,
+ [window, this] {
+ this->dataChanged(window, VirtualDesktops);
- QObject::connect(window, &KWayland::Client::PlasmaWindow::virtualDesktopChanged, q,
- [window, this] { this->dataChanged(window, VirtualDesktop); }
+ // If the count has changed from 0, the window may no longer be on all virtual
+ // desktops.
+ if (window->plasmaVirtualDesktops().count() > 0) {
+ this->dataChanged(window, VirtualDesktops);
+ }
+ }
);
- QObject::connect(window, &KWayland::Client::PlasmaWindow::onAllDesktopsChanged, q,
- [window, this] { this->dataChanged(window, IsOnAllVirtualDesktops); }
+ QObject::connect(window, &KWayland::Client::PlasmaWindow::plasmaVirtualDesktopLeft, q,
+ [window, this] {
+ this->dataChanged(window, VirtualDesktops);
+
+ // If the count has changed to 0, the window is now on all virtual desktops.
+ if (window->plasmaVirtualDesktops().count() == 0) {
+ this->dataChanged(window, VirtualDesktops);
+ }
+ }
);
QObject::connect(window, &KWayland::Client::PlasmaWindow::geometryChanged, q,
@@ -314,6 +343,20 @@ QIcon WaylandTasksModel::Private::icon(KWayland::Client::PlasmaWindow *window)
return window->icon();
}
+QString WaylandTasksModel::Private::mimeType()
+{
+ // Use a unique format id to make this intentionally useless for
+ // cross-process DND.
+ return QString("windowsystem/winid+" + uuid.toString().toAscii());
+}
+
+QString WaylandTasksModel::Private::groupMimeType()
+{
+ // Use a unique format id to make this intentionally useless for
+ // cross-process DND.
+ return QString("windowsystem/multiple-winids+" + uuid.toString().toAscii());
+}
+
void WaylandTasksModel::Private::dataChanged(KWayland::Client::PlasmaWindow *window, int role)
{
QModelIndex idx = q->index(windows.indexOf(window));
@@ -361,6 +404,12 @@ QVariant WaylandTasksModel::data(const QModelIndex &index, int role) const
return d->appData(window).genericName;
} else if (role == LauncherUrl || role == LauncherUrlWithoutIcon) {
return d->appData(window).url;
+ } else if (role == WinIdList) {
+ return QVariantList() << window->internalId();
+ } else if (role == MimeType) {
+ return d->mimeType();
+ } else if (role == MimeData) {
+ return QByteArray::number(window->internalId());
} else if (role == IsWindow) {
return true;
} else if (role == IsActive) {
@@ -391,12 +440,13 @@ QVariant WaylandTasksModel::data(const QModelIndex &index, int role) const
return window->isShadeable();
} else if (role == IsShaded) {
return window->isShaded();
- } else if (role == IsVirtualDesktopChangeable) {
- return window->isVirtualDesktopChangeable();
- } else if (role == VirtualDesktop) {
- return window->virtualDesktop();
+ } else if (role == IsVirtualDesktopsChangeable) {
+ // FIXME Currently not implemented in KWayland.
+ return true;
+ } else if (role == VirtualDesktops) {
+ return window->plasmaVirtualDesktops();
} else if (role == IsOnAllVirtualDesktops) {
- return window->isOnAllDesktops();
+ return window->plasmaVirtualDesktops().isEmpty();
} else if (role == Geometry) {
return window->geometry();
} else if (role == ScreenGeometry) {
@@ -468,46 +518,70 @@ void WaylandTasksModel::requestClose(const QModelIndex &index)
void WaylandTasksModel::requestMove(const QModelIndex &index)
{
- // FIXME Move-to-desktop logic from XWindows version. (See also others.)
-
if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
return;
}
- d->windows.at(index.row())->requestMove();
+ KWayland::Client::PlasmaWindow *window = d->windows.at(index.row());
+
+ const QString &currentDesktop = d->virtualDesktopInfo->currentDesktop().toString();
+
+ if (!currentDesktop.isEmpty()) {
+ window->requestEnterVirtualDesktop(currentDesktop);
+ }
+
+ window->requestMove();
}
void WaylandTasksModel::requestResize(const QModelIndex &index)
{
- // FIXME Move-to-desktop logic from XWindows version. (See also others.)
-
if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
return;
}
- d->windows.at(index.row())->requestResize();
+ KWayland::Client::PlasmaWindow *window = d->windows.at(index.row());
+
+ const QString &currentDesktop = d->virtualDesktopInfo->currentDesktop().toString();
+
+ if (!currentDesktop.isEmpty()) {
+ window->requestEnterVirtualDesktop(currentDesktop);
+ }
+
+ window->requestResize();
}
void WaylandTasksModel::requestToggleMinimized(const QModelIndex &index)
{
- // FIXME Move-to-desktop logic from XWindows version. (See also others.)
-
if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
return;
}
- d->windows.at(index.row())->requestToggleMinimized();
+ KWayland::Client::PlasmaWindow *window = d->windows.at(index.row());
+
+ const QString &currentDesktop = d->virtualDesktopInfo->currentDesktop().toString();
+
+ if (!currentDesktop.isEmpty()) {
+ window->requestEnterVirtualDesktop(currentDesktop);
+ }
+
+ window->requestToggleMinimized();
}
void WaylandTasksModel::requestToggleMaximized(const QModelIndex &index)
{
- // FIXME Move-to-desktop logic from XWindows version. (See also others.)
-
if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
return;
}
- d->windows.at(index.row())->requestToggleMaximized();
+ KWayland::Client::PlasmaWindow *window = d->windows.at(index.row());
+
+ const QString &currentDesktop = d->virtualDesktopInfo->currentDesktop().toString();
+
+ if (!currentDesktop.isEmpty()) {
+ window->requestEnterVirtualDesktop(currentDesktop);
+ }
+
+ window->requestToggleMaximized();
}
void WaylandTasksModel::requestToggleKeepAbove(const QModelIndex &index)
@@ -544,16 +618,53 @@ void WaylandTasksModel::requestToggleShaded(const QModelIndex &index)
d->windows.at(index.row())->requestToggleShaded();
}
-void WaylandTasksModel::requestVirtualDesktop(const QModelIndex &index, qint32 desktop)
+void WaylandTasksModel::requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops)
{
- // FIXME Lacks add-new-desktop code from XWindows version.
- // FIXME Does this do the set-on-all-desktops stuff from the XWindows version?
+ // FIXME TODO: Lacks the "if we've requested the current desktop, force-activate
+ // the window" logic from X11 version. This behavior should be in KWin rather than
+ // libtm however.
if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
return;
}
- d->windows.at(index.row())->requestVirtualDesktop(desktop);
+ KWayland::Client::PlasmaWindow *window = d->windows.at(index.row());
+
+ if (desktops.isEmpty()) {
+ foreach (const QVariant &desktop, window->plasmaVirtualDesktops()) {
+ window->requestLeaveVirtualDesktop(desktop.toString());
+ }
+ } else {
+ const QStringList &now = window->plasmaVirtualDesktops();
+ QStringList next;
+
+ foreach (const QVariant &desktop, desktops) {
+ const QString &desktopId = desktop.toString();
+
+ if (!desktopId.isEmpty()) {
+ next << desktopId;
+
+ if (!now.contains(desktopId)) {
+ window->requestEnterVirtualDesktop(desktopId);
+ }
+ }
+ }
+
+ foreach (const QString &desktop, now) {
+ if (!next.contains(desktop)) {
+ window->requestLeaveVirtualDesktop(desktop);
+ }
+ }
+ }
+}
+
+void WaylandTasksModel::requestNewVirtualDesktop(const QModelIndex &index)
+{
+ if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
+ return;
+ }
+
+ d->windows.at(index.row())->requestEnterNewVirtualDesktop();
}
void WaylandTasksModel::requestActivities(const QModelIndex &index, const QStringList &activities)
@@ -605,4 +716,53 @@ void WaylandTasksModel::requestPublishDelegateGeometry(const QModelIndex &index,
window->setMinimizedGeometry(surface, rect);
}
+quint32 WaylandTasksModel::winIdFromMimeData(const QMimeData *mimeData, bool *ok)
+{
+ Q_ASSERT(mimeData);
+
+ if (ok) {
+ *ok = false;
+ }
+
+ if (!mimeData->hasFormat(Private::mimeType())) {
+ return 0;
+ }
+
+ quint32 id = mimeData->data(Private::mimeType()).toUInt(ok);
+
+ return id;
+}
+
+QList<quint32> WaylandTasksModel::winIdsFromMimeData(const QMimeData *mimeData, bool *ok)
+{
+ Q_ASSERT(mimeData);
+ QList<quint32> ids;
+
+ if (ok) {
+ *ok = false;
+ }
+
+ if (!mimeData->hasFormat(Private::groupMimeType())) {
+ // Try to extract single window id.
+ bool singularOk;
+ WId id = winIdFromMimeData(mimeData, &singularOk);
+
+ if (ok) {
+ *ok = singularOk;
+ }
+
+ if (singularOk) {
+ ids << id;
+ }
+
+ return ids;
+ }
+
+ // FIXME: Extracting multiple winids is still unimplemented;
+ // TaskGroupingProxy::data(..., ::MimeData) can't produce
+ // a payload with them anyways.
+
+ return ids;
+}
+
}
diff --git a/libtaskmanager/waylandtasksmodel.h b/libtaskmanager/waylandtasksmodel.h
index d208a7f..c1d95ba 100644
--- a/libtaskmanager/waylandtasksmodel.h
+++ b/libtaskmanager/waylandtasksmodel.h
@@ -44,7 +44,8 @@ namespace TaskManager
* server the host process is connected to.
*
* FIXME: Filtering by window type still needed.
- * FIXME: Support for taskmanagerrulesrc (maybe) still needed.
+ *
+ * @see WindowTasksModel
*
* @author Eike Hein <[email protected]>
*/
@@ -162,15 +163,26 @@ public:
void requestToggleShaded(const QModelIndex &index) override;
/**
- * Request moving the window at the given index to the specified virtual
- * desktop.
+ * Request entering the window at the given index on the specified virtual desktops,
+ * leaving any other desktops.
*
- * FIXME: X Windows version has extra virtual desktop logic.
+ * Virtual desktop ids are QStrings.
+ *
+ * An empty list has a special meaning: The window is entered on all virtual desktops
+ * in the session.
+ *
+ * @param index An index in this window tasks model.
+ * @param desktops A list of virtual desktop ids.
+ **/
+ void requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops) override;
+
+ /**
+ * Request entering the window at the given index on a new virtual desktop,
+ * which is created in response to this request.
*
* @param index An index in this window tasks model.
- * @param desktop A virtual desktop number.
**/
- void requestVirtualDesktop(const QModelIndex &index, qint32 desktop) override;
+ void requestNewVirtualDesktop(const QModelIndex &index) override;
/**
* Request moving the window at the given index to the specified activities
@@ -204,6 +216,22 @@ public:
void requestPublishDelegateGeometry(const QModelIndex &index, const QRect &geometry,
QObject *delegate = nullptr) override;
+ /**
+ * Tries to extract a process-internal Wayland window id from supplied mime data.
+ *
+ * @param mimeData Some mime data.
+ * @param @ok Set to true or false on success or failure.
+ */
+ static quint32 winIdFromMimeData(const QMimeData *mimeData, bool *ok = nullptr);
+
+ /**
+ * Tries to extract process-internal Wayland window ids from supplied mime data.
+ *
+ * @param mimeData Some mime data.
+ * @param @ok Set to true or false on success or failure.
+ */
+ static QList<quint32> winIdsFromMimeData(const QMimeData *mimeData, bool *ok = nullptr);
+
private:
class Private;
QScopedPointer<Private> d;
diff --git a/libtaskmanager/windowtasksmodel.cpp b/libtaskmanager/windowtasksmodel.cpp
index 663f586..5ca2ef8 100644
--- a/libtaskmanager/windowtasksmodel.cpp
+++ b/libtaskmanager/windowtasksmodel.cpp
@@ -60,7 +60,6 @@ WindowTasksModel::Private::~Private()
{
--instanceCount;
-
if (!instanceCount) {
delete sourceTasksModel;
sourceTasksModel = nullptr;
diff --git a/libtaskmanager/windowtasksmodel.h b/libtaskmanager/windowtasksmodel.h
index cdb8f4a..d9bca82 100644
--- a/libtaskmanager/windowtasksmodel.h
+++ b/libtaskmanager/windowtasksmodel.h
@@ -37,6 +37,9 @@ namespace TaskManager
* windowing server the host process is connected to. The underlying
* windowing system is abstracted away.
*
+ * @see WaylandTasksModel
+ * @see XWindowTasksModel
+ *
* @author Eike Hein <[email protected]>
**/
diff --git a/libtaskmanager/xwindowtasksmodel.cpp b/libtaskmanager/xwindowtasksmodel.cpp
index babfd23..ae892a0 100644
--- a/libtaskmanager/xwindowtasksmodel.cpp
+++ b/libtaskmanager/xwindowtasksmodel.cpp
@@ -365,12 +365,12 @@ void XWindowTasksModel::Private::windowChanged(WId window, NET::Properties prope
if (properties2 & NET::WM2AllowedActions) {
wipeInfoCache = true;
changedRoles << IsClosable << IsMovable << IsResizable << IsMaximizable << IsMinimizable;
- changedRoles << IsFullScreenable << IsShadeable << IsVirtualDesktopChangeable;
+ changedRoles << IsFullScreenable << IsShadeable << IsVirtualDesktopsChangeable;
}
if (properties & NET::WMDesktop) {
wipeInfoCache = true;
- changedRoles << VirtualDesktop << IsOnAllVirtualDesktops;
+ changedRoles << VirtualDesktops << IsOnAllVirtualDesktops;
}
if (properties & NET::WMGeometry) {
@@ -591,7 +591,7 @@ QVariant XWindowTasksModel::data(const QModelIndex &index, int role) const
return d->launcherUrl(window);
} else if (role == LauncherUrlWithoutIcon) {
return d->launcherUrl(window, false /* encodeFallbackIcon */);
- } else if (role == LegacyWinIdList) {
+ } else if (role == WinIdList) {
return QVariantList() << window;
} else if (role == MimeType) {
return d->mimeType();
@@ -628,10 +628,10 @@ QVariant XWindowTasksModel::data(const QModelIndex &index, int role) const
return d->windowInfo(window)->actionSupported(NET::ActionShade);
} else if (role == IsShaded) {
return d->windowInfo(window)->hasState(NET::Shaded);
- } else if (role == IsVirtualDesktopChangeable) {
+ } else if (role == IsVirtualDesktopsChangeable) {
return d->windowInfo(window)->actionSupported(NET::ActionChangeDesktop);
- } else if (role == VirtualDesktop) {
- return d->windowInfo(window)->desktop();
+ } else if (role == VirtualDesktops) {
+ return QVariantList() << d->windowInfo(window)->desktop();
} else if (role == IsOnAllVirtualDesktops) {
return d->windowInfo(window)->onAllDesktops();
} else if (role == Geometry) {
@@ -910,12 +910,28 @@ void XWindowTasksModel::requestToggleShaded(const QModelIndex &index)
}
}
-void XWindowTasksModel::requestVirtualDesktop(const QModelIndex &index, qint32 desktop)
+void XWindowTasksModel::requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops)
{
if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
return;
}
+ int desktop = 0;
+
+ if (!desktops.isEmpty()) {
+ bool ok = false;
+
+ desktop = desktops.first().toUInt(&ok);
+
+ if (!ok) {
+ return;
+ }
+ }
+
+ if (desktop > KWindowSystem::numberOfDesktops()) {
+ return;
+ }
+
const WId window = d->windows.at(index.row());
const KWindowInfo *info = d->windowInfo(window);
@@ -928,17 +944,6 @@ void XWindowTasksModel::requestVirtualDesktop(const QModelIndex &index, qint32 d
}
return;
- // FIXME Move add-new-desktop logic up into proxy.
- } else if (desktop > KWindowSystem::numberOfDesktops()) {
- desktop = KWindowSystem::numberOfDesktops() + 1;
-
- // FIXME Arbitrary limit of 20 copied from old code.
- if (desktop > 20) {
- return;
- }
-
- NETRootInfo ri(QX11Info::connection(), NET::NumberOfDesktops);
- ri.setNumberOfDesktops(desktop);
}
KWindowSystem::setOnDesktop(window, desktop);
@@ -948,6 +953,26 @@ void XWindowTasksModel::requestVirtualDesktop(const QModelIndex &index, qint32 d
}
}
+void XWindowTasksModel::requestNewVirtualDesktop(const QModelIndex &index)
+{
+ if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
+ return;
+ }
+
+ const WId window = d->windows.at(index.row());
+ const int desktop = KWindowSystem::numberOfDesktops() + 1;
+
+ // FIXME Arbitrary limit of 20 copied from old code.
+ if (desktop > 20) {
+ return;
+ }
+
+ NETRootInfo ri(QX11Info::connection(), NET::NumberOfDesktops);
+ ri.setNumberOfDesktops(desktop);
+
+ KWindowSystem::setOnDesktop(window, desktop);
+}
+
void XWindowTasksModel::requestActivities(const QModelIndex &index, const QStringList &activities)
{
if (!index.isValid() || index.model() != this || index.row() < 0 || index.row() >= d->windows.count()) {
diff --git a/libtaskmanager/xwindowtasksmodel.h b/libtaskmanager/xwindowtasksmodel.h
index ef46fd3..37df379 100644
--- a/libtaskmanager/xwindowtasksmodel.h
+++ b/libtaskmanager/xwindowtasksmodel.h
@@ -34,7 +34,7 @@ namespace TaskManager
{
/**
- * @short A tasks model for X Windows windows.
+ * @short A tasks model for X Window System windows.
*
* This model presents tasks sourced from window data on the X Windows
* server the host process is connected to.
@@ -44,6 +44,8 @@ namespace TaskManager
* transients for an otherwise-included window) are omitted from the
* model.
*
+ * @see WindowTasksModel
+ *
* @author Eike Hein <[email protected]>
*/
@@ -174,22 +176,29 @@ public:
void requestToggleShaded(const QModelIndex &index) override;
/**
- * Request moving the window at the given index to the specified virtual
- * desktop.
+ * Request entering the window at the given index on the specified virtual desktop.
+ * For compatibility across windowing systems the library supports, the desktops
+ * parameter is a list; however, on X11 a window can only be on one or all virtual
+ * desktops. Therefore, only the first list entry is actually used.
*
- * If the specified virtual desktop is 0, IsOnAllVirtualDesktops is
- * toggled instead.
+ * An empty list has a special meaning: The window is entered on all virtual desktops
+ * in the session.
*
- * If the specified desktop number exceeds the number of virtual
- * desktops in the session, a new desktop is created before moving
- * the window.
+ * The id 0 has a special meaning: The window is entered on all virtual desktops in
+ * the session.
*
- * FIXME: Desktop logic should maybe move into proxy.
+ * @param index An index in this window tasks model.
+ * @param desktops A list of virtual desktop ids (uint).
+ **/
+ void requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops) override;
+
+ /**
+ * Request entering the window at the given index on a new virtual desktop,
+ * which is created in response to this request.
*
* @param index An index in this window tasks model.
- * @param desktop A virtual desktop number.
**/
- void requestVirtualDesktop(const QModelIndex &index, qint32 desktop) override;
+ void requestNewVirtualDesktop(const QModelIndex &index) override;
/**
* Request moving the task at the given index to the specified activities.