libs: rework KTaskManager to not cache information other than the window ID

otherwise the name and desktop number have to be refreshed each time a task
window changes and that information may or may not be used in, say, the
pager applet

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2023-10-02 22:15:46 +03:00
parent 9964857908
commit 057b58b76d
4 changed files with 104 additions and 144 deletions

View file

@ -48,110 +48,63 @@ static bool kIsTaskWindow(const WId window)
return true; return true;
} }
static void kUpdateTask(KTaskManager::Task &task, const bool force = false) class KTaskManagerPrivate
{ {
const KWindowInfo kwindowinfo = KWindowSystem::windowInfo(
task.window,
NET::WMVisibleName | NET::WMDesktop
);
if (task.name.isEmpty() || force) {
task.name = kwindowinfo.visibleName();
}
task.desktop = kwindowinfo.desktop();
}
class KTaskManagerPrivate : QObject
{
Q_OBJECT
public: public:
KTaskManagerPrivate(QObject *parent); KTaskManagerPrivate(KTaskManager *ktaskmanager);
QList<KTaskManager::Task> tasks; QList<WId> tasks;
private Q_SLOTS: void _k_slotNewWindow(const WId window);
void slotNewWindow(const WId window); void _k_slotChangedWindow(const WId window);
void slotChangedWindow(const WId window); void _k_slotRemovedWindow(const WId window);
void slotRemovedWindow(const WId window);
private: private:
QMutex m_mutex; QMutex m_mutex;
KTaskManager* m_taskmanager;
}; };
KTaskManagerPrivate::KTaskManagerPrivate(QObject *parent) KTaskManagerPrivate::KTaskManagerPrivate(KTaskManager *ktaskmanager)
: QObject(parent) : m_taskmanager(ktaskmanager)
{ {
foreach (const WId window, KWindowSystem::stackingOrder()) { foreach (const WId window, KWindowSystem::stackingOrder()) {
if (!kIsTaskWindow(window)) { if (!kIsTaskWindow(window)) {
continue; continue;
} }
kDebug() << "adding task for" << window; kDebug() << "adding task window" << window;
KTaskManager::Task task; tasks.append(window);
task.window = window; emit m_taskmanager->taskAdded(window);
task.desktop = s_nodesktop;
kUpdateTask(task);
tasks.append(task);
KTaskManager* ktaskmanager = qobject_cast<KTaskManager*>(parent);
emit ktaskmanager->taskAdded(task);
} }
connect(
KWindowSystem::self(), SIGNAL(windowAdded(WId)),
this, SLOT(slotNewWindow(WId))
);
connect(
KWindowSystem::self(), SIGNAL(windowChanged(WId)),
this, SLOT(slotChangedWindow(WId))
);
connect(
KWindowSystem::self(), SIGNAL(windowRemoved(WId)),
this, SLOT(slotRemovedWindow(WId))
);
} }
void KTaskManagerPrivate::slotNewWindow(const WId window) void KTaskManagerPrivate::_k_slotNewWindow(const WId window)
{ {
if (!kIsTaskWindow(window)) { if (!kIsTaskWindow(window)) {
return; return;
} }
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
kDebug() << "new window task for" << window; kDebug() << "new task window" << window;
KTaskManager::Task task; tasks.append(window);
task.window = window; emit m_taskmanager->taskAdded(window);
task.desktop = s_nodesktop;
kUpdateTask(task);
tasks.append(task);
KTaskManager* ktaskmanager = qobject_cast<KTaskManager*>(parent());
emit ktaskmanager->taskAdded(task);
} }
void KTaskManagerPrivate::slotChangedWindow(const WId window) void KTaskManagerPrivate::_k_slotChangedWindow(const WId window)
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
QMutableListIterator<KTaskManager::Task> iter(tasks); if (tasks.contains(window)) {
while (iter.hasNext()) { kDebug() << "changed task window" << window;
KTaskManager::Task &task = iter.next(); emit m_taskmanager->taskChanged(window);
if (task.window == window) {
kDebug() << "changed window task for" << window;
kUpdateTask(task, true);
KTaskManager* ktaskmanager = qobject_cast<KTaskManager*>(parent());
emit ktaskmanager->taskChanged(task);
break;
}
} }
} }
void KTaskManagerPrivate::slotRemovedWindow(const WId window) void KTaskManagerPrivate::_k_slotRemovedWindow(const WId window)
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
QMutableListIterator<KTaskManager::Task> iter(tasks); const int indexofwindow = tasks.indexOf(window);
while (iter.hasNext()) { if (indexofwindow >= 0) {
const KTaskManager::Task task = iter.next(); kDebug() << "removed task window" << window;
if (task.window == window) { tasks.removeAt(indexofwindow);
kDebug() << "removed window task for" << window; emit m_taskmanager->taskRemoved(window);
iter.remove();
KTaskManager* ktaskmanager = qobject_cast<KTaskManager*>(parent());
emit ktaskmanager->taskRemoved(task);
break;
}
} }
} }
@ -163,6 +116,18 @@ KTaskManager::KTaskManager(QObject *parent)
d(nullptr) d(nullptr)
{ {
d = new KTaskManagerPrivate(this); d = new KTaskManagerPrivate(this);
connect(
KWindowSystem::self(), SIGNAL(windowAdded(WId)),
this, SLOT(_k_slotNewWindow(WId))
);
connect(
KWindowSystem::self(), SIGNAL(windowChanged(WId)),
this, SLOT(_k_slotChangedWindow(WId))
);
connect(
KWindowSystem::self(), SIGNAL(windowRemoved(WId)),
this, SLOT(_k_slotRemovedWindow(WId))
);
} }
KTaskManager::~KTaskManager() KTaskManager::~KTaskManager()
@ -170,41 +135,41 @@ KTaskManager::~KTaskManager()
delete d; delete d;
} }
QList<KTaskManager::Task> KTaskManager::tasks() const QList<WId> KTaskManager::tasks() const
{ {
return d->tasks; return d->tasks;
} }
bool KTaskManager::isActive(const KTaskManager::Task &task) bool KTaskManager::isActive(const WId task)
{ {
const WId activewindow = KWindowSystem::activeWindow(); const WId activewindow = KWindowSystem::activeWindow();
return (task.window == activewindow || KWindowSystem::transientFor(task.window) == activewindow); return (task == activewindow || KWindowSystem::transientFor(task) == activewindow);
} }
bool KTaskManager::demandsAttention(const KTaskManager::Task &task) bool KTaskManager::demandsAttention(const WId task)
{ {
KWindowInfo kwindowinfo = KWindowSystem::windowInfo( KWindowInfo kwindowinfo = KWindowSystem::windowInfo(
task.window, task,
NET::WMState | NET::XAWMState NET::WMState | NET::XAWMState
); );
if (kwindowinfo.hasState(NET::DemandsAttention)) { if (kwindowinfo.hasState(NET::DemandsAttention)) {
return true; return true;
} }
kwindowinfo = KWindowSystem::windowInfo( kwindowinfo = KWindowSystem::windowInfo(
KWindowSystem::transientFor(task.window), KWindowSystem::transientFor(task),
NET::WMState | NET::XAWMState NET::WMState | NET::XAWMState
); );
return kwindowinfo.hasState(NET::DemandsAttention); return kwindowinfo.hasState(NET::DemandsAttention);
} }
void KTaskManager::activateRaiseOrIconify(const KTaskManager::Task &task) void KTaskManager::activateRaiseOrIconify(const WId task)
{ {
if (isActive(task)) { if (isActive(task)) {
KWindowSystem::minimizeWindow(task.window); KWindowSystem::minimizeWindow(task);
return; return;
} }
KWindowSystem::activateWindow(task.window); KWindowSystem::activateWindow(task);
KWindowSystem::raiseWindow(task.window); KWindowSystem::raiseWindow(task);
} }
KTaskManager* KTaskManager::self() KTaskManager* KTaskManager::self()
@ -212,4 +177,4 @@ KTaskManager* KTaskManager::self()
return globalktaskmanager; return globalktaskmanager;
} }
#include "ktaskmanager.moc" #include "moc_ktaskmanager.cpp"

