File indexing completed on 2024-11-10 04:57:19
0001 /* 0002 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "windowmodel.h" 0008 #include "core/output.h" 0009 #include "core/outputbackend.h" 0010 #include "virtualdesktops.h" 0011 #include "window.h" 0012 #include "workspace.h" 0013 0014 namespace KWin 0015 { 0016 0017 WindowModel::WindowModel(QObject *parent) 0018 : QAbstractListModel(parent) 0019 { 0020 connect(workspace(), &Workspace::windowAdded, this, &WindowModel::handleWindowAdded); 0021 connect(workspace(), &Workspace::windowRemoved, this, &WindowModel::handleWindowRemoved); 0022 0023 m_windows = workspace()->windows(); 0024 for (Window *window : std::as_const(m_windows)) { 0025 setupWindowConnections(window); 0026 } 0027 } 0028 0029 void WindowModel::markRoleChanged(Window *window, int role) 0030 { 0031 const QModelIndex row = index(m_windows.indexOf(window), 0); 0032 Q_EMIT dataChanged(row, row, {role}); 0033 } 0034 0035 void WindowModel::setupWindowConnections(Window *window) 0036 { 0037 connect(window, &Window::desktopsChanged, this, [this, window]() { 0038 markRoleChanged(window, DesktopRole); 0039 }); 0040 connect(window, &Window::outputChanged, this, [this, window]() { 0041 markRoleChanged(window, OutputRole); 0042 }); 0043 connect(window, &Window::activitiesChanged, this, [this, window]() { 0044 markRoleChanged(window, ActivityRole); 0045 }); 0046 } 0047 0048 void WindowModel::handleWindowAdded(Window *window) 0049 { 0050 beginInsertRows(QModelIndex(), m_windows.count(), m_windows.count()); 0051 m_windows.append(window); 0052 endInsertRows(); 0053 0054 setupWindowConnections(window); 0055 } 0056 0057 void WindowModel::handleWindowRemoved(Window *window) 0058 { 0059 const int index = m_windows.indexOf(window); 0060 Q_ASSERT(index != -1); 0061 0062 beginRemoveRows(QModelIndex(), index, index); 0063 m_windows.removeAt(index); 0064 endRemoveRows(); 0065 } 0066 0067 QHash<int, QByteArray> WindowModel::roleNames() const 0068 { 0069 return { 0070 {Qt::DisplayRole, QByteArrayLiteral("display")}, 0071 {WindowRole, QByteArrayLiteral("window")}, 0072 {OutputRole, QByteArrayLiteral("output")}, 0073 {DesktopRole, QByteArrayLiteral("desktop")}, 0074 {ActivityRole, QByteArrayLiteral("activity")}, 0075 }; 0076 } 0077 0078 QVariant WindowModel::data(const QModelIndex &index, int role) const 0079 { 0080 if (!index.isValid() || index.row() < 0 || index.row() >= m_windows.count()) { 0081 return QVariant(); 0082 } 0083 0084 Window *window = m_windows[index.row()]; 0085 switch (role) { 0086 case Qt::DisplayRole: 0087 case WindowRole: 0088 return QVariant::fromValue(window); 0089 case OutputRole: 0090 return QVariant::fromValue(window->output()); 0091 case DesktopRole: 0092 return QVariant::fromValue(window->desktops()); 0093 case ActivityRole: 0094 return window->activities(); 0095 default: 0096 return QVariant(); 0097 } 0098 } 0099 0100 int WindowModel::rowCount(const QModelIndex &parent) const 0101 { 0102 return parent.isValid() ? 0 : m_windows.count(); 0103 } 0104 0105 WindowFilterModel::WindowFilterModel(QObject *parent) 0106 : QSortFilterProxyModel(parent) 0107 { 0108 } 0109 0110 WindowModel *WindowFilterModel::windowModel() const 0111 { 0112 return m_windowModel; 0113 } 0114 0115 void WindowFilterModel::setWindowModel(WindowModel *windowModel) 0116 { 0117 if (windowModel == m_windowModel) { 0118 return; 0119 } 0120 m_windowModel = windowModel; 0121 setSourceModel(m_windowModel); 0122 Q_EMIT windowModelChanged(); 0123 } 0124 0125 QString WindowFilterModel::activity() const 0126 { 0127 return m_activity.value_or(QString()); 0128 } 0129 0130 void WindowFilterModel::setActivity(const QString &activity) 0131 { 0132 if (m_activity != activity) { 0133 m_activity = activity; 0134 Q_EMIT activityChanged(); 0135 invalidateFilter(); 0136 } 0137 } 0138 0139 void WindowFilterModel::resetActivity() 0140 { 0141 if (m_activity.has_value()) { 0142 m_activity.reset(); 0143 Q_EMIT activityChanged(); 0144 invalidateFilter(); 0145 } 0146 } 0147 0148 VirtualDesktop *WindowFilterModel::desktop() const 0149 { 0150 return m_desktop; 0151 } 0152 0153 void WindowFilterModel::setDesktop(VirtualDesktop *desktop) 0154 { 0155 if (m_desktop != desktop) { 0156 m_desktop = desktop; 0157 Q_EMIT desktopChanged(); 0158 invalidateFilter(); 0159 } 0160 } 0161 0162 void WindowFilterModel::resetDesktop() 0163 { 0164 setDesktop(nullptr); 0165 } 0166 0167 QString WindowFilterModel::filter() const 0168 { 0169 return m_filter; 0170 } 0171 0172 void WindowFilterModel::setFilter(const QString &filter) 0173 { 0174 if (filter == m_filter) { 0175 return; 0176 } 0177 m_filter = filter; 0178 Q_EMIT filterChanged(); 0179 invalidateFilter(); 0180 } 0181 0182 QString WindowFilterModel::screenName() const 0183 { 0184 return m_output ? m_output->name() : QString(); 0185 } 0186 0187 void WindowFilterModel::setScreenName(const QString &screen) 0188 { 0189 Output *output = kwinApp()->outputBackend()->findOutput(screen); 0190 if (m_output != output) { 0191 m_output = output; 0192 Q_EMIT screenNameChanged(); 0193 invalidateFilter(); 0194 } 0195 } 0196 0197 void WindowFilterModel::resetScreenName() 0198 { 0199 if (m_output) { 0200 m_output = nullptr; 0201 Q_EMIT screenNameChanged(); 0202 invalidateFilter(); 0203 } 0204 } 0205 0206 WindowFilterModel::WindowTypes WindowFilterModel::windowType() const 0207 { 0208 return m_windowType.value_or(WindowTypes()); 0209 } 0210 0211 void WindowFilterModel::setWindowType(WindowTypes windowType) 0212 { 0213 if (m_windowType != windowType) { 0214 m_windowType = windowType; 0215 Q_EMIT windowTypeChanged(); 0216 invalidateFilter(); 0217 } 0218 } 0219 0220 void WindowFilterModel::resetWindowType() 0221 { 0222 if (m_windowType.has_value()) { 0223 m_windowType.reset(); 0224 Q_EMIT windowTypeChanged(); 0225 invalidateFilter(); 0226 } 0227 } 0228 0229 void WindowFilterModel::setMinimizedWindows(bool show) 0230 { 0231 if (m_showMinimizedWindows == show) { 0232 return; 0233 } 0234 0235 m_showMinimizedWindows = show; 0236 invalidateFilter(); 0237 Q_EMIT minimizedWindowsChanged(); 0238 } 0239 0240 bool WindowFilterModel::minimizedWindows() const 0241 { 0242 return m_showMinimizedWindows; 0243 } 0244 0245 bool WindowFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const 0246 { 0247 if (!m_windowModel) { 0248 return false; 0249 } 0250 const QModelIndex index = m_windowModel->index(sourceRow, 0, sourceParent); 0251 if (!index.isValid()) { 0252 return false; 0253 } 0254 const QVariant data = index.data(); 0255 if (!data.isValid()) { 0256 // an invalid QVariant is valid data 0257 return true; 0258 } 0259 0260 Window *window = qvariant_cast<Window *>(data); 0261 if (!window) { 0262 return false; 0263 } 0264 0265 if (m_activity.has_value()) { 0266 if (!window->isOnActivity(*m_activity)) { 0267 return false; 0268 } 0269 } 0270 0271 if (m_desktop) { 0272 if (!window->isOnDesktop(m_desktop)) { 0273 return false; 0274 } 0275 } 0276 0277 if (m_output) { 0278 if (!window->isOnOutput(m_output)) { 0279 return false; 0280 } 0281 } 0282 0283 if (m_windowType.has_value()) { 0284 if (!(windowTypeMask(window) & *m_windowType)) { 0285 return false; 0286 } 0287 } 0288 0289 if (!m_filter.isEmpty()) { 0290 if (window->caption().contains(m_filter, Qt::CaseInsensitive)) { 0291 return true; 0292 } 0293 if (window->windowRole().contains(m_filter, Qt::CaseInsensitive)) { 0294 return true; 0295 } 0296 if (window->resourceName().contains(m_filter, Qt::CaseInsensitive)) { 0297 return true; 0298 } 0299 if (window->resourceClass().contains(m_filter, Qt::CaseInsensitive)) { 0300 return true; 0301 } 0302 return false; 0303 } 0304 0305 if (!m_showMinimizedWindows) { 0306 return !window->isMinimized(); 0307 } 0308 return true; 0309 } 0310 0311 WindowFilterModel::WindowTypes WindowFilterModel::windowTypeMask(Window *window) const 0312 { 0313 WindowTypes mask; 0314 if (window->isNormalWindow()) { 0315 mask |= WindowType::Normal; 0316 } else if (window->isDialog()) { 0317 mask |= WindowType::Dialog; 0318 } else if (window->isDock()) { 0319 mask |= WindowType::Dock; 0320 } else if (window->isDesktop()) { 0321 mask |= WindowType::Desktop; 0322 } else if (window->isNotification()) { 0323 mask |= WindowType::Notification; 0324 } else if (window->isCriticalNotification()) { 0325 mask |= WindowType::CriticalNotification; 0326 } 0327 return mask; 0328 } 0329 0330 } // namespace KWin 0331 0332 #include "moc_windowmodel.cpp"