1 /*
2     SPDX-FileCopyrightText: 2015 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 #include "plasmawindowmodel.h"
7 #include "plasmawindowmanagement.h"
8 
9 #include <QMetaEnum>
10 
11 namespace KWayland
12 {
13 namespace Client
14 {
15 class Q_DECL_HIDDEN PlasmaWindowModel::Private
16 {
17 public:
18     Private(PlasmaWindowModel *q);
19     QList<PlasmaWindow *> windows;
20     PlasmaWindow *window = nullptr;
21 
22     void addWindow(PlasmaWindow *window);
23     void dataChanged(PlasmaWindow *window, int role);
24 
25 private:
26     PlasmaWindowModel *q;
27 };
28 
Private(PlasmaWindowModel * q)29 PlasmaWindowModel::Private::Private(PlasmaWindowModel *q)
30     : q(q)
31 {
32 }
33 
addWindow(PlasmaWindow * window)34 void PlasmaWindowModel::Private::addWindow(PlasmaWindow *window)
35 {
36     if (windows.indexOf(window) != -1) {
37         return;
38     }
39 
40     const int count = windows.count();
41     q->beginInsertRows(QModelIndex(), count, count);
42     windows.append(window);
43     q->endInsertRows();
44 
45     auto removeWindow = [window, this] {
46         const int row = windows.indexOf(window);
47         if (row != -1) {
48             q->beginRemoveRows(QModelIndex(), row, row);
49             windows.removeAt(row);
50             q->endRemoveRows();
51         }
52     };
53 
54     QObject::connect(window, &PlasmaWindow::unmapped, q, removeWindow);
55     QObject::connect(window, &QObject::destroyed, q, removeWindow);
56 
57     QObject::connect(window, &PlasmaWindow::titleChanged, q, [window, this] {
58         this->dataChanged(window, Qt::DisplayRole);
59     });
60 
61     QObject::connect(window, &PlasmaWindow::iconChanged, q, [window, this] {
62         this->dataChanged(window, Qt::DecorationRole);
63     });
64 
65     QObject::connect(window, &PlasmaWindow::appIdChanged, q, [window, this] {
66         this->dataChanged(window, PlasmaWindowModel::AppId);
67     });
68 
69     QObject::connect(window, &PlasmaWindow::activeChanged, q, [window, this] {
70         this->dataChanged(window, IsActive);
71     });
72 
73     QObject::connect(window, &PlasmaWindow::fullscreenableChanged, q, [window, this] {
74         this->dataChanged(window, IsFullscreenable);
75     });
76 
77     QObject::connect(window, &PlasmaWindow::fullscreenChanged, q, [window, this] {
78         this->dataChanged(window, IsFullscreen);
79     });
80 
81     QObject::connect(window, &PlasmaWindow::maximizeableChanged, q, [window, this] {
82         this->dataChanged(window, IsMaximizable);
83     });
84 
85     QObject::connect(window, &PlasmaWindow::maximizedChanged, q, [window, this] {
86         this->dataChanged(window, IsMaximized);
87     });
88 
89     QObject::connect(window, &PlasmaWindow::minimizeableChanged, q, [window, this] {
90         this->dataChanged(window, IsMinimizable);
91     });
92 
93     QObject::connect(window, &PlasmaWindow::minimizedChanged, q, [window, this] {
94         this->dataChanged(window, IsMinimized);
95     });
96 
97     QObject::connect(window, &PlasmaWindow::keepAboveChanged, q, [window, this] {
98         this->dataChanged(window, IsKeepAbove);
99     });
100 
101     QObject::connect(window, &PlasmaWindow::keepBelowChanged, q, [window, this] {
102         this->dataChanged(window, IsKeepBelow);
103     });
104 
105     QObject::connect(window, &PlasmaWindow::virtualDesktopChanged, q, [window, this] {
106         this->dataChanged(window, VirtualDesktop);
107     });
108 
109     QObject::connect(window, &PlasmaWindow::onAllDesktopsChanged, q, [window, this] {
110         this->dataChanged(window, IsOnAllDesktops);
111     });
112 
113     QObject::connect(window, &PlasmaWindow::demandsAttentionChanged, q, [window, this] {
114         this->dataChanged(window, IsDemandingAttention);
115     });
116 
117     QObject::connect(window, &PlasmaWindow::skipTaskbarChanged, q, [window, this] {
118         this->dataChanged(window, SkipTaskbar);
119     });
120 
121     QObject::connect(window, &PlasmaWindow::skipSwitcherChanged, q, [window, this] {
122         this->dataChanged(window, SkipSwitcher);
123     });
124 
125     QObject::connect(window, &PlasmaWindow::shadeableChanged, q, [window, this] {
126         this->dataChanged(window, IsShadeable);
127     });
128 
129     QObject::connect(window, &PlasmaWindow::shadedChanged, q, [window, this] {
130         this->dataChanged(window, IsShaded);
131     });
132 
133     QObject::connect(window, &PlasmaWindow::movableChanged, q, [window, this] {
134         this->dataChanged(window, IsMovable);
135     });
136 
137     QObject::connect(window, &PlasmaWindow::resizableChanged, q, [window, this] {
138         this->dataChanged(window, IsResizable);
139     });
140 
141     QObject::connect(window, &PlasmaWindow::virtualDesktopChangeableChanged, q, [window, this] {
142         this->dataChanged(window, IsVirtualDesktopChangeable);
143     });
144 
145     QObject::connect(window, &PlasmaWindow::closeableChanged, q, [window, this] {
146         this->dataChanged(window, IsCloseable);
147     });
148 
149     QObject::connect(window, &PlasmaWindow::geometryChanged, q, [window, this] {
150         this->dataChanged(window, Geometry);
151     });
152 
153     QObject::connect(window, &PlasmaWindow::plasmaVirtualDesktopEntered, q, [window, this] {
154         this->dataChanged(window, VirtualDesktops);
155     });
156 
157     QObject::connect(window, &PlasmaWindow::plasmaVirtualDesktopLeft, q, [window, this] {
158         this->dataChanged(window, VirtualDesktops);
159     });
160 }
161 
dataChanged(PlasmaWindow * window,int role)162 void PlasmaWindowModel::Private::dataChanged(PlasmaWindow *window, int role)
163 {
164     QModelIndex idx = q->index(windows.indexOf(window));
165     Q_EMIT q->dataChanged(idx, idx, QVector<int>() << role);
166 }
167 
PlasmaWindowModel(PlasmaWindowManagement * parent)168 PlasmaWindowModel::PlasmaWindowModel(PlasmaWindowManagement *parent)
169     : QAbstractListModel(parent)
170     , d(new Private(this))
171 {
172     connect(parent, &PlasmaWindowManagement::interfaceAboutToBeReleased, this, [this] {
173         beginResetModel();
174         d->windows.clear();
175         endResetModel();
176     });
177 
178     connect(parent, &PlasmaWindowManagement::windowCreated, this, [this](PlasmaWindow *window) {
179         d->addWindow(window);
180     });
181 
182     for (auto it = parent->windows().constBegin(); it != parent->windows().constEnd(); ++it) {
183         d->addWindow(*it);
184     }
185 }
186 
~PlasmaWindowModel()187 PlasmaWindowModel::~PlasmaWindowModel()
188 {
189 }
190 
roleNames() const191 QHash<int, QByteArray> PlasmaWindowModel::roleNames() const
192 {
193     QHash<int, QByteArray> roles;
194 
195     roles.insert(Qt::DisplayRole, "DisplayRole");
196     roles.insert(Qt::DecorationRole, "DecorationRole");
197 
198     QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles"));
199 
200     for (int i = 0; i < e.keyCount(); ++i) {
201         roles.insert(e.value(i), e.key(i));
202     }
203 
204     return roles;
205 }
206 
data(const QModelIndex & index,int role) const207 QVariant PlasmaWindowModel::data(const QModelIndex &index, int role) const
208 {
209     if (!index.isValid() || index.row() >= d->windows.count()) {
210         return QVariant();
211     }
212 
213     const PlasmaWindow *window = d->windows.at(index.row());
214 
215     if (role == Qt::DisplayRole) {
216         return window->title();
217     } else if (role == Qt::DecorationRole) {
218         return window->icon();
219     } else if (role == AppId) {
220         return window->appId();
221     } else if (role == Pid) {
222         return window->pid();
223     } else if (role == IsActive) {
224         return window->isActive();
225     } else if (role == IsFullscreenable) {
226         return window->isFullscreenable();
227     } else if (role == IsFullscreen) {
228         return window->isFullscreen();
229     } else if (role == IsMaximizable) {
230         return window->isMaximizeable();
231     } else if (role == IsMaximized) {
232         return window->isMaximized();
233     } else if (role == IsMinimizable) {
234         return window->isMinimizeable();
235     } else if (role == IsMinimized) {
236         return window->isMinimized();
237     } else if (role == IsKeepAbove) {
238         return window->isKeepAbove();
239     } else if (role == IsKeepBelow) {
240         return window->isKeepBelow();
241     } else if (role == VirtualDesktop) {
242         return window->virtualDesktop();
243     } else if (role == IsOnAllDesktops) {
244         return window->isOnAllDesktops();
245     } else if (role == IsDemandingAttention) {
246         return window->isDemandingAttention();
247     } else if (role == SkipTaskbar) {
248         return window->skipTaskbar();
249     } else if (role == SkipSwitcher) {
250         return window->skipSwitcher();
251     } else if (role == IsShadeable) {
252         return window->isShadeable();
253     } else if (role == IsShaded) {
254         return window->isShaded();
255     } else if (role == IsMovable) {
256         return window->isMovable();
257     } else if (role == IsResizable) {
258         return window->isResizable();
259     } else if (role == IsVirtualDesktopChangeable) {
260         return window->isVirtualDesktopChangeable();
261     } else if (role == IsCloseable) {
262         return window->isCloseable();
263     } else if (role == Geometry) {
264         return window->geometry();
265     } else if (role == VirtualDesktops) {
266         return window->plasmaVirtualDesktops();
267     } else if (role == Uuid) {
268         return window->uuid();
269     }
270 
271     return QVariant();
272 }
273 
rowCount(const QModelIndex & parent) const274 int PlasmaWindowModel::rowCount(const QModelIndex &parent) const
275 {
276     return parent.isValid() ? 0 : d->windows.count();
277 }
278 
index(int row,int column,const QModelIndex & parent) const279 QModelIndex PlasmaWindowModel::index(int row, int column, const QModelIndex &parent) const
280 {
281     return hasIndex(row, column, parent) ? createIndex(row, column, d->windows.at(row)) : QModelIndex();
282 }
283 
requestActivate(int row)284 Q_INVOKABLE void PlasmaWindowModel::requestActivate(int row)
285 {
286     if (row >= 0 && row < d->windows.count()) {
287         d->windows.at(row)->requestActivate();
288     }
289 }
290 
requestClose(int row)291 Q_INVOKABLE void PlasmaWindowModel::requestClose(int row)
292 {
293     if (row >= 0 && row < d->windows.count()) {
294         d->windows.at(row)->requestClose();
295     }
296 }
297 
requestMove(int row)298 Q_INVOKABLE void PlasmaWindowModel::requestMove(int row)
299 {
300     if (row >= 0 && row < d->windows.count()) {
301         d->windows.at(row)->requestMove();
302     }
303 }
304 
requestResize(int row)305 Q_INVOKABLE void PlasmaWindowModel::requestResize(int row)
306 {
307     if (row >= 0 && row < d->windows.count()) {
308         d->windows.at(row)->requestResize();
309     }
310 }
311 
requestVirtualDesktop(int row,quint32 desktop)312 Q_INVOKABLE void PlasmaWindowModel::requestVirtualDesktop(int row, quint32 desktop)
313 {
314     if (row >= 0 && row < d->windows.count()) {
315         d->windows.at(row)->requestVirtualDesktop(desktop);
316     }
317 }
318 
requestToggleKeepAbove(int row)319 Q_INVOKABLE void PlasmaWindowModel::requestToggleKeepAbove(int row)
320 {
321     if (row >= 0 && row < d->windows.count()) {
322         d->windows.at(row)->requestToggleKeepAbove();
323     }
324 }
325 
requestToggleKeepBelow(int row)326 Q_INVOKABLE void PlasmaWindowModel::requestToggleKeepBelow(int row)
327 {
328     if (row >= 0 && row < d->windows.count()) {
329         d->windows.at(row)->requestToggleKeepBelow();
330     }
331 }
332 
requestToggleMinimized(int row)333 Q_INVOKABLE void PlasmaWindowModel::requestToggleMinimized(int row)
334 {
335     if (row >= 0 && row < d->windows.count()) {
336         d->windows.at(row)->requestToggleMinimized();
337     }
338 }
339 
requestToggleMaximized(int row)340 Q_INVOKABLE void PlasmaWindowModel::requestToggleMaximized(int row)
341 {
342     if (row >= 0 && row < d->windows.count()) {
343         d->windows.at(row)->requestToggleMaximized();
344     }
345 }
346 
setMinimizedGeometry(int row,Surface * panel,const QRect & geom)347 Q_INVOKABLE void PlasmaWindowModel::setMinimizedGeometry(int row, Surface *panel, const QRect &geom)
348 {
349     if (row >= 0 && row < d->windows.count()) {
350         d->windows.at(row)->setMinimizedGeometry(panel, geom);
351     }
352 }
353 
requestToggleShaded(int row)354 Q_INVOKABLE void PlasmaWindowModel::requestToggleShaded(int row)
355 {
356     if (row >= 0 && row < d->windows.count()) {
357         d->windows.at(row)->requestToggleShaded();
358     }
359 }
360 
361 }
362 }
363