View file

@ -22,7 +22,7 @@
#include "kworkspace_export.h" #include "kworkspace_export.h"
#include <QObject> #include <QObject>
#include <QMenu> #include <qwindowdefs.h>
class KTaskManagerPrivate; class KTaskManagerPrivate;
@ -30,34 +30,29 @@ class KWORKSPACE_EXPORT KTaskManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
struct Task
{
QString name;
int desktop;
WId window;
};
KTaskManager(QObject *parent = nullptr); KTaskManager(QObject *parent = nullptr);
~KTaskManager(); ~KTaskManager();
QList<KTaskManager::Task> tasks() const; QList<WId> tasks() const;
static bool isActive(const KTaskManager::Task &task); static bool isActive(const WId task);
static bool demandsAttention(const KTaskManager::Task &task); static bool demandsAttention(const WId task);
static void activateRaiseOrIconify(const KTaskManager::Task &task); static void activateRaiseOrIconify(const WId task);
static KTaskManager* self(); static KTaskManager* self();
Q_SIGNALS: Q_SIGNALS:
void taskAdded(const KTaskManager::Task &task); void taskAdded(const WId task);
void taskChanged(const KTaskManager::Task &task); void taskChanged(const WId task);
void taskRemoved(const KTaskManager::Task &task); void taskRemoved(const WId task);
private: private:
friend KTaskManagerPrivate; friend KTaskManagerPrivate;
Q_DISABLE_COPY(KTaskManager); Q_DISABLE_COPY(KTaskManager);
KTaskManagerPrivate* d; KTaskManagerPrivate* d;
Q_PRIVATE_SLOT(d, void _k_slotNewWindow(const WId window));
Q_PRIVATE_SLOT(d, void _k_slotChangedWindow(const WId window));
Q_PRIVATE_SLOT(d, void _k_slotRemovedWindow(const WId window));
}; };
Q_DECLARE_METATYPE(KTaskManager::Task);
#endif // KTASKMANAGER_H #endif // KTASKMANAGER_H

