File feature-virt-desk-per-scr.patch of Package plasma6-workspace

From 103f6dc908fc588ee2db2e8fe3bf3b6c282a408e Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Sat, 13 Dec 2025 08:58:06 +0100
Subject: [PATCH 01/12] add per-screen active desktop

---
 libtaskmanager/virtualdesktopinfo.cpp | 115 +++++++++++++++++++++++++-
 libtaskmanager/virtualdesktopinfo.h   |  10 ++-
 2 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/libtaskmanager/virtualdesktopinfo.cpp b/libtaskmanager/virtualdesktopinfo.cpp
index 60c5f5a8ae..51f1c20a3e 100644
--- a/libtaskmanager/virtualdesktopinfo.cpp
+++ b/libtaskmanager/virtualdesktopinfo.cpp
@@ -53,6 +53,7 @@ public:
 
     virtual void init() = 0;
     virtual QVariant currentDesktop() const = 0;
+    virtual QVariant currentDesktopByScreenName(const QString &screenName) const = 0;
     virtual int numberOfDesktops() const = 0;
     virtual QVariantList desktopIds() const = 0;
     virtual QStringList desktopNames() const = 0;
@@ -126,6 +127,7 @@ public:
 
     void init() override;
     QVariant currentDesktop() const override;
+    QVariant currentDesktopByScreenName(const QString &screeName) const override;
     int numberOfDesktops() const override;
     QVariantList desktopIds() const override;
     QStringList desktopNames() const override;
@@ -164,6 +166,12 @@ QVariant VirtualDesktopInfo::XWindowPrivate::currentDesktop() const
     return KX11Extras::currentDesktop();
 }
 
+QVariant VirtualDesktopInfo::XWindowPrivate::currentDesktopByScreenName(const QString &) const
+{
+    // Per-screen virtual desktops are not supported on X11.
+    return currentDesktop();
+}
+
 int VirtualDesktopInfo::XWindowPrivate::numberOfDesktops() const
 {
     return KX11Extras::numberOfDesktops();
@@ -281,13 +289,61 @@ protected:
     }
 };
 
+class PlasmaOutputVirtualDesktop : public QObject, public QtWayland::org_kde_plasma_output_virtual_desktop
+{
+    Q_OBJECT
+public:
+    PlasmaOutputVirtualDesktop(struct ::org_kde_plasma_output_virtual_desktop *object)
+        : org_kde_plasma_output_virtual_desktop(object)
+    {
+    }
+    ~PlasmaOutputVirtualDesktop()
+    {
+        wl_proxy_destroy(reinterpret_cast<wl_proxy *>(object()));
+    }
+    QString uuid;
+    QString name;
+    QString activeDesktopId;
+Q_SIGNALS:
+    void done();
+    void removed();
+    void activeDesktopChanged(QString activeDesktopId);
+
+protected:
+    void org_kde_plasma_output_virtual_desktop_uuid(const QString &uuid) override
+    {
+        this->uuid = uuid;
+    }
+    void org_kde_plasma_output_virtual_desktop_name(const QString &name) override
+    {
+        this->name = name;
+    }
+    void org_kde_plasma_output_virtual_desktop_active_desktop_id(const QString &desktop_id) override
+    {
+        if (activeDesktopId == desktop_id) {
+            return;
+        }
+
+        this->activeDesktopId = desktop_id;
+        Q_EMIT activeDesktopChanged(desktop_id);
+    }
+    void org_kde_plasma_output_virtual_desktop_done() override
+    {
+        Q_EMIT done();
+    }
+    void org_kde_plasma_output_virtual_desktop_removed() override
+    {
+        Q_EMIT removed();
+    }
+};
+
 class PlasmaVirtualDesktopManagement : public QWaylandClientExtensionTemplate<PlasmaVirtualDesktopManagement>,
                                        public QtWayland::org_kde_plasma_virtual_desktop_management
 {
     Q_OBJECT
 public:
     PlasmaVirtualDesktopManagement()
-        : QWaylandClientExtensionTemplate(3)
+        : QWaylandClientExtensionTemplate(4)
     {
         connect(this, &QWaylandClientExtension::activeChanged, this, [this] {
             if (!isActive()) {
@@ -301,10 +357,13 @@ public:
             wl_proxy_destroy(reinterpret_cast<wl_proxy *>(object()));
         }
     }
+
+    std::vector<std::unique_ptr<PlasmaOutputVirtualDesktop>> outputs;
 Q_SIGNALS:
     void desktopCreated(const QString &id, quint32 position);
     void desktopRemoved(const QString &id);
     void rowsChanged(const quint32 rows);
+    void currentDesktopForScreenChanged();
     void done();
 
 protected:
@@ -324,6 +383,34 @@ protected:
     {
         Q_EMIT done();
     }
+    void org_kde_plasma_virtual_desktop_management_output_added(struct ::org_kde_plasma_output_virtual_desktop *output) override
+    {
+        auto outputVd = std::make_unique<PlasmaOutputVirtualDesktop>(output);
+        auto *outputVdPtr = outputVd.get();
+
+        connect(
+            outputVd.get(),
+            &PlasmaOutputVirtualDesktop::done,
+            this,
+            [this, outputVdPtr]() {
+                QString uuid = outputVdPtr->uuid;
+
+                connect(outputVdPtr, &PlasmaOutputVirtualDesktop::activeDesktopChanged, this, [this]() {
+                    Q_EMIT currentDesktopForScreenChanged();
+                });
+
+                connect(outputVdPtr, &PlasmaOutputVirtualDesktop::removed, this, [this, uuid]() {
+                    std::erase_if(outputs, [uuid](const std::unique_ptr<PlasmaOutputVirtualDesktop> &outputVd) {
+                        return outputVd->uuid == uuid;
+                    });
+                });
+                // TODO: VD: Is this necessary?
+                Q_EMIT currentDesktopForScreenChanged();
+            },
+            Qt::SingleShotConnection);
+
+        outputs.push_back(std::move(outputVd));
+    }
 };
 
 class Q_DECL_HIDDEN VirtualDesktopInfo::WaylandPrivate : public VirtualDesktopInfo::Private
@@ -342,6 +429,7 @@ public:
     void init() override;
     void addDesktop(const QString &id, quint32 position);
     QVariant currentDesktop() const override;
+    QVariant currentDesktopByScreenName(const QString &screenName) const override;
     int numberOfDesktops() const override;
     QVariantList desktopIds() const override;
     QStringList desktopNames() const override;
@@ -428,6 +516,12 @@ void VirtualDesktopInfo::WaylandPrivate::init()
             Q_EMIT desktopPositionsChanged();
         }
     });
+
+    connect(virtualDesktopManagement.get(), &PlasmaVirtualDesktopManagement::currentDesktopForScreenChanged, this, [this]() {
+        // TODO: VD: Optimize this so that it doesn't trigger for each screen. Clients should probably be able to listen directly for VD changes of screens
+        // they're interested in.
+        Q_EMIT currentDesktopChanged();
+    });
 }
 
 void VirtualDesktopInfo::WaylandPrivate::addDesktop(const QString &id, quint32 position)
@@ -461,6 +555,20 @@ QVariant VirtualDesktopInfo::WaylandPrivate::currentDesktop() const
     return currentVirtualDesktop;
 }
 
+QVariant VirtualDesktopInfo::WaylandPrivate::currentDesktopByScreenName(const QString &screenName) const
+{
+    const auto &outputs = virtualDesktopManagement->outputs;
+    auto result = std::ranges::find_if(outputs, [screenName](const std::unique_ptr<PlasmaOutputVirtualDesktop> &outputVd) {
+        return outputVd->name == screenName;
+    });
+
+    if (result == outputs.cend()) {
+        return currentDesktop();
+    }
+
+    return (*result)->activeDesktopId;
+}
+
 int VirtualDesktopInfo::WaylandPrivate::numberOfDesktops() const
 {
     return virtualDesktops.size();
@@ -583,6 +691,11 @@ QVariant VirtualDesktopInfo::currentDesktop() const
     return d->currentDesktop();
 }
 
