Plasma-workspace

taskfilterproxymodel.cpp
1/*
2 SPDX-FileCopyrightText: 2016 Eike Hein <hein@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "taskfilterproxymodel.h"
8#include "abstracttasksmodel.h"
9
10#include "launchertasksmodel_p.h"
11
12#include "config-X11.h"
13#if HAVE_X11
14#include <QGuiApplication>
15#include <QScreen>
16
17#include <KWindowSystem>
18#endif
19
20namespace TaskManager
21{
22class Q_DECL_HIDDEN TaskFilterProxyModel::Private
23{
24public:
25 Private(TaskFilterProxyModel *q);
26
27 AbstractTasksModelIface *sourceTasksModel = nullptr;
28
29 QVariant virtualDesktop;
30 QRect screenGeometry;
31 QRect regionGeometry;
32 QString activity;
33
34 bool filterByVirtualDesktop = false;
35 bool filterByScreen = false;
36 bool filterByActivity = false;
37 RegionFilterMode::Mode filterByRegion = RegionFilterMode::Mode::Disabled;
38 bool filterMinimized = false;
39 bool filterNotMinimized = false;
40 bool filterNotMaximized = false;
41 bool filterHidden = false;
42 bool filterSkipTaskbar = true;
43 bool filterSkipPager = false;
44
45 bool demandingAttentionSkipsFilters = true;
46};
47
48TaskFilterProxyModel::Private::Private(TaskFilterProxyModel *)
49{
50}
51
52TaskFilterProxyModel::TaskFilterProxyModel(QObject *parent)
54 , d(new Private(this))
55{
56}
57
58TaskFilterProxyModel::~TaskFilterProxyModel()
59{
60}
61
62void TaskFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
63{
64 d->sourceTasksModel = dynamic_cast<AbstractTasksModelIface *>(sourceModel);
65
67}
68
69QVariant TaskFilterProxyModel::virtualDesktop() const
70{
71 return d->virtualDesktop;
72}
73
75{
76 if (d->virtualDesktop != desktop) {
77 d->virtualDesktop = desktop;
78
79 if (d->filterByVirtualDesktop) {
81 }
82
83 Q_EMIT virtualDesktopChanged();
84 }
85}
86
87QRect TaskFilterProxyModel::screenGeometry() const
88{
89 return d->screenGeometry;
90}
91
93{
94 if (d->screenGeometry != geometry) {
95 d->screenGeometry = geometry;
96
97 if (d->filterByScreen) {
99 }
100
101 Q_EMIT screenGeometryChanged();
102 }
103}
104
105QRect TaskFilterProxyModel::regionGeometry() const
106{
107 return d->regionGeometry;
108}
109
111{
112 if (d->regionGeometry == geometry) {
113 return;
114 }
115 d->regionGeometry = geometry;
116
117 if (d->filterByRegion != RegionFilterMode::Mode::Disabled) {
119 }
120
121 Q_EMIT regionGeometryChanged();
122}
123
124QString TaskFilterProxyModel::activity() const
125{
126 return d->activity;
127}
128
130{
131 if (d->activity != activity) {
132 d->activity = activity;
133
134 if (d->filterByActivity) {
136 }
137
138 Q_EMIT activityChanged();
139 }
140}
141
142bool TaskFilterProxyModel::filterByVirtualDesktop() const
143{
144 return d->filterByVirtualDesktop;
145}
146
148{
149 if (d->filterByVirtualDesktop != filter) {
150 d->filterByVirtualDesktop = filter;
151
153
154 Q_EMIT filterByVirtualDesktopChanged();
155 }
156}
157
158bool TaskFilterProxyModel::filterByScreen() const
159{
160 return d->filterByScreen;
161}
162
164{
165 if (d->filterByScreen != filter) {
166 d->filterByScreen = filter;
167
169
170 Q_EMIT filterByScreenChanged();
171 }
172}
173
174bool TaskFilterProxyModel::filterByActivity() const
175{
176 return d->filterByActivity;
177}
178
180{
181 if (d->filterByActivity != filter) {
182 d->filterByActivity = filter;
183
185
186 Q_EMIT filterByActivityChanged();
187 }
188}
189
190RegionFilterMode::Mode TaskFilterProxyModel::filterByRegion() const
191{
192 return d->filterByRegion;
193}
194
195void TaskFilterProxyModel::setFilterByRegion(RegionFilterMode::Mode mode)
196{
197 if (d->filterByRegion == mode) {
198 return;
199 }
200
201 d->filterByRegion = mode;
203 Q_EMIT filterByActivityChanged();
204}
205
206bool TaskFilterProxyModel::filterMinimized() const
207{
208 return d->filterMinimized;
209}
210
212{
213 if (d->filterMinimized == filter) {
214 return;
215 }
216
217 d->filterMinimized = filter;
219
220 Q_EMIT filterMinimizedChanged();
221}
222
223bool TaskFilterProxyModel::filterNotMinimized() const
224{
225 return d->filterNotMinimized;
226}
227
229{
230 if (d->filterNotMinimized != filter) {
231 d->filterNotMinimized = filter;
232
234
235 Q_EMIT filterNotMinimizedChanged();
236 }
237}
238
239bool TaskFilterProxyModel::filterNotMaximized() const
240{
241 return d->filterNotMaximized;
242}
243
245{
246 if (d->filterNotMaximized != filter) {
247 d->filterNotMaximized = filter;
248
250
251 Q_EMIT filterNotMaximizedChanged();
252 }
253}
254
255bool TaskFilterProxyModel::filterHidden() const
256{
257 return d->filterHidden;
258}
259
261{
262 if (d->filterHidden != filter) {
263 d->filterHidden = filter;
264
266
267 Q_EMIT filterHiddenChanged();
268 }
269}
270
271bool TaskFilterProxyModel::filterSkipTaskbar() const
272{
273 return d->filterSkipTaskbar;
274}
275
277{
278 if (d->filterSkipTaskbar != filter) {
279 d->filterSkipTaskbar = filter;
280
282
283 Q_EMIT filterSkipTaskbarChanged();
284 }
285}
286
287bool TaskFilterProxyModel::filterSkipPager() const
288{
289 return d->filterSkipPager;
290}
291
293{
294 if (d->filterSkipPager != filter) {
295 d->filterSkipPager = filter;
296
298
299 Q_EMIT filterSkipPagerChanged();
300 }
301}
302
303bool TaskFilterProxyModel::demandingAttentionSkipsFilters() const
304{
305 return d->demandingAttentionSkipsFilters;
306}
307
309{
310 if (d->demandingAttentionSkipsFilters != skip) {
311 d->demandingAttentionSkipsFilters = skip;
312
314
315 Q_EMIT demandingAttentionSkipsFiltersChanged();
316 }
317}
318
319QModelIndex TaskFilterProxyModel::mapIfaceToSource(const QModelIndex &index) const
320{
321 return mapToSource(index);
322}
323
324bool TaskFilterProxyModel::acceptsRow(int sourceRow) const
325{
326 const QModelIndex &sourceIdx = sourceModel()->index(sourceRow, 0);
327
328 if (!sourceIdx.isValid()) {
329 return false;
330 }
331
332 // Filter tasks that are not to be shown on the task bar.
333 if (d->filterSkipTaskbar && sourceIdx.data(AbstractTasksModel::SkipTaskbar).toBool()) {
334 return false;
335 }
336
337 // Filter tasks that are not to be shown on the pager.
338 if (d->filterSkipPager && sourceIdx.data(AbstractTasksModel::SkipPager).toBool()) {
339 return false;
340 }
341
342 // Filter by virtual desktop.
343 if (d->filterByVirtualDesktop && !d->virtualDesktop.isNull()) {
345 && (!d->demandingAttentionSkipsFilters || !sourceIdx.data(AbstractTasksModel::IsDemandingAttention).toBool())) {
346 const QVariantList &virtualDesktops = sourceIdx.data(AbstractTasksModel::VirtualDesktops).toList();
347
348 if (!virtualDesktops.isEmpty() && !virtualDesktops.contains(d->virtualDesktop)) {
349 return false;
350 }
351 }
352 }
353
354 // Filter by screen.
355 if (d->filterByScreen && d->screenGeometry.isValid()) {
356 const QRect &screenGeometry = sourceIdx.data(AbstractTasksModel::ScreenGeometry).toRect();
357
358 if (screenGeometry.isValid() && screenGeometry != d->screenGeometry) {
359 return false;
360 }
361 }
362
363 // Filter by region
364 if (d->filterByRegion != RegionFilterMode::Mode::Disabled && d->regionGeometry.isValid()) {
365 QRect windowGeometry = sourceIdx.data(AbstractTasksModel::Geometry).toRect();
366
367 QRect regionGeometry = d->regionGeometry;
368#if HAVE_X11
369 if (static const bool isX11 = KWindowSystem::isPlatformX11(); isX11 && windowGeometry.isValid()) {
370 // On X11, in regionGeometry, the original point of the topLeft position belongs to the device coordinate system
371 // but the size belongs to the logical coordinate system (which means the reported size is already divided by DPR)
372 // Converting regionGeometry to device coordinate system is better than converting windowGeometry to logical
373 // coordinate system because the window may span multiple screens, while the region is always on one screen.
374 const double devicePixelRatio = qGuiApp->devicePixelRatio();
375 const QPoint screenTopLeft = d->screenGeometry.topLeft();
376 const QPoint regionTopLeft =
377 screenTopLeft + QPoint(regionGeometry.x() - screenTopLeft.x(), regionGeometry.y() - screenTopLeft.y()) * devicePixelRatio;
378 regionGeometry = QRect(regionTopLeft, regionGeometry.size() * devicePixelRatio);
379 }
380#endif
381 switch (d->filterByRegion) {
382 case RegionFilterMode::Mode::Inside: {
383 if (!regionGeometry.contains(windowGeometry)) {
384 return false;
385 }
386 break;
387 }
388 case RegionFilterMode::Mode::Intersect: {
389 if (!regionGeometry.intersects(windowGeometry)) {
390 return false;
391 }
392 break;
393 }
394 case RegionFilterMode::Mode::Outside: {
395 if (regionGeometry.contains(windowGeometry)) {
396 return false;
397 }
398 break;
399 }
400 default:
401 break;
402 }
403 }
404
405 // Filter by activity.
406 if (d->filterByActivity && !d->activity.isEmpty()) {
407 if (!d->demandingAttentionSkipsFilters || !sourceIdx.data(AbstractTasksModel::IsDemandingAttention).toBool()) {
408 const QVariant &activities = sourceIdx.data(AbstractTasksModel::Activities);
409
410 if (!activities.isNull()) {
411 const QStringList l = activities.toStringList();
412
413 if (!l.isEmpty() && !l.contains(NULL_UUID) && !l.contains(d->activity)) {
414 return false;
415 }
416 }
417 }
418 }
419
420 // Filter not minimized.
421 if (d->filterNotMinimized) {
422 bool isMinimized = sourceIdx.data(AbstractTasksModel::IsMinimized).toBool();
423
424 if (!isMinimized) {
425 return false;
426 }
427 }
428
429 // Filter out minimized windows
430 if (d->filterMinimized) {
431 const bool isMinimized = sourceIdx.data(AbstractTasksModel::IsMinimized).toBool();
432
433 if (isMinimized) {
434 return false;
435 }
436 }
437
438 // Filter not maximized.
439 if (d->filterNotMaximized) {
440 bool isMaximized = sourceIdx.data(AbstractTasksModel::IsMaximized).toBool();
441
442 if (!isMaximized) {
443 return false;
444 }
445 }
446
447 // Filter hidden.
448 if (d->filterHidden) {
449 bool isHidden = sourceIdx.data(AbstractTasksModel::IsHidden).toBool();
450
451 if (isHidden) {
452 return false;
453 }
454 }
455
456 return true;
457}
458
459bool TaskFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
460{
461 Q_UNUSED(sourceParent)
462
463 return acceptsRow(sourceRow);
464}
465
466}
467
468#include "moc_taskfilterproxymodel.cpp"
static bool isPlatformX11()
@ Activities
Activities for the task (i.e.
@ IsDemandingAttention
Task is demanding attention.
@ IsHidden
Task (i.e window) is hidden on screen.
@ SkipTaskbar
Task should not be shown in a 'task bar' user interface.
@ VirtualDesktops
Virtual desktops for the task (i.e.
@ SkipPager
Task should not to be shown in a 'pager' user interface.
@ IsOnAllVirtualDesktops
Task is on all virtual desktops.
@ Geometry
The task's geometry (i.e.
@ ScreenGeometry
Screen geometry for the task (i.e.
A proxy tasks model filtering its source model by various properties.
void setFilterByScreen(bool filter)
Set whether tasks should be filtered by screen.
void setActivity(const QString &activity)
Set the id of the activity to use in filtering by activity.
bool acceptsRow(int sourceRow) const
Returns whether the filter model accepts this source row.
void setFilterSkipTaskbar(bool filter)
Set whether tasks which should be omitted from 'task bars' should be filtered.
void setVirtualDesktop(const QVariant &desktop=QVariant())
Set the id of the virtual desktop to use in filtering by virtual desktop.
void setRegionGeometry(const QRect &geometry)
Set the geometry of the screen to use in filtering by region.
void setFilterNotMinimized(bool filter)
Set whether non-minimized tasks should be filtered.
void setScreenGeometry(const QRect &geometry)
Set the geometry of the screen to use in filtering by screen.
void setDemandingAttentionSkipsFilters(bool skip)
Sets whether tasks which demand attention should bypass filters by virtual desktop or activity.
void setFilterByActivity(bool filter)
Set whether tasks should be filtered by activity.
void setFilterNotMaximized(bool filter)
Set whether non-maximized tasks should be filtered.
void setFilterByRegion(RegionFilterMode::Mode mode)
Set whether tasks should be filtered by region.
void setFilterHidden(bool filter)
Set whether hidden tasks should be filtered.
void setFilterByVirtualDesktop(bool filter)
Set whether tasks should be filtered by virtual desktop.
void setFilterSkipPager(bool filter)
Set whether tasks which should be omitted from 'pagers' should be filtered.
void setFilterMinimized(bool filter)
Sets whether non-minimized tasks should be filtered out.
virtual QModelIndex parent(const QModelIndex &index) const const=0
bool isEmpty() const const
QVariant data(int role) const const
bool isValid() const const
QObject(QObject *parent)
Q_EMITQ_EMIT
int x() const const
int y() const const
bool isValid() const const
QSortFilterProxyModel(QObject *parent)
virtual void setSourceModel(QAbstractItemModel *sourceModel) override
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
bool isNull() const const
bool toBool() const const
QList< QVariant > toList() const const
QRect toRect() const const
QStringList toStringList() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:57:53 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.