File indexing completed on 2024-11-10 04:57:20
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2009 Martin Gräßlin <mgraesslin@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "clientmodel.h" 0011 #include "tabboxconfig.h" 0012 #include "window.h" 0013 0014 #include <KLocalizedString> 0015 0016 #include <QIcon> 0017 #include <QUuid> 0018 0019 #include <cmath> 0020 0021 namespace KWin 0022 { 0023 namespace TabBox 0024 { 0025 0026 ClientModel::ClientModel(QObject *parent) 0027 : QAbstractItemModel(parent) 0028 { 0029 } 0030 0031 ClientModel::~ClientModel() 0032 { 0033 } 0034 0035 QVariant ClientModel::data(const QModelIndex &index, int role) const 0036 { 0037 if (!index.isValid()) { 0038 return QVariant(); 0039 } 0040 0041 if (m_clientList.isEmpty()) { 0042 return QVariant(); 0043 } 0044 0045 int clientIndex = index.row(); 0046 if (clientIndex >= m_clientList.count()) { 0047 return QVariant(); 0048 } 0049 Window *client = m_clientList[clientIndex]; 0050 if (!client) { 0051 return QVariant(); 0052 } 0053 switch (role) { 0054 case Qt::DisplayRole: 0055 case CaptionRole: { 0056 if (client->isDesktop()) { 0057 return i18nc("Special entry in alt+tab list for minimizing all windows", 0058 "Show Desktop"); 0059 } 0060 return client->caption(); 0061 } 0062 case ClientRole: 0063 return QVariant::fromValue<void *>(client); 0064 case DesktopNameRole: { 0065 return tabBox->desktopName(client); 0066 } 0067 case WIdRole: 0068 return client->internalId(); 0069 case MinimizedRole: 0070 return client->isMinimized(); 0071 case CloseableRole: 0072 return client->isCloseable(); 0073 case IconRole: 0074 if (client->isDesktop()) { 0075 return QIcon::fromTheme(QStringLiteral("user-desktop")); 0076 } 0077 return client->icon(); 0078 default: 0079 return QVariant(); 0080 } 0081 } 0082 0083 QString ClientModel::longestCaption() const 0084 { 0085 QString caption; 0086 for (Window *window : std::as_const(m_clientList)) { 0087 if (window->caption().size() > caption.size()) { 0088 caption = window->caption(); 0089 } 0090 } 0091 return caption; 0092 } 0093 0094 int ClientModel::columnCount(const QModelIndex &parent) const 0095 { 0096 return 1; 0097 } 0098 0099 int ClientModel::rowCount(const QModelIndex &parent) const 0100 { 0101 if (parent.isValid()) { 0102 return 0; 0103 } 0104 return m_clientList.count(); 0105 } 0106 0107 QModelIndex ClientModel::parent(const QModelIndex &child) const 0108 { 0109 return QModelIndex(); 0110 } 0111 0112 QModelIndex ClientModel::index(int row, int column, const QModelIndex &parent) const 0113 { 0114 if (row < 0 || column != 0 || parent.isValid()) { 0115 return QModelIndex(); 0116 } 0117 int index = row * columnCount(); 0118 if (index >= m_clientList.count() && !m_clientList.isEmpty()) { 0119 return QModelIndex(); 0120 } 0121 return createIndex(row, 0); 0122 } 0123 0124 QHash<int, QByteArray> ClientModel::roleNames() const 0125 { 0126 return { 0127 {CaptionRole, QByteArrayLiteral("caption")}, 0128 {DesktopNameRole, QByteArrayLiteral("desktopName")}, 0129 {MinimizedRole, QByteArrayLiteral("minimized")}, 0130 {WIdRole, QByteArrayLiteral("windowId")}, 0131 {CloseableRole, QByteArrayLiteral("closeable")}, 0132 {IconRole, QByteArrayLiteral("icon")}, 0133 }; 0134 } 0135 0136 QModelIndex ClientModel::index(Window *client) const 0137 { 0138 const int index = m_clientList.indexOf(client); 0139 if (index == -1) { 0140 return QModelIndex(); 0141 } 0142 int row = index / columnCount(); 0143 int column = index % columnCount(); 0144 return createIndex(row, column); 0145 } 0146 0147 void ClientModel::createFocusChainClientList(Window *start) 0148 { 0149 auto c = start; 0150 if (!tabBox->isInFocusChain(c)) { 0151 Window *firstClient = tabBox->firstClientFocusChain(); 0152 if (firstClient) { 0153 c = firstClient; 0154 } 0155 } 0156 auto stop = c; 0157 do { 0158 Window *add = tabBox->clientToAddToList(c); 0159 if (add) { 0160 m_mutableClientList += add; 0161 } 0162 c = tabBox->nextClientFocusChain(c); 0163 } while (c && c != stop); 0164 } 0165 0166 void ClientModel::createStackingOrderClientList(Window *start) 0167 { 0168 // TODO: needs improvement 0169 const QList<Window *> stacking = tabBox->stackingOrder(); 0170 auto c = stacking.first(); 0171 auto stop = c; 0172 int index = 0; 0173 while (c) { 0174 Window *add = tabBox->clientToAddToList(c); 0175 if (add) { 0176 if (start == add) { 0177 m_mutableClientList.removeAll(add); 0178 m_mutableClientList.prepend(add); 0179 } else { 0180 m_mutableClientList += add; 0181 } 0182 } 0183 if (index >= stacking.size() - 1) { 0184 c = nullptr; 0185 } else { 0186 c = stacking[++index]; 0187 } 0188 0189 if (c == stop) { 0190 break; 0191 } 0192 } 0193 } 0194 0195 void ClientModel::createClientList(bool partialReset) 0196 { 0197 auto start = tabBox->activeClient(); 0198 // TODO: new clients are not added at correct position 0199 if (partialReset && !m_mutableClientList.isEmpty()) { 0200 Window *firstClient = m_mutableClientList.constFirst(); 0201 if (!firstClient->isDeleted()) { 0202 start = firstClient; 0203 } 0204 } 0205 0206 m_mutableClientList.clear(); 0207 0208 switch (tabBox->config().clientSwitchingMode()) { 0209 case TabBoxConfig::FocusChainSwitching: { 0210 createFocusChainClientList(start); 0211 break; 0212 } 0213 case TabBoxConfig::StackingOrderSwitching: { 0214 createStackingOrderClientList(start); 0215 break; 0216 } 0217 } 0218 0219 if (tabBox->config().orderMinimizedMode() == TabBoxConfig::GroupByMinimized) { 0220 // Put all non-minimized included clients first. 0221 std::stable_partition(m_mutableClientList.begin(), m_mutableClientList.end(), [](const auto &client) { 0222 return !client->isMinimized(); 0223 }); 0224 } 0225 0226 if (!m_mutableClientList.isEmpty() 0227 && tabBox->config().clientApplicationsMode() != TabBoxConfig::AllWindowsCurrentApplication 0228 && tabBox->config().showDesktopMode() == TabBoxConfig::ShowDesktopClient) { 0229 Window *desktopClient = tabBox->desktopClient(); 0230 if (desktopClient) { 0231 m_mutableClientList.append(desktopClient); 0232 } 0233 } 0234 0235 if (m_clientList == m_mutableClientList) { 0236 return; 0237 } 0238 0239 beginResetModel(); 0240 m_clientList = m_mutableClientList; 0241 endResetModel(); 0242 } 0243 0244 void ClientModel::close(int i) 0245 { 0246 QModelIndex ind = index(i, 0); 0247 if (!ind.isValid()) { 0248 return; 0249 } 0250 Window *client = m_mutableClientList.at(i); 0251 if (client) { 0252 client->closeWindow(); 0253 } 0254 } 0255 0256 void ClientModel::activate(int i) 0257 { 0258 QModelIndex ind = index(i, 0); 0259 if (!ind.isValid()) { 0260 return; 0261 } 0262 tabBox->setCurrentIndex(ind); 0263 tabBox->activateAndClose(); 0264 } 0265 0266 } // namespace Tabbox 0267 } // namespace KWin 0268 0269 #include "moc_clientmodel.cpp"