File indexing completed on 2024-05-05 05:38:34
0001 /* 0002 SPDX-FileCopyrightText: 2016 Eike Hein <hein@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "taskfilterproxymodel.h" 0008 #include "abstracttasksmodel.h" 0009 0010 #include "launchertasksmodel_p.h" 0011 0012 #include "config-X11.h" 0013 #if HAVE_X11 0014 #include <QGuiApplication> 0015 #include <QScreen> 0016 0017 #include <KWindowSystem> 0018 #endif 0019 0020 namespace TaskManager 0021 { 0022 class Q_DECL_HIDDEN TaskFilterProxyModel::Private 0023 { 0024 public: 0025 Private(TaskFilterProxyModel *q); 0026 0027 AbstractTasksModelIface *sourceTasksModel = nullptr; 0028 0029 QVariant virtualDesktop; 0030 QRect screenGeometry; 0031 QRect regionGeometry; 0032 QString activity; 0033 0034 bool filterByVirtualDesktop = false; 0035 bool filterByScreen = false; 0036 bool filterByActivity = false; 0037 RegionFilterMode::Mode filterByRegion = RegionFilterMode::Mode::Disabled; 0038 bool filterMinimized = false; 0039 bool filterNotMinimized = false; 0040 bool filterNotMaximized = false; 0041 bool filterHidden = false; 0042 bool filterSkipTaskbar = true; 0043 bool filterSkipPager = false; 0044 0045 bool demandingAttentionSkipsFilters = true; 0046 }; 0047 0048 TaskFilterProxyModel::Private::Private(TaskFilterProxyModel *) 0049 { 0050 } 0051 0052 TaskFilterProxyModel::TaskFilterProxyModel(QObject *parent) 0053 : QSortFilterProxyModel(parent) 0054 , d(new Private(this)) 0055 { 0056 } 0057 0058 TaskFilterProxyModel::~TaskFilterProxyModel() 0059 { 0060 } 0061 0062 void TaskFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) 0063 { 0064 d->sourceTasksModel = dynamic_cast<AbstractTasksModelIface *>(sourceModel); 0065 0066 QSortFilterProxyModel::setSourceModel(sourceModel); 0067 } 0068 0069 QVariant TaskFilterProxyModel::virtualDesktop() const 0070 { 0071 return d->virtualDesktop; 0072 } 0073 0074 void TaskFilterProxyModel::setVirtualDesktop(const QVariant &desktop) 0075 { 0076 if (d->virtualDesktop != desktop) { 0077 d->virtualDesktop = desktop; 0078 0079 if (d->filterByVirtualDesktop) { 0080 invalidateFilter(); 0081 } 0082 0083 Q_EMIT virtualDesktopChanged(); 0084 } 0085 } 0086 0087 QRect TaskFilterProxyModel::screenGeometry() const 0088 { 0089 return d->screenGeometry; 0090 } 0091 0092 void TaskFilterProxyModel::setScreenGeometry(const QRect &geometry) 0093 { 0094 if (d->screenGeometry != geometry) { 0095 d->screenGeometry = geometry; 0096 0097 if (d->filterByScreen) { 0098 invalidateFilter(); 0099 } 0100 0101 Q_EMIT screenGeometryChanged(); 0102 } 0103 } 0104 0105 QRect TaskFilterProxyModel::regionGeometry() const 0106 { 0107 return d->regionGeometry; 0108 } 0109 0110 void TaskFilterProxyModel::setRegionGeometry(const QRect &geometry) 0111 { 0112 if (d->regionGeometry == geometry) { 0113 return; 0114 } 0115 d->regionGeometry = geometry; 0116 0117 if (d->filterByRegion != RegionFilterMode::Mode::Disabled) { 0118 invalidateFilter(); 0119 } 0120 0121 Q_EMIT regionGeometryChanged(); 0122 } 0123 0124 QString TaskFilterProxyModel::activity() const 0125 { 0126 return d->activity; 0127 } 0128 0129 void TaskFilterProxyModel::setActivity(const QString &activity) 0130 { 0131 if (d->activity != activity) { 0132 d->activity = activity; 0133 0134 if (d->filterByActivity) { 0135 invalidateFilter(); 0136 } 0137 0138 Q_EMIT activityChanged(); 0139 } 0140 } 0141 0142 bool TaskFilterProxyModel::filterByVirtualDesktop() const 0143 { 0144 return d->filterByVirtualDesktop; 0145 } 0146 0147 void TaskFilterProxyModel::setFilterByVirtualDesktop(bool filter) 0148 { 0149 if (d->filterByVirtualDesktop != filter) { 0150 d->filterByVirtualDesktop = filter; 0151 0152 invalidateFilter(); 0153 0154 Q_EMIT filterByVirtualDesktopChanged(); 0155 } 0156 } 0157 0158 bool TaskFilterProxyModel::filterByScreen() const 0159 { 0160 return d->filterByScreen; 0161 } 0162 0163 void TaskFilterProxyModel::setFilterByScreen(bool filter) 0164 { 0165 if (d->filterByScreen != filter) { 0166 d->filterByScreen = filter; 0167 0168 invalidateFilter(); 0169 0170 Q_EMIT filterByScreenChanged(); 0171 } 0172 } 0173 0174 bool TaskFilterProxyModel::filterByActivity() const 0175 { 0176 return d->filterByActivity; 0177 } 0178 0179 void TaskFilterProxyModel::setFilterByActivity(bool filter) 0180 { 0181 if (d->filterByActivity != filter) { 0182 d->filterByActivity = filter; 0183 0184 invalidateFilter(); 0185 0186 Q_EMIT filterByActivityChanged(); 0187 } 0188 } 0189 0190 RegionFilterMode::Mode TaskFilterProxyModel::filterByRegion() const 0191 { 0192 return d->filterByRegion; 0193 } 0194 0195 void TaskFilterProxyModel::setFilterByRegion(RegionFilterMode::Mode mode) 0196 { 0197 if (d->filterByRegion == mode) { 0198 return; 0199 } 0200 0201 d->filterByRegion = mode; 0202 invalidateFilter(); 0203 Q_EMIT filterByActivityChanged(); 0204 } 0205 0206 bool TaskFilterProxyModel::filterMinimized() const 0207 { 0208 return d->filterMinimized; 0209 } 0210 0211 void TaskFilterProxyModel::setFilterMinimized(bool filter) 0212 { 0213 if (d->filterMinimized == filter) { 0214 return; 0215 } 0216 0217 d->filterMinimized = filter; 0218 invalidateFilter(); 0219 0220 Q_EMIT filterMinimizedChanged(); 0221 } 0222 0223 bool TaskFilterProxyModel::filterNotMinimized() const 0224 { 0225 return d->filterNotMinimized; 0226 } 0227 0228 void TaskFilterProxyModel::setFilterNotMinimized(bool filter) 0229 { 0230 if (d->filterNotMinimized != filter) { 0231 d->filterNotMinimized = filter; 0232 0233 invalidateFilter(); 0234 0235 Q_EMIT filterNotMinimizedChanged(); 0236 } 0237 } 0238 0239 bool TaskFilterProxyModel::filterNotMaximized() const 0240 { 0241 return d->filterNotMaximized; 0242 } 0243 0244 void TaskFilterProxyModel::setFilterNotMaximized(bool filter) 0245 { 0246 if (d->filterNotMaximized != filter) { 0247 d->filterNotMaximized = filter; 0248 0249 invalidateFilter(); 0250 0251 Q_EMIT filterNotMaximizedChanged(); 0252 } 0253 } 0254 0255 bool TaskFilterProxyModel::filterHidden() const 0256 { 0257 return d->filterHidden; 0258 } 0259 0260 void TaskFilterProxyModel::setFilterHidden(bool filter) 0261 { 0262 if (d->filterHidden != filter) { 0263 d->filterHidden = filter; 0264 0265 invalidateFilter(); 0266 0267 Q_EMIT filterHiddenChanged(); 0268 } 0269 } 0270 0271 bool TaskFilterProxyModel::filterSkipTaskbar() const 0272 { 0273 return d->filterSkipTaskbar; 0274 } 0275 0276 void TaskFilterProxyModel::setFilterSkipTaskbar(bool filter) 0277 { 0278 if (d->filterSkipTaskbar != filter) { 0279 d->filterSkipTaskbar = filter; 0280 0281 invalidateFilter(); 0282 0283 Q_EMIT filterSkipTaskbarChanged(); 0284 } 0285 } 0286 0287 bool TaskFilterProxyModel::filterSkipPager() const 0288 { 0289 return d->filterSkipPager; 0290 } 0291 0292 void TaskFilterProxyModel::setFilterSkipPager(bool filter) 0293 { 0294 if (d->filterSkipPager != filter) { 0295 d->filterSkipPager = filter; 0296 0297 invalidateFilter(); 0298 0299 Q_EMIT filterSkipPagerChanged(); 0300 } 0301 } 0302 0303 bool TaskFilterProxyModel::demandingAttentionSkipsFilters() const 0304 { 0305 return d->demandingAttentionSkipsFilters; 0306 } 0307 0308 void TaskFilterProxyModel::setDemandingAttentionSkipsFilters(bool skip) 0309 { 0310 if (d->demandingAttentionSkipsFilters != skip) { 0311 d->demandingAttentionSkipsFilters = skip; 0312 0313 invalidateFilter(); 0314 0315 Q_EMIT demandingAttentionSkipsFiltersChanged(); 0316 } 0317 } 0318 0319 QModelIndex TaskFilterProxyModel::mapIfaceToSource(const QModelIndex &index) const 0320 { 0321 return mapToSource(index); 0322 } 0323 0324 bool TaskFilterProxyModel::acceptsRow(int sourceRow) const 0325 { 0326 const QModelIndex &sourceIdx = sourceModel()->index(sourceRow, 0); 0327 0328 if (!sourceIdx.isValid()) { 0329 return false; 0330 } 0331 0332 // Filter tasks that are not to be shown on the task bar. 0333 if (d->filterSkipTaskbar && sourceIdx.data(AbstractTasksModel::SkipTaskbar).toBool()) { 0334 return false; 0335 } 0336 0337 // Filter tasks that are not to be shown on the pager. 0338 if (d->filterSkipPager && sourceIdx.data(AbstractTasksModel::SkipPager).toBool()) { 0339 return false; 0340 } 0341 0342 // Filter by virtual desktop. 0343 if (d->filterByVirtualDesktop && !d->virtualDesktop.isNull()) { 0344 if (!sourceIdx.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool() 0345 && (!d->demandingAttentionSkipsFilters || !sourceIdx.data(AbstractTasksModel::IsDemandingAttention).toBool())) { 0346 const QVariantList &virtualDesktops = sourceIdx.data(AbstractTasksModel::VirtualDesktops).toList(); 0347 0348 if (!virtualDesktops.isEmpty() && !virtualDesktops.contains(d->virtualDesktop)) { 0349 return false; 0350 } 0351 } 0352 } 0353 0354 // Filter by screen. 0355 if (d->filterByScreen && d->screenGeometry.isValid()) { 0356 const QRect &screenGeometry = sourceIdx.data(AbstractTasksModel::ScreenGeometry).toRect(); 0357 0358 if (screenGeometry.isValid() && screenGeometry != d->screenGeometry) { 0359 return false; 0360 } 0361 } 0362 0363 // Filter by region 0364 if (d->filterByRegion != RegionFilterMode::Mode::Disabled && d->regionGeometry.isValid()) { 0365 QRect windowGeometry = sourceIdx.data(AbstractTasksModel::Geometry).toRect(); 0366 0367 QRect regionGeometry = d->regionGeometry; 0368 #if HAVE_X11 0369 if (static const bool isX11 = KWindowSystem::isPlatformX11(); isX11 && windowGeometry.isValid()) { 0370 // On X11, in regionGeometry, the original point of the topLeft position belongs to the device coordinate system 0371 // but the size belongs to the logical coordinate system (which means the reported size is already divided by DPR) 0372 // Converting regionGeometry to device coordinate system is better than converting windowGeometry to logical 0373 // coordinate system because the window may span multiple screens, while the region is always on one screen. 0374 const double devicePixelRatio = qGuiApp->devicePixelRatio(); 0375 const QPoint screenTopLeft = d->screenGeometry.topLeft(); 0376 const QPoint regionTopLeft = 0377 screenTopLeft + QPoint(regionGeometry.x() - screenTopLeft.x(), regionGeometry.y() - screenTopLeft.y()) * devicePixelRatio; 0378 regionGeometry = QRect(regionTopLeft, regionGeometry.size() * devicePixelRatio); 0379 } 0380 #endif 0381 switch (d->filterByRegion) { 0382 case RegionFilterMode::Mode::Inside: { 0383 if (!regionGeometry.contains(windowGeometry)) { 0384 return false; 0385 } 0386 break; 0387 } 0388 case RegionFilterMode::Mode::Intersect: { 0389 if (!regionGeometry.intersects(windowGeometry)) { 0390 return false; 0391 } 0392 break; 0393 } 0394 case RegionFilterMode::Mode::Outside: { 0395 if (regionGeometry.contains(windowGeometry)) { 0396 return false; 0397 } 0398 break; 0399 } 0400 default: 0401 break; 0402 } 0403 } 0404 0405 // Filter by activity. 0406 if (d->filterByActivity && !d->activity.isEmpty()) { 0407 if (!d->demandingAttentionSkipsFilters || !sourceIdx.data(AbstractTasksModel::IsDemandingAttention).toBool()) { 0408 const QVariant &activities = sourceIdx.data(AbstractTasksModel::Activities); 0409 0410 if (!activities.isNull()) { 0411 const QStringList l = activities.toStringList(); 0412 0413 if (!l.isEmpty() && !l.contains(NULL_UUID) && !l.contains(d->activity)) { 0414 return false; 0415 } 0416 } 0417 } 0418 } 0419 0420 // Filter not minimized. 0421 if (d->filterNotMinimized) { 0422 bool isMinimized = sourceIdx.data(AbstractTasksModel::IsMinimized).toBool(); 0423 0424 if (!isMinimized) { 0425 return false; 0426 } 0427 } 0428 0429 // Filter out minimized windows 0430 if (d->filterMinimized) { 0431 const bool isMinimized = sourceIdx.data(AbstractTasksModel::IsMinimized).toBool(); 0432 0433 if (isMinimized) { 0434 return false; 0435 } 0436 } 0437 0438 // Filter not maximized. 0439 if (d->filterNotMaximized) { 0440 bool isMaximized = sourceIdx.data(AbstractTasksModel::IsMaximized).toBool(); 0441 0442 if (!isMaximized) { 0443 return false; 0444 } 0445 } 0446 0447 // Filter hidden. 0448 if (d->filterHidden) { 0449 bool isHidden = sourceIdx.data(AbstractTasksModel::IsHidden).toBool(); 0450 0451 if (isHidden) { 0452 return false; 0453 } 0454 } 0455 0456 return true; 0457 } 0458 0459 bool TaskFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const 0460 { 0461 Q_UNUSED(sourceParent) 0462 0463 return acceptsRow(sourceRow); 0464 } 0465 0466 }