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
74void TaskFilterProxyModel::setVirtualDesktop(const QVariant &desktop)
75{
76 if (d->virtualDesktop != desktop) {
77 d->virtualDesktop = desktop;
78
79 if (d->filterByVirtualDesktop) {
80 invalidateFilter();
81 }
82
83 Q_EMIT virtualDesktopChanged();
84 }
85}
86
87QRect TaskFilterProxyModel::screenGeometry() const
88{
89 return d->screenGeometry;
90}
91
92void TaskFilterProxyModel::setScreenGeometry(const QRect &geometry)
93{
94 if (d->screenGeometry != geometry) {
95 d->screenGeometry = geometry;
96
97 if (d->filterByScreen) {
98 invalidateFilter();
99 }
100
101 Q_EMIT screenGeometryChanged();
102 }
103}
104
105QRect TaskFilterProxyModel::regionGeometry() const
106{
107 return d->regionGeometry;
108}
109
110void TaskFilterProxyModel::setRegionGeometry(const QRect &geometry)
111{
112 if (d->regionGeometry == geometry) {
113 return;
114 }
115 d->regionGeometry = geometry;
116
117 if (d->filterByRegion != RegionFilterMode::Mode::Disabled) {
118 invalidateFilter();
119 }
120
121 Q_EMIT regionGeometryChanged();
122}
123
124QString TaskFilterProxyModel::activity() const
125{
126 return d->activity;
127}
128
129void TaskFilterProxyModel::setActivity(const QString &activity)
130{
131 if (d->activity != activity) {
132 d->activity = activity;
133
134 if (d->filterByActivity) {
135 invalidateFilter();
136 }
137
138 Q_EMIT activityChanged();
139 }
140}
141
142bool TaskFilterProxyModel::filterByVirtualDesktop() const
143{
144 return d->filterByVirtualDesktop;
145}
146
147void TaskFilterProxyModel::setFilterByVirtualDesktop(bool filter)
148{
149 if (d->filterByVirtualDesktop != filter) {
150 d->filterByVirtualDesktop = filter;
151
152 invalidateFilter();
153
154 Q_EMIT filterByVirtualDesktopChanged();
155 }
156}
157
158bool TaskFilterProxyModel::filterByScreen() const
159{
160 return d->filterByScreen;
161}
162
163void TaskFilterProxyModel::setFilterByScreen(bool filter)
164{
165 if (d->filterByScreen != filter) {
166 d->filterByScreen = filter;
167
168 invalidateFilter();
169
170 Q_EMIT filterByScreenChanged();
171 }
172}
173
174bool TaskFilterProxyModel::filterByActivity() const
175{
176 return d->filterByActivity;
177}
178
179void TaskFilterProxyModel::setFilterByActivity(bool filter)
180{
181 if (d->filterByActivity != filter) {
182 d->filterByActivity = filter;
183
184 invalidateFilter();
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;
202 invalidateFilter();
203 Q_EMIT filterByActivityChanged();
204}
205
206bool TaskFilterProxyModel::filterMinimized() const
207{
208 return d->filterMinimized;
209}
210
211void TaskFilterProxyModel::setFilterMinimized(bool filter)
212{
213 if (d->filterMinimized == filter) {
214 return;
215 }
216
217 d->filterMinimized = filter;
218 invalidateFilter();
219
220 Q_EMIT filterMinimizedChanged();
221}
222
223bool TaskFilterProxyModel::filterNotMinimized() const
224{
225 return d->filterNotMinimized;
226}
227
228void TaskFilterProxyModel::setFilterNotMinimized(bool filter)
229{
230 if (d->filterNotMinimized != filter) {
231 d->filterNotMinimized = filter;
232
233 invalidateFilter();
234
235 Q_EMIT filterNotMinimizedChanged();
236 }
237}
238
239bool TaskFilterProxyModel::filterNotMaximized() const
240{
241 return d->filterNotMaximized;
242}
243
244void TaskFilterProxyModel::setFilterNotMaximized(bool filter)
245{
246 if (d->filterNotMaximized != filter) {
247 d->filterNotMaximized = filter;
248
249 invalidateFilter();
250
251 Q_EMIT filterNotMaximizedChanged();
252 }
253}
254
255bool TaskFilterProxyModel::filterHidden() const
256{
257 return d->filterHidden;
258}
259
260void TaskFilterProxyModel::setFilterHidden(bool filter)
261{
262 if (d->filterHidden != filter) {
263 d->filterHidden = filter;
264
265 invalidateFilter();
266
267 Q_EMIT filterHiddenChanged();
268 }
269}
270
271bool TaskFilterProxyModel::filterSkipTaskbar() const
272{
273 return d->filterSkipTaskbar;
274}
275
276void TaskFilterProxyModel::setFilterSkipTaskbar(bool filter)
277{
278 if (d->filterSkipTaskbar != filter) {
279 d->filterSkipTaskbar = filter;
280
281 invalidateFilter();
282
283 Q_EMIT filterSkipTaskbarChanged();
284 }
285}
286
287bool TaskFilterProxyModel::filterSkipPager() const
288{
289 return d->filterSkipPager;
290}
291
292void TaskFilterProxyModel::setFilterSkipPager(bool filter)
293{
294 if (d->filterSkipPager != filter) {
295 d->filterSkipPager = filter;
296
297 invalidateFilter();
298
299 Q_EMIT filterSkipPagerChanged();
300 }
301}
302
303bool TaskFilterProxyModel::demandingAttentionSkipsFilters() const
304{
305 return d->demandingAttentionSkipsFilters;
306}
307
308void TaskFilterProxyModel::setDemandingAttentionSkipsFilters(bool skip)
309{
310 if (d->demandingAttentionSkipsFilters != skip) {
311 d->demandingAttentionSkipsFilters = skip;
312
313 invalidateFilter();
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()) {
344 if (!sourceIdx.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool()
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}
static bool isPlatformX11()
bool isEmpty() const const
QVariant data(int role) const const
bool isValid() const const
QObject * parent() const const
int x() const const
int y() const const
bool contains(const QPoint &point, bool proper) const const
bool intersects(const QRect &rectangle) const const
bool isValid() const const
QSize size() const const
int x() const const
int y() const const
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-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:42 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.