View file

@ -93,13 +93,13 @@ class PagerDialog : public Plasma::Dialog
public: public:
explicit PagerDialog(QWidget *parent = nullptr); explicit PagerDialog(QWidget *parent = nullptr);
void updateTasks(const QList<KTaskManager::Task> &tasks); void updateTasks(const QList<WId> &tasks);
private: private:
QGraphicsScene* m_scene; QGraphicsScene* m_scene;
QGraphicsWidget* m_widget; QGraphicsWidget* m_widget;
QGraphicsLinearLayout* m_layout; QGraphicsLinearLayout* m_layout;
QList<KTaskManager::Task> m_tasks; QList<WId> m_tasks;
}; };
PagerDialog::PagerDialog(QWidget *parent) PagerDialog::PagerDialog(QWidget *parent)
@ -121,7 +121,7 @@ PagerDialog::PagerDialog(QWidget *parent)
setGraphicsWidget(m_widget); setGraphicsWidget(m_widget);
} }
void PagerDialog::updateTasks(const QList<KTaskManager::Task> &tasks) void PagerDialog::updateTasks(const QList<WId> &tasks)
{ {
// TODO: // TODO:
m_tasks = tasks; m_tasks = tasks;
@ -132,7 +132,7 @@ class PagerIcon : public Plasma::IconWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit PagerIcon(const KTaskManager::Task &task, QGraphicsItem *parent); explicit PagerIcon(const WId task, QGraphicsItem *parent);
WId taskWindow() const; WId taskWindow() const;
void animatedShow(); void animatedShow();
@ -144,10 +144,10 @@ private Q_SLOTS:
void slotWindowPreviewActivated(const WId window); void slotWindowPreviewActivated(const WId window);
private: private:
KTaskManager::Task m_task; WId m_task;
}; };
PagerIcon::PagerIcon(const KTaskManager::Task &task, QGraphicsItem *parent) PagerIcon::PagerIcon(const WId task, QGraphicsItem *parent)
: Plasma::IconWidget(parent), : Plasma::IconWidget(parent),
m_task(task) m_task(task)
{ {
@ -164,7 +164,7 @@ PagerIcon::PagerIcon(const KTaskManager::Task &task, QGraphicsItem *parent)
WId PagerIcon::taskWindow() const WId PagerIcon::taskWindow() const
{ {
return m_task.window; return m_task;
} }
void PagerIcon::animatedShow() void PagerIcon::animatedShow()
@ -190,10 +190,11 @@ void PagerIcon::animatedRemove()
void PagerIcon::updateIconAndToolTip() void PagerIcon::updateIconAndToolTip()
{ {
setIcon(KWindowSystem::icon(m_task.window)); const KWindowInfo kwindowinfo = KWindowSystem::windowInfo(m_task, NET::WMVisibleName);
setIcon(KWindowSystem::icon(m_task));
Plasma::ToolTipContent plasmatooltip; Plasma::ToolTipContent plasmatooltip;
plasmatooltip.setMainText(QString::fromLatin1("<center>%1</center>").arg(m_task.name)); plasmatooltip.setMainText(QString::fromLatin1("<center>%1</center>").arg(kwindowinfo.visibleName()));
plasmatooltip.setWindowToPreview(m_task.window); plasmatooltip.setWindowToPreview(m_task);
plasmatooltip.setClickable(true); plasmatooltip.setClickable(true);
Plasma::ToolTipManager::self()->setContent(this, plasmatooltip); Plasma::ToolTipManager::self()->setContent(this, plasmatooltip);
} }
@ -230,9 +231,9 @@ private Q_SLOTS:
void slotClicked(const Qt::MouseButton button); void slotClicked(const Qt::MouseButton button);
void slotUpdate(); void slotUpdate();
void slotUpdateSvg(); void slotUpdateSvg();
void slotTaskAdded(const KTaskManager::Task &task); void slotTaskAdded(const WId task);
void slotTaskChanged(const KTaskManager::Task &task); void slotTaskChanged(const WId task);
void slotTaskRemoved(const KTaskManager::Task &task); void slotTaskRemoved(const WId task);
void slotCheckSpace(); void slotCheckSpace();
void slotShowDialog(); void slotShowDialog();
@ -264,7 +265,7 @@ PagerSvg::PagerSvg(const int desktop, const Qt::Orientation orientation, QGraphi
slotUpdateSvg(); slotUpdateSvg();
setAcceptHoverEvents(true); setAcceptHoverEvents(true);
foreach (const KTaskManager::Task &task, KTaskManager::self()->tasks()) { foreach (const WId task, KTaskManager::self()->tasks()) {
slotTaskAdded(task); slotTaskAdded(task);
} }
@ -277,16 +278,16 @@ PagerSvg::PagerSvg(const int desktop, const Qt::Orientation orientation, QGraphi
this, SLOT(slotUpdate()) this, SLOT(slotUpdate())
); );
connect( connect(
KTaskManager::self(), SIGNAL(taskAdded(KTaskManager::Task)), KTaskManager::self(), SIGNAL(taskAdded(WId)),
this, SLOT(slotTaskAdded(KTaskManager::Task)) this, SLOT(slotTaskAdded(WId))
); );
connect( connect(
KTaskManager::self(), SIGNAL(taskChanged(KTaskManager::Task)), KTaskManager::self(), SIGNAL(taskChanged(WId)),
this, SLOT(slotTaskChanged(KTaskManager::Task)) this, SLOT(slotTaskChanged(WId))
); );
connect( connect(
KTaskManager::self(), SIGNAL(taskRemoved(KTaskManager::Task)), KTaskManager::self(), SIGNAL(taskRemoved(WId)),
this, SLOT(slotTaskRemoved(KTaskManager::Task)) this, SLOT(slotTaskRemoved(WId))
); );
connect( connect(
Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()),
@ -355,13 +356,13 @@ void PagerSvg::slotUpdateSvg()
} }
} }
void PagerSvg::slotTaskAdded(const KTaskManager::Task &task) void PagerSvg::slotTaskAdded(const WId task)
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
if (m_spacer) { if (m_spacer) {
m_layout->removeItem(m_spacer); m_layout->removeItem(m_spacer);
} }
const KWindowInfo kwindowinfo = KWindowSystem::windowInfo(task.window, NET::WMDesktop); const KWindowInfo kwindowinfo = KWindowSystem::windowInfo(task, NET::WMDesktop);
if (kwindowinfo.isOnDesktop(m_desktop)) { if (kwindowinfo.isOnDesktop(m_desktop)) {
PagerIcon* pagericon = new PagerIcon(task, this); PagerIcon* pagericon = new PagerIcon(task, this);
connect( connect(
@ -393,18 +394,18 @@ void PagerSvg::slotTaskAdded(const KTaskManager::Task &task)
slotCheckSpace(); slotCheckSpace();
} }
void PagerSvg::slotTaskChanged(const KTaskManager::Task &task) void PagerSvg::slotTaskChanged(const WId task)
{ {
// special case for tasks moved from one virtual desktop to another, the check is done via // special case for tasks moved from one virtual desktop to another, the check is done via
// KWindowInfo::isOnDesktop() because tasks may be shown on all desktops // KWindowInfo::isOnDesktop() because tasks may be shown on all desktops
const KWindowInfo kwindowinfo = KWindowSystem::windowInfo(task.window, NET::WMDesktop); const KWindowInfo kwindowinfo = KWindowSystem::windowInfo(task, NET::WMDesktop);
if (!kwindowinfo.isOnDesktop(m_desktop)) { if (!kwindowinfo.isOnDesktop(m_desktop)) {
slotTaskRemoved(task); slotTaskRemoved(task);
} else { } else {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
PagerIcon* foundpagericon = nullptr; PagerIcon* foundpagericon = nullptr;
foreach (PagerIcon* pagericon, m_pagericons) { foreach (PagerIcon* pagericon, m_pagericons) {
if (pagericon->taskWindow() == task.window) { if (pagericon->taskWindow() == task) {
foundpagericon = pagericon; foundpagericon = pagericon;
break; break;
} }
@ -418,11 +419,11 @@ void PagerSvg::slotTaskChanged(const KTaskManager::Task &task)
} }
} }
void PagerSvg::slotTaskRemoved(const KTaskManager::Task &task) void PagerSvg::slotTaskRemoved(const WId task)
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
foreach (PagerIcon* pagericon, m_pagericons) { foreach (PagerIcon* pagericon, m_pagericons) {
if (pagericon->taskWindow() == task.window) { if (pagericon->taskWindow() == task) {
m_pagericons.removeAll(pagericon); m_pagericons.removeAll(pagericon);
pagericon->animatedRemove(); pagericon->animatedRemove();
break; break;

View file

@ -104,16 +104,21 @@ void SwitchWindow::makeMenu()
QMultiHash<int, QAction*> desktops; QMultiHash<int, QAction*> desktops;
// make all the window actions // make all the window actions
foreach (const KTaskManager::Task &task, KTaskManager::self()->tasks()) { foreach (const WId task, KTaskManager::self()->tasks()) {
if (task.name.isEmpty()) { const KWindowInfo kwindowinfo = KWindowSystem::windowInfo(
kDebug() << "skipping task with empty name" << task.window; task,
NET::WMVisibleName | NET::WMDesktop
);
const QString taskname = kwindowinfo.visibleName();
if (taskname.isEmpty()) {
kDebug() << "skipping task with empty name" << task;
continue; continue;
} }
QAction *action = new QAction(task.name, m_menu); QAction *action = new QAction(taskname, m_menu);
action->setIcon(KIcon(KWindowSystem::icon(task.window))); action->setIcon(KIcon(KWindowSystem::icon(task)));
action->setData(qlonglong(task.window)); action->setData(qlonglong(task));
desktops.insert(task.desktop, action); desktops.insert(kwindowinfo.desktop(), action);
} }
//sort into menu //sort into menu
@ -180,15 +185,9 @@ QList<QAction*> SwitchWindow::contextualActions()
void SwitchWindow::switchTo(QAction *action) void SwitchWindow::switchTo(QAction *action)
{ {
const qlonglong taskwindow = action->data().toLongLong(); const qlonglong task = action->data().toLongLong();
kDebug() << "task window" << taskwindow; kDebug() << "task window" << task;
foreach (const KTaskManager::Task &task, KTaskManager::self()->tasks()) { KTaskManager::self()->activateRaiseOrIconify(task);
if (task.window == taskwindow) {
KTaskManager::self()->activateRaiseOrIconify(task);
return;
}
}
kWarning() << "could not find the task window";
} }
void SwitchWindow::clearWindowsOrder() void SwitchWindow::clearWindowsOrder()