1 /********************************************************************
2 Copyright © 2020 Roman Gilg <subdiff@gmail.com>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #include "plasma_window_p.h"
21
22 #include "display.h"
23 #include "plasma_virtual_desktop.h"
24 #include "surface.h"
25
26 #include <QFile>
27 #include <QHash>
28 #include <QIcon>
29 #include <QList>
30 #include <QRect>
31 #include <QVector>
32 #include <QtConcurrentRun>
33
34 #include <csignal>
35 #include <wayland-server.h>
36
37 namespace Wrapland::Server
38 {
39
40 const struct org_kde_plasma_window_management_interface PlasmaWindowManager::Private::s_interface
41 = {
42 showDesktopCallback,
43 getWindowCallback,
44 };
45
Private(Display * display,PlasmaWindowManager * qptr)46 PlasmaWindowManager::Private::Private(Display* display, PlasmaWindowManager* qptr)
47 : PlasmaWindowManagerGlobal(qptr,
48 display,
49 &org_kde_plasma_window_management_interface,
50 &s_interface)
51 {
52 create();
53 }
54
PlasmaWindowManager(Display * display,QObject * parent)55 PlasmaWindowManager::PlasmaWindowManager(Display* display, QObject* parent)
56 : QObject(parent)
57 , d_ptr(new Private(display, this))
58 {
59 // Needed because the icon is sent via a pipe and when it closes while being written to would
60 // kill off the compositor.
61 // TODO(romangg): Replace the pipe with a Unix domain socket and set on it to ignore the SIGPIPE
62 // signal. See issue #7.
63 signal(SIGPIPE, SIG_IGN); // NOLINT
64 }
65
66 PlasmaWindowManager::~PlasmaWindowManager() = default;
67
bindInit(PlasmaWindowManagerBind * bind)68 void PlasmaWindowManager::Private::bindInit(PlasmaWindowManagerBind* bind)
69 {
70 for (auto it = windows.constBegin(); it != windows.constEnd(); ++it) {
71 send<org_kde_plasma_window_management_send_window>(bind, (*it)->d_ptr->windowId);
72 }
73 }
74
sendShowingDesktopState()75 void PlasmaWindowManager::Private::sendShowingDesktopState()
76 {
77 uint32_t state = 0;
78 switch (desktopState) {
79 case ShowingDesktopState::Enabled:
80 state = ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED;
81 break;
82 case ShowingDesktopState::Disabled:
83 state = ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED;
84 break;
85 default:
86 Q_UNREACHABLE();
87 break;
88 }
89 send<org_kde_plasma_window_management_send_show_desktop_changed>(state);
90 }
91
showDesktopCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t desktopState)92 void PlasmaWindowManager::Private::showDesktopCallback([[maybe_unused]] wl_client* wlClient,
93 wl_resource* wlResource,
94 uint32_t desktopState)
95 {
96 auto state = ShowingDesktopState::Disabled;
97
98 switch (desktopState) {
99 case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED:
100 state = ShowingDesktopState::Enabled;
101 break;
102 case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED:
103 default:
104 state = ShowingDesktopState::Disabled;
105 break;
106 }
107
108 Q_EMIT handle(wlResource)->requestChangeShowingDesktop(state);
109 }
110
getWindowCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t id,uint32_t internalWindowId)111 void PlasmaWindowManager::Private::getWindowCallback([[maybe_unused]] wl_client* wlClient,
112 wl_resource* wlResource,
113 uint32_t id,
114 uint32_t internalWindowId)
115 {
116 auto priv = handle(wlResource)->d_ptr.get();
117 auto bind = priv->getBind(wlResource);
118
119 auto it = std::find_if(priv->windows.constBegin(),
120 priv->windows.constEnd(),
121 [internalWindowId](PlasmaWindow* window) {
122 return window->d_ptr->windowId == internalWindowId;
123 });
124
125 if (it == priv->windows.constEnd()) {
126 // Create a temp window just for the resource and directly send unmapped.
127 auto window = std::unique_ptr<PlasmaWindow>(new PlasmaWindow(priv->handle()));
128 window->d_ptr->createResource(bind->version(), id, bind->client(), true);
129 return;
130 }
131 (*it)->d_ptr->createResource(bind->version(), id, bind->client(), false);
132 }
133
setShowingDesktopState(ShowingDesktopState desktopState)134 void PlasmaWindowManager::setShowingDesktopState(ShowingDesktopState desktopState)
135 {
136 if (d_ptr->desktopState == desktopState) {
137 return;
138 }
139 d_ptr->desktopState = desktopState;
140 d_ptr->sendShowingDesktopState();
141 }
142
createWindow(QObject * parent)143 PlasmaWindow* PlasmaWindowManager::createWindow(QObject* parent)
144 {
145 auto window = new PlasmaWindow(this, parent);
146
147 // TODO(unknown author): improve window ids so that it cannot wrap around
148 window->d_ptr->windowId = ++d_ptr->windowIdCounter;
149
150 d_ptr->send<org_kde_plasma_window_management_send_window>(window->d_ptr->windowId);
151
152 d_ptr->windows << window;
153 connect(
154 window, &QObject::destroyed, this, [this, window] { d_ptr->windows.removeAll(window); });
155
156 return window;
157 }
158
windows() const159 QList<PlasmaWindow*> PlasmaWindowManager::windows() const
160 {
161 return d_ptr->windows;
162 }
163
unmapWindow(PlasmaWindow * window)164 void PlasmaWindowManager::unmapWindow(PlasmaWindow* window)
165 {
166 if (!window) {
167 return;
168 }
169
170 d_ptr->windows.removeOne(window);
171 Q_ASSERT(!d_ptr->windows.contains(window));
172
173 window->d_ptr->unmap();
174 delete window;
175 }
176
setVirtualDesktopManager(PlasmaVirtualDesktopManager * manager)177 void PlasmaWindowManager::setVirtualDesktopManager(PlasmaVirtualDesktopManager* manager)
178 {
179 d_ptr->virtualDesktopManager = manager;
180 }
181
virtualDesktopManager() const182 PlasmaVirtualDesktopManager* PlasmaWindowManager::virtualDesktopManager() const
183 {
184 return d_ptr->virtualDesktopManager;
185 }
186
187 /////////////////////////// Plasma Window ///////////////////////////
188
Private(PlasmaWindowManager * manager,PlasmaWindow * q)189 PlasmaWindow::Private::Private(PlasmaWindowManager* manager, PlasmaWindow* q)
190 : manager(manager)
191 , q_ptr(q)
192 {
193 }
194
~Private()195 PlasmaWindow::Private::~Private()
196 {
197 for (auto resource : resources) {
198 resource->unmap();
199 }
200 }
201
createResource(uint32_t version,uint32_t id,Wayland::Client * client,bool temporary)202 void PlasmaWindow::Private::createResource(uint32_t version,
203 uint32_t id,
204 Wayland::Client* client,
205 bool temporary)
206 {
207 auto windowRes = new PlasmaWindowRes(client, version, id, temporary ? nullptr : q_ptr);
208 resources << windowRes;
209
210 connect(windowRes, &PlasmaWindowRes::resourceDestroyed, q_ptr, [this, windowRes]() {
211 resources.removeOne(windowRes);
212 });
213
214 windowRes->d_ptr->send<org_kde_plasma_window_send_virtual_desktop_changed>(m_virtualDesktop);
215 for (const auto& desk : plasmaVirtualDesktops) {
216 windowRes->d_ptr->send<org_kde_plasma_window_send_virtual_desktop_entered>(
217 desk.toUtf8().constData());
218 }
219 if (!m_appId.isEmpty()) {
220 windowRes->d_ptr->send<org_kde_plasma_window_send_app_id_changed>(
221 m_appId.toUtf8().constData());
222 }
223 if (m_pid != 0) {
224 windowRes->d_ptr->send<org_kde_plasma_window_send_pid_changed>(m_pid);
225 }
226 if (!m_title.isEmpty()) {
227 windowRes->d_ptr->send<org_kde_plasma_window_send_title_changed>(
228 m_title.toUtf8().constData());
229 }
230 if (!m_applicationMenu.serviceName.isEmpty() || !m_applicationMenu.objectPath.isEmpty()) {
231 windowRes->d_ptr->send<org_kde_plasma_window_send_application_menu>(
232 m_applicationMenu.serviceName.toLatin1().constData(),
233 m_applicationMenu.objectPath.toLatin1().constData());
234 }
235 windowRes->d_ptr->send<org_kde_plasma_window_send_state_changed>(m_desktopState);
236 if (!m_themedIconName.isEmpty()) {
237 windowRes->d_ptr->send<org_kde_plasma_window_send_themed_icon_name_changed>(
238 m_themedIconName.toUtf8().constData());
239 } else {
240 if (version >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) {
241 windowRes->d_ptr->send<org_kde_plasma_window_send_icon_changed>();
242 }
243 }
244
245 auto parentRes = getResourceOfParent(parentWindow, windowRes);
246 windowRes->d_ptr->send<org_kde_plasma_window_send_parent_window>(
247 parentRes ? parentRes->d_ptr->resource() : nullptr);
248
249 if (temporary) {
250 windowRes->d_ptr->send<org_kde_plasma_window_send_unmapped>();
251 }
252
253 if (geometry.isValid() && version >= ORG_KDE_PLASMA_WINDOW_GEOMETRY_SINCE_VERSION) {
254 windowRes->d_ptr->send<org_kde_plasma_window_send_geometry>(
255 geometry.x(), geometry.y(), geometry.width(), geometry.height());
256 }
257
258 if (version >= ORG_KDE_PLASMA_WINDOW_INITIAL_STATE_SINCE_VERSION) {
259 windowRes->d_ptr->send<org_kde_plasma_window_send_initial_state>();
260 }
261 client->flush();
262 }
263
setAppId(const QString & appId)264 void PlasmaWindow::Private::setAppId(const QString& appId)
265 {
266 if (m_appId == appId) {
267 return;
268 }
269 m_appId = appId;
270 const QByteArray utf8 = m_appId.toUtf8();
271 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
272 (*it)->d_ptr->send<org_kde_plasma_window_send_app_id_changed>(utf8.constData());
273 }
274 }
275
setPid(uint32_t pid)276 void PlasmaWindow::Private::setPid(uint32_t pid)
277 {
278 if (m_pid == pid) {
279 return;
280 }
281 m_pid = pid;
282 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
283 (*it)->d_ptr->send<org_kde_plasma_window_send_pid_changed>(pid);
284 }
285 }
286
setThemedIconName(const QString & iconName)287 void PlasmaWindow::Private::setThemedIconName(const QString& iconName)
288 {
289 if (m_themedIconName == iconName) {
290 return;
291 }
292 m_themedIconName = iconName;
293 const QByteArray utf8 = m_themedIconName.toUtf8();
294 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
295 (*it)->d_ptr->send<org_kde_plasma_window_send_themed_icon_name_changed>(utf8.constData());
296 }
297 }
298
setIcon(const QIcon & icon)299 void PlasmaWindow::Private::setIcon(const QIcon& icon)
300 {
301 m_icon = icon;
302 setThemedIconName(m_icon.name());
303 if (m_icon.name().isEmpty()) {
304 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
305 if (wl_resource_get_version((*it)->d_ptr->resource())
306 >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) {
307 (*it)->d_ptr->send<org_kde_plasma_window_send_icon_changed>();
308 }
309 }
310 }
311 }
312
setTitle(const QString & title)313 void PlasmaWindow::Private::setTitle(const QString& title)
314 {
315 if (m_title == title) {
316 return;
317 }
318 m_title = title;
319 const QByteArray utf8 = m_title.toUtf8();
320 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
321 (*it)->d_ptr->send<org_kde_plasma_window_send_title_changed>(utf8.constData());
322 }
323 }
324
unmap() const325 void PlasmaWindow::Private::unmap() const
326 {
327 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
328 (*it)->unmap();
329 }
330 }
331
setState(org_kde_plasma_window_management_state flag,bool set)332 void PlasmaWindow::Private::setState(org_kde_plasma_window_management_state flag, bool set)
333 {
334 uint32_t newState = m_desktopState;
335 if (set) {
336 newState |= flag;
337 } else {
338 newState &= ~flag;
339 }
340 if (newState == m_desktopState) {
341 return;
342 }
343 m_desktopState = newState;
344 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
345 (*it)->d_ptr->send<org_kde_plasma_window_send_state_changed>(m_desktopState);
346 }
347 }
348
getResourceOfParent(PlasmaWindow * parent,PlasmaWindowRes * childRes)349 PlasmaWindowRes* PlasmaWindow::Private::getResourceOfParent(PlasmaWindow* parent,
350 PlasmaWindowRes* childRes)
351 {
352 if (!parent) {
353 return nullptr;
354 }
355
356 auto childClient = childRes->d_ptr->client();
357 auto it = std::find_if(parent->d_ptr->resources.begin(),
358 parent->d_ptr->resources.end(),
359 [childClient](PlasmaWindowRes* parentRes) {
360 return parentRes->d_ptr->client() == childClient;
361 });
362 return it != parent->d_ptr->resources.end() ? *it : nullptr;
363 }
364
setParentWindow(PlasmaWindow * window)365 void PlasmaWindow::Private::setParentWindow(PlasmaWindow* window)
366 {
367 if (parentWindow == window) {
368 return;
369 }
370 QObject::disconnect(parentWindowDestroyConnection);
371 parentWindowDestroyConnection = QMetaObject::Connection();
372 parentWindow = window;
373 if (parentWindow) {
374 parentWindowDestroyConnection
375 = QObject::connect(window, &QObject::destroyed, q_ptr, [this] {
376 parentWindow = nullptr;
377 parentWindowDestroyConnection = QMetaObject::Connection();
378 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
379 (*it)->d_ptr->send<org_kde_plasma_window_send_parent_window>(nullptr);
380 }
381 });
382 }
383 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
384 auto parentRes = getResourceOfParent(window, *it);
385 (*it)->d_ptr->send<org_kde_plasma_window_send_parent_window>(
386 parentRes ? parentRes->d_ptr->resource() : nullptr);
387 }
388 }
389
setGeometry(const QRect & geo)390 void PlasmaWindow::Private::setGeometry(const QRect& geo)
391 {
392 if (geometry == geo) {
393 return;
394 }
395 geometry = geo;
396 if (!geometry.isValid()) {
397 return;
398 }
399 for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
400 auto resource = (*it)->d_ptr->resource();
401 if (wl_resource_get_version(resource) < ORG_KDE_PLASMA_WINDOW_GEOMETRY_SINCE_VERSION) {
402 continue;
403 }
404 (*it)->d_ptr->send<org_kde_plasma_window_send_geometry>(
405 geometry.x(), geometry.y(), geometry.width(), geometry.height());
406 }
407 }
408
setApplicationMenuPaths(const QString & serviceName,const QString & objectPath)409 void PlasmaWindow::Private::setApplicationMenuPaths(const QString& serviceName,
410 const QString& objectPath)
411 {
412 if (m_applicationMenu.serviceName == serviceName
413 && m_applicationMenu.objectPath == objectPath) {
414 return;
415 }
416 auto const service_name = serviceName.toLatin1();
417 auto const object_path = objectPath.toLatin1();
418
419 m_applicationMenu.serviceName = serviceName;
420 m_applicationMenu.objectPath = objectPath;
421
422 for (auto resource : qAsConst(resources)) {
423 resource->d_ptr->send<org_kde_plasma_window_send_application_menu,
424 ORG_KDE_PLASMA_WINDOW_APPLICATION_MENU_SINCE_VERSION>(
425 service_name.data(), object_path.data());
426 }
427 }
428
PlasmaWindow(PlasmaWindowManager * manager,QObject * parent)429 PlasmaWindow::PlasmaWindow(PlasmaWindowManager* manager, QObject* parent)
430 : QObject(parent)
431 , d_ptr(new Private(manager, this))
432 {
433 }
434
435 PlasmaWindow::~PlasmaWindow() = default;
436
setAppId(const QString & appId)437 void PlasmaWindow::setAppId(const QString& appId)
438 {
439 d_ptr->setAppId(appId);
440 }
441
setPid(uint32_t pid)442 void PlasmaWindow::setPid(uint32_t pid)
443 {
444 d_ptr->setPid(pid);
445 }
446
setTitle(const QString & title)447 void PlasmaWindow::setTitle(const QString& title)
448 {
449 d_ptr->setTitle(title);
450 }
451
unmap()452 void PlasmaWindow::unmap()
453 {
454 d_ptr->manager->unmapWindow(this);
455 }
456
minimizedGeometries() const457 QHash<Surface*, QRect> PlasmaWindow::minimizedGeometries() const
458 {
459 return d_ptr->minimizedGeometries;
460 }
461
setActive(bool set)462 void PlasmaWindow::setActive(bool set)
463 {
464 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE, set);
465 }
466
setFullscreen(bool set)467 void PlasmaWindow::setFullscreen(bool set)
468 {
469 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN, set);
470 }
471
setKeepAbove(bool set)472 void PlasmaWindow::setKeepAbove(bool set)
473 {
474 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE, set);
475 }
476
setKeepBelow(bool set)477 void PlasmaWindow::setKeepBelow(bool set)
478 {
479 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW, set);
480 }
481
setMaximized(bool set)482 void PlasmaWindow::setMaximized(bool set)
483 {
484 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED, set);
485 }
486
setMinimized(bool set)487 void PlasmaWindow::setMinimized(bool set)
488 {
489 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED, set);
490 }
491
setOnAllDesktops(bool set)492 void PlasmaWindow::setOnAllDesktops(bool set)
493 {
494 // the deprecated vd management
495 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ON_ALL_DESKTOPS, set);
496
497 if (!d_ptr->manager->virtualDesktopManager()) {
498 return;
499 }
500
501 // the current vd management
502 if (set) {
503 if (d_ptr->plasmaVirtualDesktops.isEmpty()) {
504 return;
505 }
506 // leaving everything means on all desktops
507 auto const desktops = plasmaVirtualDesktops();
508 for (auto const& desk : desktops) {
509 for (auto it = d_ptr->resources.constBegin(); it != d_ptr->resources.constEnd(); ++it) {
510 (*it)->d_ptr->send<org_kde_plasma_window_send_virtual_desktop_left>(
511 desk.toUtf8().constData());
512 }
513 }
514 d_ptr->plasmaVirtualDesktops.clear();
515 } else {
516 if (!d_ptr->plasmaVirtualDesktops.isEmpty()) {
517 return;
518 }
519 // enters the desktops which are active (usually only one but not a given)
520 for (auto desk : d_ptr->manager->virtualDesktopManager()->desktops()) {
521 if (desk->active() && !d_ptr->plasmaVirtualDesktops.contains(desk->id())) {
522 d_ptr->plasmaVirtualDesktops << desk->id();
523 for (auto it = d_ptr->resources.constBegin(); it != d_ptr->resources.constEnd();
524 ++it) {
525 (*it)->d_ptr->send<org_kde_plasma_window_send_virtual_desktop_entered>(
526 desk->id().toUtf8().constData());
527 }
528 }
529 }
530 }
531 }
532
setDemandsAttention(bool set)533 void PlasmaWindow::setDemandsAttention(bool set)
534 {
535 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION, set);
536 }
537
setCloseable(bool set)538 void PlasmaWindow::setCloseable(bool set)
539 {
540 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE, set);
541 }
542
setFullscreenable(bool set)543 void PlasmaWindow::setFullscreenable(bool set)
544 {
545 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE, set);
546 }
547
setMaximizeable(bool set)548 void PlasmaWindow::setMaximizeable(bool set)
549 {
550 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE, set);
551 }
552
setMinimizeable(bool set)553 void PlasmaWindow::setMinimizeable(bool set)
554 {
555 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE, set);
556 }
557
setSkipTaskbar(bool set)558 void PlasmaWindow::setSkipTaskbar(bool set)
559 {
560 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR, set);
561 }
562
setSkipSwitcher(bool set)563 void PlasmaWindow::setSkipSwitcher(bool set)
564 {
565 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER, set);
566 }
567
setIcon(const QIcon & icon)568 void PlasmaWindow::setIcon(const QIcon& icon)
569 {
570 d_ptr->setIcon(icon);
571 }
572
addPlasmaVirtualDesktop(const QString & id)573 void PlasmaWindow::addPlasmaVirtualDesktop(const QString& id)
574 {
575 // don't add a desktop we're not sure it exists
576 if (!d_ptr->manager->virtualDesktopManager() || d_ptr->plasmaVirtualDesktops.contains(id)) {
577 return;
578 }
579
580 PlasmaVirtualDesktop* desktop = d_ptr->manager->virtualDesktopManager()->desktop(id);
581
582 if (!desktop) {
583 return;
584 }
585
586 d_ptr->plasmaVirtualDesktops << id;
587
588 // if the desktop dies, remove it from or list
589 connect(desktop, &QObject::destroyed, this, [this, id]() { removePlasmaVirtualDesktop(id); });
590
591 for (auto it = d_ptr->resources.constBegin(); it != d_ptr->resources.constEnd(); ++it) {
592 (*it)->d_ptr->send<org_kde_plasma_window_send_virtual_desktop_entered>(
593 id.toUtf8().constData());
594 }
595 }
596
removePlasmaVirtualDesktop(const QString & id)597 void PlasmaWindow::removePlasmaVirtualDesktop(const QString& id)
598 {
599 if (!d_ptr->plasmaVirtualDesktops.contains(id)) {
600 return;
601 }
602
603 d_ptr->plasmaVirtualDesktops.removeAll(id);
604 for (auto it = d_ptr->resources.constBegin(); it != d_ptr->resources.constEnd(); ++it) {
605 (*it)->d_ptr->send<org_kde_plasma_window_send_virtual_desktop_left>(
606 id.toUtf8().constData());
607 }
608
609 // we went on all desktops
610 if (d_ptr->plasmaVirtualDesktops.isEmpty()) {
611 setOnAllDesktops(true);
612 }
613 }
614
plasmaVirtualDesktops() const615 QStringList PlasmaWindow::plasmaVirtualDesktops() const
616 {
617 return d_ptr->plasmaVirtualDesktops;
618 }
619
setShadeable(bool set)620 void PlasmaWindow::setShadeable(bool set)
621 {
622 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE, set);
623 }
624
setShaded(bool set)625 void PlasmaWindow::setShaded(bool set)
626 {
627 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, set);
628 }
629
setMovable(bool set)630 void PlasmaWindow::setMovable(bool set)
631 {
632 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE, set);
633 }
634
setResizable(bool set)635 void PlasmaWindow::setResizable(bool set)
636 {
637 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE, set);
638 }
639
setApplicationMenuPaths(const QString & serviceName,const QString & objectPath) const640 void PlasmaWindow::setApplicationMenuPaths(const QString& serviceName,
641 const QString& objectPath) const
642 {
643 d_ptr->setApplicationMenuPaths(serviceName, objectPath);
644 }
645
setVirtualDesktopChangeable(bool set)646 void PlasmaWindow::setVirtualDesktopChangeable(bool set)
647 {
648 d_ptr->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE, set);
649 }
650
setParentWindow(PlasmaWindow * parentWindow)651 void PlasmaWindow::setParentWindow(PlasmaWindow* parentWindow)
652 {
653 d_ptr->setParentWindow(parentWindow);
654 }
655
setGeometry(const QRect & geometry)656 void PlasmaWindow::setGeometry(const QRect& geometry)
657 {
658 d_ptr->setGeometry(geometry);
659 }
660
661 /////////////////////////// Plasma Window Resource ///////////////////////////
662
Private(Wayland::Client * client,uint32_t version,uint32_t id,PlasmaWindow * window,PlasmaWindowRes * q)663 PlasmaWindowRes::Private::Private(Wayland::Client* client,
664 uint32_t version,
665 uint32_t id,
666 PlasmaWindow* window,
667 PlasmaWindowRes* q)
668 : Wayland::Resource<PlasmaWindowRes>(client,
669 version,
670 id,
671 &org_kde_plasma_window_interface,
672 &s_interface,
673 q)
674 , window(window)
675 {
676 }
677
678 const struct org_kde_plasma_window_interface PlasmaWindowRes::Private::s_interface = {
679 setStateCallback,
680 setVirtualDesktopCallback,
681 setMinimizedGeometryCallback,
682 unsetMinimizedGeometryCallback,
683 closeCallback,
684 requestMoveCallback,
685 requestResizeCallback,
686 destroyCallback,
687 getIconCallback,
688 requestEnterVirtualDesktopCallback,
689 requestEnterNewVirtualDesktopCallback,
690 requestLeaveVirtualDesktopCallback,
691 };
692
getIconCallback(wl_client * wlClient,wl_resource * wlResource,int32_t fd)693 void PlasmaWindowRes::Private::getIconCallback([[maybe_unused]] wl_client* wlClient,
694 wl_resource* wlResource,
695 int32_t fd)
696 {
697 auto priv = handle(wlResource)->d_ptr;
698 if (!priv->window) {
699 return;
700 }
701 QtConcurrent::run(
702 [fd](const QIcon& icon) {
703 QFile file;
704 file.open(fd, QIODevice::WriteOnly, QFileDevice::AutoCloseHandle);
705 QDataStream ds(&file);
706 ds << icon;
707 file.close();
708 },
709 priv->window->d_ptr->m_icon);
710 }
711
requestEnterVirtualDesktopCallback(wl_client * wlClient,wl_resource * wlResource,const char * id)712 void PlasmaWindowRes::Private::requestEnterVirtualDesktopCallback(
713 [[maybe_unused]] wl_client* wlClient,
714 wl_resource* wlResource,
715 const char* id)
716 {
717 auto priv = handle(wlResource)->d_ptr;
718 if (!priv->window) {
719 return;
720 }
721 Q_EMIT priv->window->enterPlasmaVirtualDesktopRequested(QString::fromUtf8(id));
722 }
723
requestEnterNewVirtualDesktopCallback(wl_client * wlClient,wl_resource * wlResource)724 void PlasmaWindowRes::Private::requestEnterNewVirtualDesktopCallback(
725 [[maybe_unused]] wl_client* wlClient,
726 wl_resource* wlResource)
727 {
728 auto priv = handle(wlResource)->d_ptr;
729 if (!priv->window) {
730 return;
731 }
732 Q_EMIT priv->window->enterNewPlasmaVirtualDesktopRequested();
733 }
734
requestLeaveVirtualDesktopCallback(wl_client * wlClient,wl_resource * wlResource,const char * id)735 void PlasmaWindowRes::Private::requestLeaveVirtualDesktopCallback(
736 [[maybe_unused]] wl_client* wlClient,
737 wl_resource* wlResource,
738 const char* id)
739 {
740 auto priv = handle(wlResource)->d_ptr;
741 if (!priv->window) {
742 return;
743 }
744 Q_EMIT priv->window->leavePlasmaVirtualDesktopRequested(QString::fromUtf8(id));
745 }
746
closeCallback(wl_client * wlClient,wl_resource * wlResource)747 void PlasmaWindowRes::Private::closeCallback([[maybe_unused]] wl_client* wlClient,
748 wl_resource* wlResource)
749 {
750 auto priv = handle(wlResource)->d_ptr;
751 if (!priv->window) {
752 return;
753 }
754 Q_EMIT priv->window->closeRequested();
755 }
756
requestMoveCallback(wl_client * wlClient,wl_resource * wlResource)757 void PlasmaWindowRes::Private::requestMoveCallback([[maybe_unused]] wl_client* wlClient,
758 wl_resource* wlResource)
759 {
760 auto priv = handle(wlResource)->d_ptr;
761 if (!priv->window) {
762 return;
763 }
764 Q_EMIT priv->window->moveRequested();
765 }
766
requestResizeCallback(wl_client * wlClient,wl_resource * wlResource)767 void PlasmaWindowRes::Private::requestResizeCallback([[maybe_unused]] wl_client* wlClient,
768 wl_resource* wlResource)
769 {
770 auto priv = handle(wlResource)->d_ptr;
771 if (!priv->window) {
772 return;
773 }
774 Q_EMIT priv->window->resizeRequested();
775 }
776
setVirtualDesktopCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t number)777 void PlasmaWindowRes::Private::setVirtualDesktopCallback([[maybe_unused]] wl_client* wlClient,
778 [[maybe_unused]] wl_resource* wlResource,
779 [[maybe_unused]] uint32_t number)
780 {
781 }
782
setStateCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t flags,uint32_t desktopState)783 void PlasmaWindowRes::Private::setStateCallback([[maybe_unused]] wl_client* wlClient,
784 wl_resource* wlResource,
785 uint32_t flags,
786 uint32_t desktopState)
787 {
788 auto window = handle(wlResource)->d_ptr->window;
789 if (!window) {
790 return;
791 }
792
793 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE) {
794 Q_EMIT window->activeRequested(desktopState
795 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE);
796 }
797
798 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED) {
799 Q_EMIT window->minimizedRequested(desktopState
800 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED);
801 }
802
803 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED) {
804 Q_EMIT window->maximizedRequested(desktopState
805 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED);
806 }
807
808 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN) {
809 Q_EMIT window->fullscreenRequested(desktopState
810 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN);
811 }
812
813 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE) {
814 Q_EMIT window->keepAboveRequested(desktopState
815 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE);
816 }
817
818 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW) {
819 Q_EMIT window->keepBelowRequested(desktopState
820 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW);
821 }
822
823 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION) {
824 Q_EMIT window->demandsAttentionRequested(
825 desktopState & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION);
826 }
827
828 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE) {
829 Q_EMIT window->closeableRequested(desktopState
830 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE);
831 }
832
833 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE) {
834 Q_EMIT window->minimizeableRequested(desktopState
835 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE);
836 }
837
838 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE) {
839 Q_EMIT window->maximizeableRequested(desktopState
840 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE);
841 }
842
843 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE) {
844 Q_EMIT window->fullscreenableRequested(
845 desktopState & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE);
846 }
847
848 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR) {
849 Q_EMIT window->skipTaskbarRequested(desktopState
850 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR);
851 }
852
853 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER) {
854 Q_EMIT window->skipSwitcherRequested(desktopState
855 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER);
856 }
857
858 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE) {
859 Q_EMIT window->shadeableRequested(desktopState
860 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE);
861 }
862
863 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED) {
864 Q_EMIT window->shadedRequested(desktopState
865 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED);
866 }
867
868 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE) {
869 Q_EMIT window->movableRequested(desktopState
870 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE);
871 }
872
873 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE) {
874 Q_EMIT window->resizableRequested(desktopState
875 & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE);
876 }
877
878 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE) {
879 Q_EMIT window->virtualDesktopChangeableRequested(
880 desktopState & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE);
881 }
882 }
883
setMinimizedGeometryCallback(wl_client * wlClient,wl_resource * wlResource,wl_resource * wlPanel,uint32_t x,uint32_t y,uint32_t width,uint32_t height)884 void PlasmaWindowRes::Private::setMinimizedGeometryCallback([[maybe_unused]] wl_client* wlClient,
885 wl_resource* wlResource,
886 wl_resource* wlPanel,
887 uint32_t x,
888 uint32_t y,
889 uint32_t width,
890 uint32_t height)
891 {
892 auto priv = handle(wlResource)->d_ptr;
893 if (!priv->window) {
894 return;
895 }
896
897 auto panel = Wayland::Resource<Surface>::handle(wlPanel);
898 auto const rect = QRect(static_cast<int>(x),
899 static_cast<int>(y),
900 static_cast<int>(width),
901 static_cast<int>(height));
902
903 if (priv->window->d_ptr->minimizedGeometries.value(panel) == rect) {
904 return;
905 }
906
907 priv->window->d_ptr->minimizedGeometries[panel] = rect;
908 Q_EMIT priv->window->minimizedGeometriesChanged();
909 connect(panel, &Surface::resourceDestroyed, priv->handle(), [priv, panel]() {
910 if (priv->window && priv->window->d_ptr->minimizedGeometries.remove(panel)) {
911 Q_EMIT priv->window->minimizedGeometriesChanged();
912 }
913 });
914 }
915
unsetMinimizedGeometryCallback(wl_client * wlClient,wl_resource * wlResource,wl_resource * wlPanel)916 void PlasmaWindowRes::Private::unsetMinimizedGeometryCallback([[maybe_unused]] wl_client* wlClient,
917 wl_resource* wlResource,
918 wl_resource* wlPanel)
919 {
920 auto priv = handle(wlResource)->d_ptr;
921 if (!priv->window) {
922 return;
923 }
924
925 auto panel = Wayland::Resource<Surface>::handle(wlPanel);
926
927 if (!panel) {
928 return;
929 }
930 if (!priv->window->d_ptr->minimizedGeometries.contains(panel)) {
931 return;
932 }
933 priv->window->d_ptr->minimizedGeometries.remove(panel);
934 Q_EMIT priv->window->minimizedGeometriesChanged();
935 }
936
unmap()937 void PlasmaWindowRes::Private::unmap()
938 {
939 window = nullptr;
940 send<org_kde_plasma_window_send_unmapped>();
941 client()->flush();
942 }
943
PlasmaWindowRes(Wayland::Client * client,uint32_t version,uint32_t id,PlasmaWindow * window)944 PlasmaWindowRes::PlasmaWindowRes(Wayland::Client* client,
945 uint32_t version,
946 uint32_t id,
947 PlasmaWindow* window)
948 : QObject(nullptr)
949 , d_ptr(new Private(client, version, id, window, this))
950 {
951 }
952
unmap()953 void PlasmaWindowRes::unmap()
954 {
955 d_ptr->unmap();
956 }
957
958 }
959