+QVariant VirtualDesktopInfo::currentDesktopByScreenName(const QString &screenName) const
+{
+    return d->currentDesktopByScreenName(screenName);
+}
+
 int VirtualDesktopInfo::numberOfDesktops() const
 {
     return d->numberOfDesktops();
diff --git a/libtaskmanager/virtualdesktopinfo.h b/libtaskmanager/virtualdesktopinfo.h
index 867463816e..227dc237be 100644
--- a/libtaskmanager/virtualdesktopinfo.h
+++ b/libtaskmanager/virtualdesktopinfo.h
@@ -40,13 +40,21 @@ public:
     ~VirtualDesktopInfo() override;
 
     /**
-     * The currently active virtual desktop.
+     * The currently active virtual desktop on active screen.
      *
      * @returns the id of the currently active virtual desktop. QString on
      * Wayland; uint >0 on X11.
      **/
     QVariant currentDesktop() const;
 
+    /**
+     * The currently active virtual desktop on given screen.
+     *
+     * @return the id of the currently active virtual desktop. QString on
+     * Wayland; uint >0 on X11.
+     */
+    QVariant currentDesktopByScreenName(const QString &screenName) const;
+
     /**
      * The number of virtual desktops present in the session.
      *
-- 
GitLab


From d720c438774d8fd2c835f73e90c4538ff78aaafc Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Sat, 13 Dec 2025 09:05:25 +0100
Subject: [PATCH 02/12] WIP: pager: show windows even partially overllaping
 with screen

---
 applets/appmenu/appmenumodel.cpp        | 2 ++
 libtaskmanager/taskfilterproxymodel.cpp | 6 +++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/applets/appmenu/appmenumodel.cpp b/applets/appmenu/appmenumodel.cpp
index 99510e83e3..cb39c1b9e1 100644
--- a/applets/appmenu/appmenumodel.cpp
+++ b/applets/appmenu/appmenumodel.cpp
@@ -43,6 +43,8 @@ AppMenuModel::AppMenuModel(QObject *parent)
     , m_tasksModel(new TaskManager::TasksModel(this))
     , m_serviceWatcher(new QDBusServiceWatcher(this))
 {
+    // TODO: VD: This is OK-ish, but the appmenu is shown on all screens with which the window overlaps.
+    // It would probably make more sense to make it strict (only consider window center).
     m_tasksModel->setFilterByScreen(true);
     connect(m_tasksModel, &TaskManager::TasksModel::activeTaskChanged, this, &AppMenuModel::onActiveWindowChanged);
     connect(m_tasksModel,
diff --git a/libtaskmanager/taskfilterproxymodel.cpp b/libtaskmanager/taskfilterproxymodel.cpp
index 8430fc33fe..b3d56c51d4 100644
--- a/libtaskmanager/taskfilterproxymodel.cpp
+++ b/libtaskmanager/taskfilterproxymodel.cpp
@@ -354,7 +354,11 @@ bool TaskFilterProxyModel::acceptsRow(int sourceRow) const
         const QRect &screenGeometry = sourceIdx.data(AbstractTasksModel::ScreenGeometry).toRect();
 
         if (screenGeometry.isValid() && screenGeometry != d->screenGeometry) {
-            return false;
+            const QRect &windowGeometry = sourceIdx.data(AbstractTasksModel::Geometry).toRect();
+
+            if (windowGeometry.isValid() && !windowGeometry.intersects(d->screenGeometry)) {
+                return false;
+            }
         }
     }
 
-- 
GitLab


From b6b89f5242498d87462986bd6cbcc0f8e1a7a5ef Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Sat, 13 Dec 2025 13:34:44 +0100
Subject: [PATCH 03/12] add ability to filter task based on their screen's
 active desktop

---
 libtaskmanager/taskfilterproxymodel.cpp | 78 ++++++++++++++++++++++++-
 libtaskmanager/taskfilterproxymodel.h   | 48 +++++++++++++++
 libtaskmanager/tasksmodel.cpp           | 31 +++++++++-
 libtaskmanager/tasksmodel.h             | 22 +++++++
 4 files changed, 177 insertions(+), 2 deletions(-)

diff --git a/libtaskmanager/taskfilterproxymodel.cpp b/libtaskmanager/taskfilterproxymodel.cpp
index b3d56c51d4..d982ad6ef3 100644
--- a/libtaskmanager/taskfilterproxymodel.cpp
+++ b/libtaskmanager/taskfilterproxymodel.cpp
@@ -6,14 +6,16 @@
 
 #include "taskfilterproxymodel.h"
 #include "abstracttasksmodel.h"
+#include "virtualdesktopinfo.h"
 
 #include "launchertasksmodel_p.h"
 
 #include "config-X11.h"
-#if HAVE_X11
+
 #include <QGuiApplication>
 #include <QScreen>
 
+#if HAVE_X11
 #include <KWindowSystem>
 #endif
 
@@ -27,11 +29,13 @@ public:
     AbstractTasksModelIface *sourceTasksModel = nullptr;
 
     QVariant virtualDesktop;
+    QVariant virtualDesktopInfo;
     QRect screenGeometry;
     QRect regionGeometry;
     QString activity;
 
     bool filterByVirtualDesktop = false;
+    bool filterByPerScreenVirtualDesktop = false;
     bool filterByScreen = false;
     bool filterByActivity = false;
     RegionFilterMode::Mode filterByRegion = RegionFilterMode::Mode::Disabled;
@@ -82,6 +86,40 @@ void TaskFilterProxyModel::setVirtualDesktop(const QVariant &desktop)
     }
 }
 
+QVariant TaskFilterProxyModel::virtualDesktopInfo() const
+{
+    return d->virtualDesktopInfo;
+}
+
+void TaskFilterProxyModel::setVirtualDesktopInfo(const QVariant &virtualDesktopInfo)
+{
+    if (d->virtualDesktopInfo != virtualDesktopInfo) {
+        auto prevVirtualDesktopInfoPtr = virtualDesktopInfo.value<VirtualDesktopInfo *>();
+
+        if (prevVirtualDesktopInfoPtr != nullptr) {
+            disconnect(prevVirtualDesktopInfoPtr, nullptr, this, nullptr);
+        }
+
+        d->virtualDesktopInfo = virtualDesktopInfo;
+
+        auto virtualDesktopInfoPtr = virtualDesktopInfo.value<VirtualDesktopInfo *>();
+
+        if (virtualDesktopInfoPtr != nullptr) {
+            connect(virtualDesktopInfoPtr, &VirtualDesktopInfo::currentDesktopChanged, this, [this]() {
+                if (d->filterByPerScreenVirtualDesktop) {
+                    invalidateFilter();
+                }
+            });
+        }
+
+        if (d->filterByPerScreenVirtualDesktop) {
+            invalidateFilter();
+        }
+
+        Q_EMIT virtualDesktopInfoChanged();
+    }
+}
+
 QRect TaskFilterProxyModel::screenGeometry() const
 {
     return d->screenGeometry;
@@ -153,6 +191,22 @@ void TaskFilterProxyModel::setFilterByVirtualDesktop(bool filter)
     }
 }
 
+bool TaskFilterProxyModel::filterByPerScreenVirtualDesktop() const
+{
+    return d->filterByPerScreenVirtualDesktop;
+}
+
+void TaskFilterProxyModel::setFilterByPerScreenVirtualDesktop(bool filter)
+{
+    if (d->filterByPerScreenVirtualDesktop != filter) {
+        d->filterByPerScreenVirtualDesktop = filter;
+
+        invalidateFilter();
+
+        Q_EMIT filterByPerScreenVirtualDesktopChanged();
+    }
+}
+
 bool TaskFilterProxyModel::filterByScreen() const
 {
     return d->filterByScreen;
@@ -349,6 +403,28 @@ bool TaskFilterProxyModel::acceptsRow(int sourceRow) const
         }
     }
 
+    // Filter by per-screen virtual desktop.
+    if (d->filterByPerScreenVirtualDesktop && !d->virtualDesktopInfo.isNull()) {
+        if (!sourceIdx.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool()
+            && (!d->demandingAttentionSkipsFilters || !sourceIdx.data(AbstractTasksModel::IsDemandingAttention).toBool())) {
+            const QVariantList &virtualDesktops = sourceIdx.data(AbstractTasksModel::VirtualDesktops).toList();
+            auto virtualDesktopInfo = d->virtualDesktopInfo.value<VirtualDesktopInfo *>();
+            const QRect &screenGeometry = sourceIdx.data(AbstractTasksModel::ScreenGeometry).toRect();
+
+            if (!virtualDesktops.isEmpty() && virtualDesktopInfo != nullptr && screenGeometry.isValid()) {
+                for (QScreen *screen : qGuiApp->screens()) {
+                    if (screen->geometry() != screenGeometry) {
+                        continue;
+                    }
+                    if (!virtualDesktops.contains(virtualDesktopInfo->currentDesktopByScreenName(screen->name()))) {
+                        return false;
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
     // Filter by screen.
     if (d->filterByScreen && d->screenGeometry.isValid()) {
         const QRect &screenGeometry = sourceIdx.data(AbstractTasksModel::ScreenGeometry).toRect();
diff --git a/libtaskmanager/taskfilterproxymodel.h b/libtaskmanager/taskfilterproxymodel.h
index 083b6fdc73..a61c04f81a 100644
--- a/libtaskmanager/taskfilterproxymodel.h
+++ b/libtaskmanager/taskfilterproxymodel.h
@@ -33,11 +33,14 @@ class TASKMANAGER_EXPORT TaskFilterProxyModel : public QSortFilterProxyModel, pu
     Q_OBJECT
 
     Q_PROPERTY(QVariant virtualDesktop READ virtualDesktop WRITE setVirtualDesktop NOTIFY virtualDesktopChanged)
+    Q_PROPERTY(QVariant virtualDesktopInfo READ virtualDesktopInfo WRITE setVirtualDesktopInfo NOTIFY virtualDesktopInfoChanged)
     Q_PROPERTY(QRect screenGeometry READ screenGeometry WRITE setScreenGeometry NOTIFY screenGeometryChanged)
     Q_PROPERTY(QRect regionGeometry READ regionGeometry WRITE setRegionGeometry NOTIFY regionGeometryChanged)
     Q_PROPERTY(QString activity READ activity WRITE setActivity NOTIFY activityChanged)
 
     Q_PROPERTY(bool filterByVirtualDesktop READ filterByVirtualDesktop WRITE setFilterByVirtualDesktop NOTIFY filterByVirtualDesktopChanged)
+    Q_PROPERTY(bool filterByPerScreenVirtualDesktop READ filterByPerScreenVirtualDesktop WRITE setFilterByPerScreenVirtualDesktop NOTIFY
+                   filterByPerScreenVirtualDesktopChanged)
     Q_PROPERTY(bool filterByScreen READ filterByScreen WRITE setFilterByScreen NOTIFY filterByScreenChanged)
     Q_PROPERTY(bool filterByActivity READ filterByActivity WRITE setFilterByActivity NOTIFY filterByActivityChanged)
     Q_PROPERTY(RegionFilterMode::Mode filterByRegion READ filterByRegion WRITE setFilterByRegion NOTIFY filterByRegionChanged)
@@ -78,6 +81,24 @@ public:
      **/
     void setVirtualDesktop(const QVariant &desktop = QVariant());
 
+    /**
+     * VirtualDesktopInfo used in filtering by per-screen virtual desktop.
+     * Defaults to empty.
+     *
+     * @see setVirtualDesktopInfo
+     **/
+    QVariant virtualDesktopInfo() const;
+
+    /**
+     * Set the VirtualDesktopInfo to use in filtering by per-screen virtual
+     * desktop.
+     *
+     * If set to a null pointer, filtering by virtual desktop is disabled.
+     *
+     * @see virtualDesktop
+     **/
+    void setVirtualDesktopInfo(const QVariant &virtualDesktopInfo = QVariant());
+
     /**
      * The geometry of the screen used in filtering by screen. Defaults
      * to a null QRect.
@@ -160,6 +181,31 @@ public:
      **/
     void setFilterByVirtualDesktop(bool filter);
 
+    /**
+     * Whether tasks should be filtered by its screen's virtual desktop.
+     * Defaults to @c false.
+     *
+     * Filtering by virtual desktop only happens if VirtualDesktopInfo
+     * is set, even if this is set to @c true.
+     *
+     * @see setFilterByPerScreenVirtualDesktop
+     * @returns @c true if tasks should be filtered by their screen's
+     * virtual desktops.
+     **/
+    bool filterByPerScreenVirtualDesktop() const;
+
+    /**
+     * Set whether tasks should be filtered by virtual desktop.
+     *
+     * Filtering by virtual desktop only happens if VirtualDesktopInfo
+     * is set, even if this is set to @c true.
+     *
+     * @see filterByPerScreenVirtualDesktop
+     * @param filter Whether tasks should be filtered by their screen's
+     * virtual desktop.
+     **/
+    void setFilterByPerScreenVirtualDesktop(bool filter);
+
     /**
      * Whether tasks should be filtered by screen. Defaults to @c false.
      *
@@ -375,10 +421,12 @@ public:
 
 Q_SIGNALS:
     void virtualDesktopChanged() const;
+    void virtualDesktopInfoChanged() const;
     void screenGeometryChanged() const;
     void regionGeometryChanged();
     void activityChanged() const;
     void filterByVirtualDesktopChanged() const;
+    void filterByPerScreenVirtualDesktopChanged() const;
     void filterByScreenChanged() const;
     void filterByActivityChanged() const;
     void filterByRegionChanged();
diff --git a/libtaskmanager/tasksmodel.cpp b/libtaskmanager/tasksmodel.cpp
index 1967846632..00c4514d6c 100644
--- a/libtaskmanager/tasksmodel.cpp
+++ b/libtaskmanager/tasksmodel.cpp
@@ -88,6 +88,7 @@ public:
     bool lessThan(const QModelIndex &left, const QModelIndex &right, bool sortOnlyLaunchers = false) const;
     std::optional<bool> lessThanByVirtualDesktop(const QModelIndex &left, const QModelIndex &right) const;
     static void modelTest(QAbstractItemModel *model);
+    void clearVirtualDesktopInfoIfNotNecessary();
 
 private:
     TasksModel *const q;
@@ -282,6 +283,7 @@ void TasksModel::Private::initModels()
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::regionGeometryChanged, q, &TasksModel::regionGeometryChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::activityChanged, q, &TasksModel::activityChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByVirtualDesktopChanged, q, &TasksModel::filterByVirtualDesktopChanged);
+    QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByPerScreenVirtualDesktopChanged, q, &TasksModel::filterByPerScreenVirtualDesktopChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByScreenChanged, q, &TasksModel::filterByScreenChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByActivityChanged, q, &TasksModel::filterByActivityChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByRegionChanged, q, &TasksModel::filterByRegionChanged);
@@ -824,6 +826,16 @@ std::optional<bool> TasksModel::Private::lessThanByVirtualDesktop(const QModelIn
     return std::nullopt;
 }
 
+void TasksModel::Private::clearVirtualDesktopInfoIfNotNecessary()
+{
+    if (sortMode == SortVirtualDesktop || sortMode == SortWindowPositionHorizontal || filterProxyModel->filterByPerScreenVirtualDesktop()) {
+        return;
+    }
+
+    virtualDesktopInfo = nullptr;
+    filterProxyModel->setVirtualDesktopInfo(QVariant());
+}
+
 bool TasksModel::Private::lessThan(const QModelIndex &left, const QModelIndex &right, bool sortOnlyLaunchers) const
 {
     // Launcher tasks go first.
@@ -1175,6 +1187,23 @@ void TasksModel::setFilterByVirtualDesktop(bool filter)
     d->filterProxyModel->setFilterByVirtualDesktop(filter);
 }
 
+bool TasksModel::filterByPerScreenVirtualDesktop() const
+{
+    return d->filterProxyModel->filterByPerScreenVirtualDesktop();
+}
+
+void TasksModel::setFilterByPerScreenVirtualDesktop(bool filter)
+{
+    d->filterProxyModel->setFilterByPerScreenVirtualDesktop(filter);
+
+    if (filter) {
+        d->virtualDesktopInfo = virtualDesktopInfo();
+        d->filterProxyModel->setVirtualDesktopInfo(QVariant::fromValue(d->virtualDesktopInfo.get()));
+    } else {
+        d->clearVirtualDesktopInfoIfNotNecessary();
+    }
+}
+
 bool TasksModel::filterByScreen() const
 {
     return d->filterProxyModel->filterByScreen();
@@ -1263,7 +1292,6 @@ void TasksModel::setSortMode(SortMode mode)
             d->virtualDesktopInfo = virtualDesktopInfo();
             setSortRole(AbstractTasksModel::VirtualDesktops);
         } else if (d->sortMode == SortVirtualDesktop || d->sortMode == SortWindowPositionHorizontal) {
-            d->virtualDesktopInfo = nullptr;
             setSortRole(Qt::DisplayRole);
         }
 
@@ -1284,6 +1312,7 @@ void TasksModel::setSortMode(SortMode mode)
         }
 
         d->sortMode = mode;
+        d->clearVirtualDesktopInfoIfNotNecessary();
 
         d->forceResort();
 
diff --git a/libtaskmanager/tasksmodel.h b/libtaskmanager/tasksmodel.h
index e933b3da03..b06d4c8282 100644
--- a/libtaskmanager/tasksmodel.h
+++ b/libtaskmanager/tasksmodel.h
@@ -63,6 +63,8 @@ class TASKMANAGER_EXPORT TasksModel : public QSortFilterProxyModel, public Abstr
     Q_PROPERTY(QString activity READ activity WRITE setActivity NOTIFY activityChanged)
 
     Q_PROPERTY(bool filterByVirtualDesktop READ filterByVirtualDesktop WRITE setFilterByVirtualDesktop NOTIFY filterByVirtualDesktopChanged)
+    Q_PROPERTY(bool filterByPerScreenVirtualDesktop READ filterByPerScreenVirtualDesktop WRITE setFilterByPerScreenVirtualDesktop NOTIFY
+                   filterByPerScreenVirtualDesktopChanged)
     Q_PROPERTY(bool filterByScreen READ filterByScreen WRITE setFilterByScreen NOTIFY filterByScreenChanged)
     Q_PROPERTY(bool filterByActivity READ filterByActivity WRITE setFilterByActivity NOTIFY filterByActivityChanged)
     Q_PROPERTY(RegionFilterMode::Mode filterByRegion READ filterByRegion WRITE setFilterByRegion NOTIFY filterByRegionChanged)
@@ -251,6 +253,25 @@ public:
      **/
     void setFilterByVirtualDesktop(bool filter);
 
+    /**
+     * Whether tasks should be filtered by its screen's virtual desktop.
+     * Defaults to @c false.
+     *
+     * @see setFilterByPerScreenVirtualDesktop
+     * @returns @c true if tasks should be filtered by their screen's
+     * virtual desktops.
+     **/
+    bool filterByPerScreenVirtualDesktop() const;
+
+    /**
+     * Set whether tasks should be filtered by virtual desktop.
+     *
+     * @see filterByPerScreenVirtualDesktop
+     * @param filter Whether tasks should be filtered by their screen's
+     * virtual desktop.
+     **/
+    void setFilterByPerScreenVirtualDesktop(bool filter);
+
     /**
      * Whether tasks should be filtered by screen. Defaults to @c false.
      *
@@ -1006,6 +1027,7 @@ Q_SIGNALS:
     void regionGeometryChanged();
     void activityChanged() const;
     void filterByVirtualDesktopChanged() const;
+    void filterByPerScreenVirtualDesktopChanged() const;
     void filterByScreenChanged() const;
     void filterByActivityChanged() const;
     void filterByRegionChanged();
-- 
GitLab


From 224feb06617ab39a9e379e7b1ce4a49ef1b152f7 Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Sun, 14 Dec 2025 13:20:50 +0100
Subject: [PATCH 04/12] revert setFilterByScreen by geometry intersect

It's not strictly related to per-output virtual desktops and it causes
some issues:

- appmenu behavior would have to be fixed.
- Window overlapping multiple screens will remain visible on the
  secondary screen's pager even after switching to another desktop on
  its screen. At that point the window is not visible on either screen,
  but it's still showing up on the secondary screen's pager.
---
 applets/appmenu/appmenumodel.cpp        | 2 --
 libtaskmanager/taskfilterproxymodel.cpp | 6 +-----
 2 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/applets/appmenu/appmenumodel.cpp b/applets/appmenu/appmenumodel.cpp
index cb39c1b9e1..99510e83e3 100644
--- a/applets/appmenu/appmenumodel.cpp
+++ b/applets/appmenu/appmenumodel.cpp
@@ -43,8 +43,6 @@ AppMenuModel::AppMenuModel(QObject *parent)
     , m_tasksModel(new TaskManager::TasksModel(this))
     , m_serviceWatcher(new QDBusServiceWatcher(this))
 {
-    // TODO: VD: This is OK-ish, but the appmenu is shown on all screens with which the window overlaps.
-    // It would probably make more sense to make it strict (only consider window center).
     m_tasksModel->setFilterByScreen(true);
     connect(m_tasksModel, &TaskManager::TasksModel::activeTaskChanged, this, &AppMenuModel::onActiveWindowChanged);
     connect(m_tasksModel,
diff --git a/libtaskmanager/taskfilterproxymodel.cpp b/libtaskmanager/taskfilterproxymodel.cpp
index d982ad6ef3..20fbf3e623 100644
--- a/libtaskmanager/taskfilterproxymodel.cpp
+++ b/libtaskmanager/taskfilterproxymodel.cpp
@@ -430,11 +430,7 @@ bool TaskFilterProxyModel::acceptsRow(int sourceRow) const
         const QRect &screenGeometry = sourceIdx.data(AbstractTasksModel::ScreenGeometry).toRect();
 
         if (screenGeometry.isValid() && screenGeometry != d->screenGeometry) {
-            const QRect &windowGeometry = sourceIdx.data(AbstractTasksModel::Geometry).toRect();
-
-            if (windowGeometry.isValid() && !windowGeometry.intersects(d->screenGeometry)) {
-                return false;
-            }
+            return false;
         }
     }
 
-- 
GitLab


From e9ed1462c2708f48e425e0ee8f717dbd26abc1e8 Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Tue, 16 Dec 2025 09:04:13 +0100
Subject: [PATCH 05/12] improve output-added handling

---
 libtaskmanager/virtualdesktopinfo.cpp | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/libtaskmanager/virtualdesktopinfo.cpp b/libtaskmanager/virtualdesktopinfo.cpp
index 51f1c20a3e..97c03a2109 100644
--- a/libtaskmanager/virtualdesktopinfo.cpp
+++ b/libtaskmanager/virtualdesktopinfo.cpp
@@ -388,24 +388,21 @@ protected:
         auto outputVd = std::make_unique<PlasmaOutputVirtualDesktop>(output);
         auto *outputVdPtr = outputVd.get();
 
+        connect(outputVdPtr, &PlasmaOutputVirtualDesktop::activeDesktopChanged, this, [this]() {
+            Q_EMIT currentDesktopForScreenChanged();
+        });
+
         connect(
             outputVd.get(),
             &PlasmaOutputVirtualDesktop::done,
             this,
             [this, outputVdPtr]() {
                 QString uuid = outputVdPtr->uuid;
-
-                connect(outputVdPtr, &PlasmaOutputVirtualDesktop::activeDesktopChanged, this, [this]() {
-                    Q_EMIT currentDesktopForScreenChanged();
-                });
-
                 connect(outputVdPtr, &PlasmaOutputVirtualDesktop::removed, this, [this, uuid]() {
                     std::erase_if(outputs, [uuid](const std::unique_ptr<PlasmaOutputVirtualDesktop> &outputVd) {
                         return outputVd->uuid == uuid;
                     });
                 });
-                // TODO: VD: Is this necessary?
-                Q_EMIT currentDesktopForScreenChanged();
             },
             Qt::SingleShotConnection);
 
-- 
GitLab


From 0fb7c13889bd132255626ea1089439af4e354cbb Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Tue, 16 Dec 2025 10:41:30 +0100
Subject: [PATCH 06/12] fix SwitchWindow desktop action for per-output desktops

It has a "display only the current desktop's windows" option. It didn't
work consistently to other functionality with per-output virtual
desktops. I.e. it showed windows for the active screen's virtual
desktop, even if the other screen had a different desktop.

Now it shows the windows from each screen's active desktop.
---
 containmentactions/switchwindow/switch.cpp | 23 ++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/containmentactions/switchwindow/switch.cpp b/containmentactions/switchwindow/switch.cpp
index 2e204d6cea..41ef539a59 100644
--- a/containmentactions/switchwindow/switch.cpp
+++ b/containmentactions/switchwindow/switch.cpp
@@ -64,6 +64,7 @@ SwitchWindow::~SwitchWindow()
 void SwitchWindow::restore(const KConfigGroup &config)
 {
     m_mode = (MenuMode)config.readEntry("mode", (int)AllFlat);
+    s_tasksModel->setFilterByPerScreenVirtualDesktop(m_mode == CurrentDesktop);
 }
 
 QWidget *SwitchWindow::createConfigurationInterface(QWidget *parent)
@@ -94,6 +95,8 @@ void SwitchWindow::configurationAccepted()
     } else {
         m_mode = CurrentDesktop;
     }
+
+    s_tasksModel->setFilterByPerScreenVirtualDesktop(m_mode == CurrentDesktop);
 }
 
 void SwitchWindow::save(KConfigGroup &config)
@@ -112,6 +115,7 @@ void SwitchWindow::makeMenu()
 
     QMultiMap<QString, QAction *> desktops;
     QList<QAction *> allDesktops;
+    QList<QAction *> uniqueActions;
 
     // Make all the window actions.
     for (int i = 0; i < s_tasksModel->rowCount(); ++i) {
@@ -130,6 +134,14 @@ void SwitchWindow::makeMenu()
         auto *action = new QAction(name, this);
         action->setIcon(idx.data(Qt::DecorationRole).value<QIcon>());
         action->setData(idx.data(AbstractTasksModel::WinIdList).toList());
+        connect(action, &QAction::triggered, [=, this]() {
+            switchTo(action);
+        });
+
+        if (m_mode == CurrentDesktop) {
+            uniqueActions << action;
+            continue;
+        }
 
         const QStringList &desktopList = idx.data(AbstractTasksModel::VirtualDesktops).toStringList();
 
@@ -140,22 +152,17 @@ void SwitchWindow::makeMenu()
         if (idx.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool()) {
             allDesktops << action;
         }
-
-        connect(action, &QAction::triggered, [=, this]() {
-            switchTo(action);
-        });
     }
 
     // Sort into menu(s).
     if (m_mode == CurrentDesktop) {
-        const QString &currentDesktop = m_virtualDesktopInfo->currentDesktop().toString();
-
         auto *a = new QAction(i18nc("plasma_containmentactions_switchwindow", "Windows"), this);
         a->setSeparator(true);
         m_actions << a;
-        m_actions << desktops.values(currentDesktop);
-        m_actions << allDesktops;
 
+        for (auto action : uniqueActions) {
+            m_actions << action;
+        }
     } else {
         const QVariantList &desktopIds = m_virtualDesktopInfo->desktopIds();
         const QStringList &desktopNames = m_virtualDesktopInfo->desktopNames();
-- 
GitLab


From 90b73f51f001ac4feb86b4d2aa10668e5c1d63e5 Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Tue, 16 Dec 2025 11:43:02 +0100
Subject: [PATCH 07/12] fix MaximizedWindowMonitor

Previously, it checked windows from active screen's virtual desktop,
which didn't work properly with per-output virtual desktops.
---
 wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp | 8 +-------
 wallpapers/image/plugin/utils/maximizedwindowmonitor.h   | 1 -
 2 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp b/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp
index 0385737ba8..6f75261238 100644
--- a/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp
+++ b/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp
@@ -13,7 +13,6 @@
 MaximizedWindowMonitor::MaximizedWindowMonitor(QObject *parent)
     : TaskManager::TasksModel(parent)
     , m_activityInfo(activityInfo())
-    , m_virtualDesktopInfo(virtualDesktopInfo())
 {
     setSortMode(SortMode::SortActivity);
     setGroupMode(GroupMode::GroupDisabled);
@@ -23,14 +22,9 @@ MaximizedWindowMonitor::MaximizedWindowMonitor(QObject *parent)
     setCurrentActivity();
     connect(m_activityInfo.get(), &TaskManager::ActivityInfo::currentActivityChanged, this, setCurrentActivity);
 
-    auto currentDesktop = std::bind(&TaskManager::VirtualDesktopInfo::currentDesktop, m_virtualDesktopInfo);
-    auto setCurrentDesktop = std::bind(&TaskManager::TasksModel::setVirtualDesktop, this, currentDesktop);
-    setCurrentDesktop();
-    connect(m_virtualDesktopInfo.get(), &TaskManager::VirtualDesktopInfo::currentDesktopChanged, this, setCurrentDesktop);
-
     setFilterMinimized(true);
     setFilterByActivity(true);
-    setFilterByVirtualDesktop(true);
+    setFilterByPerScreenVirtualDesktop(true);
     setFilterByRegion(RegionFilterMode::Mode::Intersect);
 }
 
diff --git a/wallpapers/image/plugin/utils/maximizedwindowmonitor.h b/wallpapers/image/plugin/utils/maximizedwindowmonitor.h
index 4a924af815..0c9c5eccde 100644
--- a/wallpapers/image/plugin/utils/maximizedwindowmonitor.h
+++ b/wallpapers/image/plugin/utils/maximizedwindowmonitor.h
@@ -30,5 +30,4 @@ protected:
 
 private:
     std::shared_ptr<TaskManager::ActivityInfo> m_activityInfo;
-    std::shared_ptr<TaskManager::VirtualDesktopInfo> m_virtualDesktopInfo;
 };
-- 
GitLab


From d8c82ace10db6a5025beff82eb5717204d1719ab Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Tue, 16 Dec 2025 12:33:33 +0100
Subject: [PATCH 08/12] add separate currentDesktopForScreenChanged

It's an optimization to limit the number of refreshes the listener
needs. Previously with just currentDesktopChanged, the listener would
(almost) always get called twice in a row: once from
PlasmaVirtualDesktopManagement::currentDesktopForScreenChanged
and again from PlasmaVirtualDesktop::activated.

Now that it's separate the places which use currentDesktopByScreenName
can subscribe just to currentDesktopForScreenChanged.
---
 libtaskmanager/taskfilterproxymodel.cpp |  2 +-
 libtaskmanager/virtualdesktopinfo.cpp   | 28 ++++++++++++++++++-------
 libtaskmanager/virtualdesktopinfo.h     |  1 +
 3 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/libtaskmanager/taskfilterproxymodel.cpp b/libtaskmanager/taskfilterproxymodel.cpp
index 20fbf3e623..ccdc6a7502 100644
--- a/libtaskmanager/taskfilterproxymodel.cpp
+++ b/libtaskmanager/taskfilterproxymodel.cpp
@@ -105,7 +105,7 @@ void TaskFilterProxyModel::setVirtualDesktopInfo(const QVariant &virtualDesktopI
         auto virtualDesktopInfoPtr = virtualDesktopInfo.value<VirtualDesktopInfo *>();
 
         if (virtualDesktopInfoPtr != nullptr) {
-            connect(virtualDesktopInfoPtr, &VirtualDesktopInfo::currentDesktopChanged, this, [this]() {
+            connect(virtualDesktopInfoPtr, &VirtualDesktopInfo::currentDesktopForScreenChanged, this, [this]() {
                 if (d->filterByPerScreenVirtualDesktop) {
                     invalidateFilter();
                 }
diff --git a/libtaskmanager/virtualdesktopinfo.cpp b/libtaskmanager/virtualdesktopinfo.cpp
index 97c03a2109..58e0488212 100644
--- a/libtaskmanager/virtualdesktopinfo.cpp
+++ b/libtaskmanager/virtualdesktopinfo.cpp
@@ -18,6 +18,7 @@
 #include <QDBusPendingCallWatcher>
 #include <QDBusPendingReply>
 #include <QGuiApplication>
+#include <QScreen>
 #include <QWaylandClientExtension>
 #include <algorithm>
 
@@ -65,6 +66,7 @@ public:
 
 Q_SIGNALS:
     void currentDesktopChanged() const;
+    void currentDesktopForScreenChanged(const QString &screenName) const;
     void numberOfDesktopsChanged() const;
     void desktopIdsChanged() const;
     void desktopNamesChanged() const;
@@ -146,7 +148,13 @@ VirtualDesktopInfo::XWindowPrivate::XWindowPrivate()
 
 void VirtualDesktopInfo::XWindowPrivate::init()
 {
-    connect(KX11Extras::self(), &KX11Extras::currentDesktopChanged, this, &VirtualDesktopInfo::XWindowPrivate::currentDesktopChanged);
+    connect(KX11Extras::self(), &KX11Extras::currentDesktopChanged, this, [this]() {
+        for (const QScreen *screen : qGuiApp->screens()) {
+            Q_EMIT currentDesktopForScreenChanged(screen->name());
+        }
+
+        Q_EMIT currentDesktopChanged();
+    });
 
     connect(KX11Extras::self(), &KX11Extras::numberOfDesktopsChanged, this, &VirtualDesktopInfo::XWindowPrivate::numberOfDesktopsChanged);
 
@@ -363,7 +371,7 @@ Q_SIGNALS:
     void desktopCreated(const QString &id, quint32 position);
     void desktopRemoved(const QString &id);
     void rowsChanged(const quint32 rows);
-    void currentDesktopForScreenChanged();
+    void currentDesktopForScreenChanged(const QString &screenName);
     void done();
 
 protected:
@@ -388,8 +396,8 @@ protected:
         auto outputVd = std::make_unique<PlasmaOutputVirtualDesktop>(output);
         auto *outputVdPtr = outputVd.get();
 
-        connect(outputVdPtr, &PlasmaOutputVirtualDesktop::activeDesktopChanged, this, [this]() {
-            Q_EMIT currentDesktopForScreenChanged();
+        connect(outputVdPtr, &PlasmaOutputVirtualDesktop::activeDesktopChanged, this, [this, outputVdPtr]() {
+            Q_EMIT currentDesktopForScreenChanged(outputVdPtr->name);
         });
 
         connect(
@@ -463,6 +471,11 @@ void VirtualDesktopInfo::WaylandPrivate::init()
             rows = 0;
             virtualDesktops.clear();
             currentVirtualDesktop.clear();
+
+            for (const auto &output : virtualDesktopManagement->outputs) {
+                Q_EMIT currentDesktopByScreenName(output->name);
+            }
+
             Q_EMIT currentDesktopChanged();
             Q_EMIT numberOfDesktopsChanged();
             Q_EMIT navigationWrappingAroundChanged();
@@ -514,10 +527,8 @@ void VirtualDesktopInfo::WaylandPrivate::init()
         }
     });
 
-    connect(virtualDesktopManagement.get(), &PlasmaVirtualDesktopManagement::currentDesktopForScreenChanged, this, [this]() {
-        // TODO: VD: Optimize this so that it doesn't trigger for each screen. Clients should probably be able to listen directly for VD changes of screens
-        // they're interested in.
-        Q_EMIT currentDesktopChanged();
+    connect(virtualDesktopManagement.get(), &PlasmaVirtualDesktopManagement::currentDesktopForScreenChanged, this, [this](const QString &screenName) {
+        Q_EMIT currentDesktopForScreenChanged(screenName);
     });
 }
 
@@ -667,6 +678,7 @@ VirtualDesktopInfo::VirtualDesktopInfo(QObject *parent)
     }
 
     connect(d, &VirtualDesktopInfo::Private::currentDesktopChanged, this, &VirtualDesktopInfo::currentDesktopChanged);
+    connect(d, &VirtualDesktopInfo::Private::currentDesktopForScreenChanged, this, &VirtualDesktopInfo::currentDesktopForScreenChanged);
     connect(d, &VirtualDesktopInfo::Private::numberOfDesktopsChanged, this, &VirtualDesktopInfo::numberOfDesktopsChanged);
     connect(d, &VirtualDesktopInfo::Private::desktopIdsChanged, this, &VirtualDesktopInfo::desktopIdsChanged);
     connect(d, &VirtualDesktopInfo::Private::desktopNamesChanged, this, &VirtualDesktopInfo::desktopNamesChanged);
diff --git a/libtaskmanager/virtualdesktopinfo.h b/libtaskmanager/virtualdesktopinfo.h
index 227dc237be..5add71140e 100644
--- a/libtaskmanager/virtualdesktopinfo.h
+++ b/libtaskmanager/virtualdesktopinfo.h
@@ -134,6 +134,7 @@ public:
 
 Q_SIGNALS:
     void currentDesktopChanged() const;
+    void currentDesktopForScreenChanged(const QString &screenName) const;
     void numberOfDesktopsChanged() const;
     void desktopIdsChanged() const;
     void desktopNamesChanged() const;
-- 
GitLab


From e3036367f40227c55b94fcbb9dc4a34d6870eff8 Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Sat, 20 Dec 2025 13:42:39 +0100
Subject: [PATCH 09/12] fix emitting wrong event

---
 libtaskmanager/virtualdesktopinfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libtaskmanager/virtualdesktopinfo.cpp b/libtaskmanager/virtualdesktopinfo.cpp
index 58e0488212..b51da7ff3a 100644
--- a/libtaskmanager/virtualdesktopinfo.cpp
+++ b/libtaskmanager/virtualdesktopinfo.cpp
@@ -473,7 +473,7 @@ void VirtualDesktopInfo::WaylandPrivate::init()
             currentVirtualDesktop.clear();
 
             for (const auto &output : virtualDesktopManagement->outputs) {
-                Q_EMIT currentDesktopByScreenName(output->name);
+                Q_EMIT currentDesktopForScreenChanged(output->name);
             }
 
             Q_EMIT currentDesktopChanged();
-- 
GitLab


From fb8e4aa162c4a3d4288dc5e32226fc92fce87b55 Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Sun, 28 Dec 2025 13:00:55 +0100
Subject: [PATCH 10/12] add VirtualDesktopInfo::currentDesktopByScreenGeometry

This is handy for applets which have access to a window and it's
ScreenGeometry property
---
 libtaskmanager/virtualdesktopinfo.cpp | 12 ++++++++++++
 libtaskmanager/virtualdesktopinfo.h   | 10 +++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/libtaskmanager/virtualdesktopinfo.cpp b/libtaskmanager/virtualdesktopinfo.cpp
index b51da7ff3a..2faa2fe6fe 100644
--- a/libtaskmanager/virtualdesktopinfo.cpp
+++ b/libtaskmanager/virtualdesktopinfo.cpp
@@ -705,6 +705,18 @@ QVariant VirtualDesktopInfo::currentDesktopByScreenName(const QString &screenNam
     return d->currentDesktopByScreenName(screenName);
 }
 
+QVariant VirtualDesktopInfo::currentDesktopByScreenGeometry(const QRect &screenGeometry) const
+{
+    for (QScreen *screen : qGuiApp->screens()) {
+        const QRect geometry = screen->geometry();
+
+        if (geometry == screenGeometry) {
+            return d->currentDesktopByScreenName(screen->name());
+        }
+    }
+    return d->currentDesktop();
+}
+
 int VirtualDesktopInfo::numberOfDesktops() const
 {
     return d->numberOfDesktops();
diff --git a/libtaskmanager/virtualdesktopinfo.h b/libtaskmanager/virtualdesktopinfo.h
index 5add71140e..45a340ebb9 100644
--- a/libtaskmanager/virtualdesktopinfo.h
+++ b/libtaskmanager/virtualdesktopinfo.h
@@ -53,7 +53,15 @@ public:
      * @return the id of the currently active virtual desktop. QString on
      * Wayland; uint >0 on X11.
      */
-    QVariant currentDesktopByScreenName(const QString &screenName) const;
+    Q_INVOKABLE QVariant currentDesktopByScreenName(const QString &screenName) const;
+
+    /**
+     * The currently active virtual desktop on given screen.
+     *
+     * @return the id of the currently active virtual desktop. QString on
+     * Wayland; uint >0 on X11.
+     */
+    Q_INVOKABLE QVariant currentDesktopByScreenGeometry(const QRect &screenGeometry) const;
 
     /**
      * The number of virtual desktops present in the session.
-- 
GitLab


From 617a7fe67cc4910474c5efef3c6e1ff561d44694 Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Thu, 1 Jan 2026 13:40:18 +0100
Subject: [PATCH 11/12] fix issues caught by codex

---
 libtaskmanager/taskfilterproxymodel.cpp                  | 2 +-
 wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/libtaskmanager/taskfilterproxymodel.cpp b/libtaskmanager/taskfilterproxymodel.cpp
index ccdc6a7502..4b84f022dd 100644
--- a/libtaskmanager/taskfilterproxymodel.cpp
+++ b/libtaskmanager/taskfilterproxymodel.cpp
@@ -94,7 +94,7 @@ QVariant TaskFilterProxyModel::virtualDesktopInfo() const
 void TaskFilterProxyModel::setVirtualDesktopInfo(const QVariant &virtualDesktopInfo)
 {
     if (d->virtualDesktopInfo != virtualDesktopInfo) {
-        auto prevVirtualDesktopInfoPtr = virtualDesktopInfo.value<VirtualDesktopInfo *>();
+        auto prevVirtualDesktopInfoPtr = d->virtualDesktopInfo.value<VirtualDesktopInfo *>();
 
         if (prevVirtualDesktopInfoPtr != nullptr) {
             disconnect(prevVirtualDesktopInfoPtr, nullptr, this, nullptr);
diff --git a/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp b/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp
index 6f75261238..247c7c8194 100644
--- a/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp
+++ b/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp
@@ -8,7 +8,6 @@
 
 #include "abstracttasksmodel.h" // For enums
 #include "activityinfo.h"
-#include "virtualdesktopinfo.h"
 
 MaximizedWindowMonitor::MaximizedWindowMonitor(QObject *parent)
     : TaskManager::TasksModel(parent)
-- 
GitLab


From 1a4ad3b5956a9de3e457566cc3a1d9fcda2fc307 Mon Sep 17 00:00:00 2001
From: Hynek Schlindenbuch <schlindenbuch.h@seznam.cz>
Date: Sat, 24 Jan 2026 10:00:16 +0100
Subject: [PATCH 12/12] improve naming: setFilterByCurrentVirtualDesktop

---
 containmentactions/switchwindow/switch.cpp    |  4 ++--
 libtaskmanager/taskfilterproxymodel.cpp       | 20 +++++++++----------
 libtaskmanager/taskfilterproxymodel.h         | 14 ++++++-------
 libtaskmanager/tasksmodel.cpp                 | 12 +++++------
 libtaskmanager/tasksmodel.h                   | 14 ++++++-------
 .../plugin/utils/maximizedwindowmonitor.cpp   |  2 +-
 6 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/containmentactions/switchwindow/switch.cpp b/containmentactions/switchwindow/switch.cpp
index 41ef539a59..62ffee88d8 100644
--- a/containmentactions/switchwindow/switch.cpp
+++ b/containmentactions/switchwindow/switch.cpp
@@ -64,7 +64,7 @@ SwitchWindow::~SwitchWindow()
 void SwitchWindow::restore(const KConfigGroup &config)
 {
     m_mode = (MenuMode)config.readEntry("mode", (int)AllFlat);
-    s_tasksModel->setFilterByPerScreenVirtualDesktop(m_mode == CurrentDesktop);
+    s_tasksModel->setFilterByCurrentVirtualDesktop(m_mode == CurrentDesktop);
 }
 
 QWidget *SwitchWindow::createConfigurationInterface(QWidget *parent)
@@ -96,7 +96,7 @@ void SwitchWindow::configurationAccepted()
         m_mode = CurrentDesktop;
     }
 
-    s_tasksModel->setFilterByPerScreenVirtualDesktop(m_mode == CurrentDesktop);
+    s_tasksModel->setFilterByCurrentVirtualDesktop(m_mode == CurrentDesktop);
 }
 
 void SwitchWindow::save(KConfigGroup &config)
diff --git a/libtaskmanager/taskfilterproxymodel.cpp b/libtaskmanager/taskfilterproxymodel.cpp
index 4b84f022dd..b3b89b8ff1 100644
--- a/libtaskmanager/taskfilterproxymodel.cpp
+++ b/libtaskmanager/taskfilterproxymodel.cpp
@@ -35,7 +35,7 @@ public:
     QString activity;
 
     bool filterByVirtualDesktop = false;
-    bool filterByPerScreenVirtualDesktop = false;
+    bool filterByCurrentVirtualDesktop = false;
     bool filterByScreen = false;
     bool filterByActivity = false;
     RegionFilterMode::Mode filterByRegion = RegionFilterMode::Mode::Disabled;
@@ -106,13 +106,13 @@ void TaskFilterProxyModel::setVirtualDesktopInfo(const QVariant &virtualDesktopI
 
         if (virtualDesktopInfoPtr != nullptr) {
             connect(virtualDesktopInfoPtr, &VirtualDesktopInfo::currentDesktopForScreenChanged, this, [this]() {
-                if (d->filterByPerScreenVirtualDesktop) {
+                if (d->filterByCurrentVirtualDesktop) {
                     invalidateFilter();
                 }
             });
         }
 
-        if (d->filterByPerScreenVirtualDesktop) {
+        if (d->filterByCurrentVirtualDesktop) {
             invalidateFilter();
         }
 
@@ -191,19 +191,19 @@ void TaskFilterProxyModel::setFilterByVirtualDesktop(bool filter)
     }
 }
 
-bool TaskFilterProxyModel::filterByPerScreenVirtualDesktop() const
+bool TaskFilterProxyModel::filterByCurrentVirtualDesktop() const
 {
-    return d->filterByPerScreenVirtualDesktop;
+    return d->filterByCurrentVirtualDesktop;
 }
 
-void TaskFilterProxyModel::setFilterByPerScreenVirtualDesktop(bool filter)
+void TaskFilterProxyModel::setFilterByCurrentVirtualDesktop(bool filter)
 {
-    if (d->filterByPerScreenVirtualDesktop != filter) {
-        d->filterByPerScreenVirtualDesktop = filter;
+    if (d->filterByCurrentVirtualDesktop != filter) {
+        d->filterByCurrentVirtualDesktop = filter;
 
         invalidateFilter();
 
-        Q_EMIT filterByPerScreenVirtualDesktopChanged();
+        Q_EMIT filterByCurrentVirtualDesktopChanged();
     }
 }
 
@@ -404,7 +404,7 @@ bool TaskFilterProxyModel::acceptsRow(int sourceRow) const
     }
 
     // Filter by per-screen virtual desktop.
-    if (d->filterByPerScreenVirtualDesktop && !d->virtualDesktopInfo.isNull()) {
+    if (d->filterByCurrentVirtualDesktop && !d->virtualDesktopInfo.isNull()) {
         if (!sourceIdx.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool()
             && (!d->demandingAttentionSkipsFilters || !sourceIdx.data(AbstractTasksModel::IsDemandingAttention).toBool())) {
             const QVariantList &virtualDesktops = sourceIdx.data(AbstractTasksModel::VirtualDesktops).toList();
diff --git a/libtaskmanager/taskfilterproxymodel.h b/libtaskmanager/taskfilterproxymodel.h
index a61c04f81a..01de52e68a 100644
--- a/libtaskmanager/taskfilterproxymodel.h
+++ b/libtaskmanager/taskfilterproxymodel.h
@@ -39,8 +39,8 @@ class TASKMANAGER_EXPORT TaskFilterProxyModel : public QSortFilterProxyModel, pu
     Q_PROPERTY(QString activity READ activity WRITE setActivity NOTIFY activityChanged)
 
     Q_PROPERTY(bool filterByVirtualDesktop READ filterByVirtualDesktop WRITE setFilterByVirtualDesktop NOTIFY filterByVirtualDesktopChanged)
-    Q_PROPERTY(bool filterByPerScreenVirtualDesktop READ filterByPerScreenVirtualDesktop WRITE setFilterByPerScreenVirtualDesktop NOTIFY
-                   filterByPerScreenVirtualDesktopChanged)
+    Q_PROPERTY(bool filterByCurrentVirtualDesktop READ filterByCurrentVirtualDesktop WRITE setFilterByCurrentVirtualDesktop NOTIFY
+                   filterByCurrentVirtualDesktopChanged)
     Q_PROPERTY(bool filterByScreen READ filterByScreen WRITE setFilterByScreen NOTIFY filterByScreenChanged)
     Q_PROPERTY(bool filterByActivity READ filterByActivity WRITE setFilterByActivity NOTIFY filterByActivityChanged)
     Q_PROPERTY(RegionFilterMode::Mode filterByRegion READ filterByRegion WRITE setFilterByRegion NOTIFY filterByRegionChanged)
@@ -188,11 +188,11 @@ public:
      * Filtering by virtual desktop only happens if VirtualDesktopInfo
      * is set, even if this is set to @c true.
      *
-     * @see setFilterByPerScreenVirtualDesktop
+     * @see setFilterByCurrentVirtualDesktop
      * @returns @c true if tasks should be filtered by their screen's
      * virtual desktops.
      **/
-    bool filterByPerScreenVirtualDesktop() const;
+    bool filterByCurrentVirtualDesktop() const;
 
     /**
      * Set whether tasks should be filtered by virtual desktop.
@@ -200,11 +200,11 @@ public:
      * Filtering by virtual desktop only happens if VirtualDesktopInfo
      * is set, even if this is set to @c true.
      *
-     * @see filterByPerScreenVirtualDesktop
+     * @see filterByCurrentVirtualDesktop
      * @param filter Whether tasks should be filtered by their screen's
      * virtual desktop.
      **/
-    void setFilterByPerScreenVirtualDesktop(bool filter);
+    void setFilterByCurrentVirtualDesktop(bool filter);
 
     /**
      * Whether tasks should be filtered by screen. Defaults to @c false.
@@ -426,7 +426,7 @@ Q_SIGNALS:
     void regionGeometryChanged();
     void activityChanged() const;
     void filterByVirtualDesktopChanged() const;
-    void filterByPerScreenVirtualDesktopChanged() const;
+    void filterByCurrentVirtualDesktopChanged() const;
     void filterByScreenChanged() const;
     void filterByActivityChanged() const;
     void filterByRegionChanged();
diff --git a/libtaskmanager/tasksmodel.cpp b/libtaskmanager/tasksmodel.cpp
index 00c4514d6c..511185b50b 100644
--- a/libtaskmanager/tasksmodel.cpp
+++ b/libtaskmanager/tasksmodel.cpp
@@ -283,7 +283,7 @@ void TasksModel::Private::initModels()
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::regionGeometryChanged, q, &TasksModel::regionGeometryChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::activityChanged, q, &TasksModel::activityChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByVirtualDesktopChanged, q, &TasksModel::filterByVirtualDesktopChanged);
-    QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByPerScreenVirtualDesktopChanged, q, &TasksModel::filterByPerScreenVirtualDesktopChanged);
+    QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByCurrentVirtualDesktopChanged, q, &TasksModel::filterByCurrentVirtualDesktopChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByScreenChanged, q, &TasksModel::filterByScreenChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByActivityChanged, q, &TasksModel::filterByActivityChanged);
     QObject::connect(filterProxyModel, &TaskFilterProxyModel::filterByRegionChanged, q, &TasksModel::filterByRegionChanged);
@@ -828,7 +828,7 @@ std::optional<bool> TasksModel::Private::lessThanByVirtualDesktop(const QModelIn
 
 void TasksModel::Private::clearVirtualDesktopInfoIfNotNecessary()
 {
-    if (sortMode == SortVirtualDesktop || sortMode == SortWindowPositionHorizontal || filterProxyModel->filterByPerScreenVirtualDesktop()) {
+    if (sortMode == SortVirtualDesktop || sortMode == SortWindowPositionHorizontal || filterProxyModel->filterByCurrentVirtualDesktop()) {
         return;
     }
 
@@ -1187,14 +1187,14 @@ void TasksModel::setFilterByVirtualDesktop(bool filter)
     d->filterProxyModel->setFilterByVirtualDesktop(filter);
 }
 
-bool TasksModel::filterByPerScreenVirtualDesktop() const
+bool TasksModel::filterByCurrentVirtualDesktop() const
 {
-    return d->filterProxyModel->filterByPerScreenVirtualDesktop();
+    return d->filterProxyModel->filterByCurrentVirtualDesktop();
 }
 
-void TasksModel::setFilterByPerScreenVirtualDesktop(bool filter)
+void TasksModel::setFilterByCurrentVirtualDesktop(bool filter)
 {
-    d->filterProxyModel->setFilterByPerScreenVirtualDesktop(filter);
+    d->filterProxyModel->setFilterByCurrentVirtualDesktop(filter);
 
     if (filter) {
         d->virtualDesktopInfo = virtualDesktopInfo();
diff --git a/libtaskmanager/tasksmodel.h b/libtaskmanager/tasksmodel.h
index b06d4c8282..b8e8709be5 100644
--- a/libtaskmanager/tasksmodel.h
+++ b/libtaskmanager/tasksmodel.h
@@ -63,8 +63,8 @@ class TASKMANAGER_EXPORT TasksModel : public QSortFilterProxyModel, public Abstr
     Q_PROPERTY(QString activity READ activity WRITE setActivity NOTIFY activityChanged)
 
     Q_PROPERTY(bool filterByVirtualDesktop READ filterByVirtualDesktop WRITE setFilterByVirtualDesktop NOTIFY filterByVirtualDesktopChanged)
-    Q_PROPERTY(bool filterByPerScreenVirtualDesktop READ filterByPerScreenVirtualDesktop WRITE setFilterByPerScreenVirtualDesktop NOTIFY
-                   filterByPerScreenVirtualDesktopChanged)
+    Q_PROPERTY(bool filterByCurrentVirtualDesktop READ filterByCurrentVirtualDesktop WRITE setFilterByCurrentVirtualDesktop NOTIFY
+                   filterByCurrentVirtualDesktopChanged)
     Q_PROPERTY(bool filterByScreen READ filterByScreen WRITE setFilterByScreen NOTIFY filterByScreenChanged)
     Q_PROPERTY(bool filterByActivity READ filterByActivity WRITE setFilterByActivity NOTIFY filterByActivityChanged)
     Q_PROPERTY(RegionFilterMode::Mode filterByRegion READ filterByRegion WRITE setFilterByRegion NOTIFY filterByRegionChanged)
@@ -257,20 +257,20 @@ public:
      * Whether tasks should be filtered by its screen's virtual desktop.
      * Defaults to @c false.
      *
-     * @see setFilterByPerScreenVirtualDesktop
+     * @see setFilterByCurrentVirtualDesktop
      * @returns @c true if tasks should be filtered by their screen's
      * virtual desktops.
      **/
-    bool filterByPerScreenVirtualDesktop() const;
+    bool filterByCurrentVirtualDesktop() const;
 
     /**
      * Set whether tasks should be filtered by virtual desktop.
      *
-     * @see filterByPerScreenVirtualDesktop
+     * @see filterByCurrentVirtualDesktop
      * @param filter Whether tasks should be filtered by their screen's
      * virtual desktop.
      **/
-    void setFilterByPerScreenVirtualDesktop(bool filter);
+    void setFilterByCurrentVirtualDesktop(bool filter);
 
     /**
      * Whether tasks should be filtered by screen. Defaults to @c false.
@@ -1027,7 +1027,7 @@ Q_SIGNALS:
     void regionGeometryChanged();
     void activityChanged() const;
     void filterByVirtualDesktopChanged() const;
-    void filterByPerScreenVirtualDesktopChanged() const;
+    void filterByCurrentVirtualDesktopChanged() const;
     void filterByScreenChanged() const;
     void filterByActivityChanged() const;
     void filterByRegionChanged();
diff --git a/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp b/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp
index 247c7c8194..4238f00123 100644
--- a/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp
+++ b/wallpapers/image/plugin/utils/maximizedwindowmonitor.cpp
@@ -23,7 +23,7 @@ MaximizedWindowMonitor::MaximizedWindowMonitor(QObject *parent)
 
     setFilterMinimized(true);
     setFilterByActivity(true);
-    setFilterByPerScreenVirtualDesktop(true);
+    setFilterByCurrentVirtualDesktop(true);
     setFilterByRegion(RegionFilterMode::Mode::Intersect);
 }
 
-- 
GitLab

openSUSE Build Service is sponsored by