File indexing completed on 2024-11-10 04:57:30
0001 /* 0002 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 #include "plasmawindowmanagement.h" 0007 #include "display.h" 0008 #include "output.h" 0009 #include "plasmavirtualdesktop.h" 0010 #include "surface.h" 0011 #include "utils/common.h" 0012 #include "wayland/quirks.h" 0013 0014 #include <QFile> 0015 #include <QHash> 0016 #include <QIcon> 0017 #include <QList> 0018 #include <QPointer> 0019 #include <QRect> 0020 #include <QThreadPool> 0021 #include <QUuid> 0022 0023 #include <qwayland-server-plasma-window-management.h> 0024 0025 namespace KWin 0026 { 0027 static const quint32 s_version = 16; 0028 static const quint32 s_activationVersion = 1; 0029 0030 class PlasmaWindowManagementInterfacePrivate : public QtWaylandServer::org_kde_plasma_window_management 0031 { 0032 public: 0033 PlasmaWindowManagementInterfacePrivate(PlasmaWindowManagementInterface *_q, Display *display); 0034 void sendShowingDesktopState(); 0035 void sendShowingDesktopState(wl_resource *resource); 0036 void sendStackingOrderChanged(); 0037 void sendStackingOrderChanged(wl_resource *resource); 0038 void sendStackingOrderUuidsChanged(); 0039 void sendStackingOrderUuidsChanged(wl_resource *resource); 0040 0041 PlasmaWindowManagementInterface::ShowingDesktopState state = PlasmaWindowManagementInterface::ShowingDesktopState::Disabled; 0042 QList<PlasmaWindowInterface *> windows; 0043 QPointer<PlasmaVirtualDesktopManagementInterface> plasmaVirtualDesktopManagementInterface = nullptr; 0044 quint32 windowIdCounter = 0; 0045 QList<quint32> stackingOrder; 0046 QList<QString> stackingOrderUuids; 0047 PlasmaWindowManagementInterface *q; 0048 0049 protected: 0050 void org_kde_plasma_window_management_bind_resource(Resource *resource) override; 0051 void org_kde_plasma_window_management_show_desktop(Resource *resource, uint32_t state) override; 0052 void org_kde_plasma_window_management_get_window(Resource *resource, uint32_t id, uint32_t internal_window_id) override; 0053 void org_kde_plasma_window_management_get_window_by_uuid(Resource *resource, uint32_t id, const QString &internal_window_uuid) override; 0054 }; 0055 0056 class PlasmaWindowInterfacePrivate : public QtWaylandServer::org_kde_plasma_window 0057 { 0058 public: 0059 PlasmaWindowInterfacePrivate(PlasmaWindowManagementInterface *wm, PlasmaWindowInterface *q); 0060 ~PlasmaWindowInterfacePrivate(); 0061 0062 class PlasmaWindowResource : public QtWaylandServer::org_kde_plasma_window::Resource 0063 { 0064 public: 0065 QtWaylandServer::org_kde_plasma_window_management::Resource *wmResource = nullptr; 0066 }; 0067 0068 void setTitle(const QString &title); 0069 void setAppId(const QString &appId); 0070 void setPid(quint32 pid); 0071 void setThemedIconName(const QString &iconName); 0072 void setIcon(const QIcon &icon); 0073 void unmap(); 0074 void setState(org_kde_plasma_window_management_state flag, bool set); 0075 void setParentWindow(PlasmaWindowInterface *parent); 0076 void setGeometry(const QRect &geometry); 0077 void setApplicationMenuPaths(const QString &service, const QString &object); 0078 void setResourceName(const QString &resourceName); 0079 void sendInitialState(Resource *resource); 0080 wl_resource *resourceForParent(PlasmaWindowInterface *parent, Resource *child) const; 0081 0082 quint32 windowId = 0; 0083 QHash<SurfaceInterface *, QRect> minimizedGeometries; 0084 PlasmaWindowManagementInterface *wm; 0085 0086 bool unmapped = false; 0087 PlasmaWindowInterface *parentWindow = nullptr; 0088 QMetaObject::Connection parentWindowDestroyConnection; 0089 QStringList plasmaVirtualDesktops; 0090 QStringList plasmaActivities; 0091 QRect geometry; 0092 PlasmaWindowInterface *q; 0093 QString m_title; 0094 QString m_appId; 0095 quint32 m_pid = 0; 0096 QString m_themedIconName; 0097 QString m_appServiceName; 0098 QString m_appObjectPath; 0099 QIcon m_icon; 0100 quint32 m_state = 0; 0101 QString uuid; 0102 QString m_resourceName; 0103 0104 protected: 0105 Resource *org_kde_plasma_window_allocate() override; 0106 void org_kde_plasma_window_set_state(Resource *resource, uint32_t flags, uint32_t state) override; 0107 void org_kde_plasma_window_set_virtual_desktop(Resource *resource, uint32_t number) override; 0108 void org_kde_plasma_window_set_minimized_geometry(Resource *resource, wl_resource *panel, uint32_t x, uint32_t y, uint32_t width, uint32_t height) override; 0109 void org_kde_plasma_window_unset_minimized_geometry(Resource *resource, wl_resource *panel) override; 0110 void org_kde_plasma_window_close(Resource *resource) override; 0111 void org_kde_plasma_window_request_move(Resource *resource) override; 0112 void org_kde_plasma_window_request_resize(Resource *resource) override; 0113 void org_kde_plasma_window_destroy(Resource *resource) override; 0114 void org_kde_plasma_window_get_icon(Resource *resource, int32_t fd) override; 0115 void org_kde_plasma_window_request_enter_virtual_desktop(Resource *resource, const QString &id) override; 0116 void org_kde_plasma_window_request_enter_new_virtual_desktop(Resource *resource) override; 0117 void org_kde_plasma_window_request_leave_virtual_desktop(Resource *resource, const QString &id) override; 0118 void org_kde_plasma_window_request_enter_activity(Resource *resource, const QString &id) override; 0119 void org_kde_plasma_window_request_leave_activity(Resource *resource, const QString &id) override; 0120 void org_kde_plasma_window_send_to_output(Resource *resource, struct wl_resource *output) override; 0121 }; 0122 0123 PlasmaWindowManagementInterfacePrivate::PlasmaWindowManagementInterfacePrivate(PlasmaWindowManagementInterface *_q, Display *display) 0124 : QtWaylandServer::org_kde_plasma_window_management(*display, s_version) 0125 , q(_q) 0126 { 0127 } 0128 0129 void PlasmaWindowManagementInterfacePrivate::sendShowingDesktopState() 0130 { 0131 const auto clientResources = resourceMap(); 0132 for (auto resource : clientResources) { 0133 sendShowingDesktopState(resource->handle); 0134 } 0135 } 0136 0137 void PlasmaWindowManagementInterfacePrivate::sendShowingDesktopState(wl_resource *r) 0138 { 0139 uint32_t s = 0; 0140 switch (state) { 0141 case PlasmaWindowManagementInterface::ShowingDesktopState::Enabled: 0142 s = QtWaylandServer::org_kde_plasma_window_management::show_desktop_enabled; 0143 break; 0144 case PlasmaWindowManagementInterface::ShowingDesktopState::Disabled: 0145 s = QtWaylandServer::org_kde_plasma_window_management::show_desktop_disabled; 0146 break; 0147 default: 0148 Q_UNREACHABLE(); 0149 break; 0150 } 0151 send_show_desktop_changed(r, s); 0152 } 0153 0154 void PlasmaWindowManagementInterfacePrivate::sendStackingOrderChanged() 0155 { 0156 const auto clientResources = resourceMap(); 0157 for (auto resource : clientResources) { 0158 sendStackingOrderChanged(resource->handle); 0159 } 0160 } 0161 0162 void PlasmaWindowManagementInterfacePrivate::sendStackingOrderChanged(wl_resource *r) 0163 { 0164 if (wl_resource_get_version(r) < ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STACKING_ORDER_CHANGED_SINCE_VERSION) { 0165 return; 0166 } 0167 0168 send_stacking_order_changed(r, QByteArray::fromRawData(reinterpret_cast<const char *>(stackingOrder.constData()), sizeof(uint32_t) * stackingOrder.size())); 0169 } 0170 0171 void PlasmaWindowManagementInterfacePrivate::sendStackingOrderUuidsChanged() 0172 { 0173 const auto clientResources = resourceMap(); 0174 for (auto resource : clientResources) { 0175 sendStackingOrderUuidsChanged(resource->handle); 0176 } 0177 } 0178 0179 void PlasmaWindowManagementInterfacePrivate::sendStackingOrderUuidsChanged(wl_resource *r) 0180 { 0181 if (wl_resource_get_version(r) < ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STACKING_ORDER_UUID_CHANGED_SINCE_VERSION) { 0182 return; 0183 } 0184 0185 QString uuids; 0186 for (const auto &uuid : std::as_const(stackingOrderUuids)) { 0187 uuids += uuid; 0188 uuids += QLatin1Char(';'); 0189 } 0190 // Remove the trailing ';', on the receiving side this is interpreted as an empty uuid. 0191 if (stackingOrderUuids.size() > 0) { 0192 uuids.remove(uuids.length() - 1, 1); 0193 } 0194 send_stacking_order_uuid_changed(r, uuids); 0195 } 0196 0197 void PlasmaWindowManagementInterfacePrivate::org_kde_plasma_window_management_bind_resource(Resource *resource) 0198 { 0199 for (const auto window : std::as_const(windows)) { 0200 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_MANAGEMENT_WINDOW_WITH_UUID_SINCE_VERSION) { 0201 send_window_with_uuid(resource->handle, window->d->windowId, window->d->uuid); 0202 } else { 0203 send_window(resource->handle, window->d->windowId); 0204 } 0205 } 0206 sendStackingOrderChanged(resource->handle); 0207 sendStackingOrderUuidsChanged(resource->handle); 0208 } 0209 0210 void PlasmaWindowManagementInterfacePrivate::org_kde_plasma_window_management_show_desktop(Resource *resource, uint32_t state) 0211 { 0212 PlasmaWindowManagementInterface::ShowingDesktopState s = PlasmaWindowManagementInterface::ShowingDesktopState::Disabled; 0213 switch (state) { 0214 case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED: 0215 s = PlasmaWindowManagementInterface::ShowingDesktopState::Enabled; 0216 break; 0217 case ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED: 0218 default: 0219 s = PlasmaWindowManagementInterface::ShowingDesktopState::Disabled; 0220 break; 0221 } 0222 Q_EMIT q->requestChangeShowingDesktop(s); 0223 } 0224 0225 void PlasmaWindowManagementInterfacePrivate::org_kde_plasma_window_management_get_window(Resource *resource, uint32_t id, uint32_t internal_window_id) 0226 { 0227 for (const auto window : std::as_const(windows)) { 0228 if (window->d->windowId == internal_window_id) { 0229 auto windowResource = window->d->add(resource->client(), id, resource->version()); 0230 static_cast<PlasmaWindowInterfacePrivate::PlasmaWindowResource *>(windowResource)->wmResource = resource; 0231 window->d->sendInitialState(windowResource); 0232 } 0233 } 0234 // create a temp window just for the resource, bind then immediately delete it, sending an unmap event 0235 PlasmaWindowInterface window(q, q); 0236 auto windowResource = window.d->add(resource->client(), id, resource->version()); 0237 window.d->sendInitialState(windowResource); 0238 } 0239 0240 void PlasmaWindowManagementInterfacePrivate::org_kde_plasma_window_management_get_window_by_uuid(Resource *resource, 0241 uint32_t id, 0242 const QString &internal_window_uuid) 0243 { 0244 auto it = std::find_if(windows.constBegin(), windows.constEnd(), [internal_window_uuid](PlasmaWindowInterface *window) { 0245 return window->d->uuid == internal_window_uuid; 0246 }); 0247 if (it == windows.constEnd()) { 0248 qCWarning(KWIN_CORE) << "Could not find window with uuid" << internal_window_uuid; 0249 // create a temp window just for the resource, bind then immediately delete it, sending an unmap event 0250 PlasmaWindowInterface window(q, q); 0251 auto windowResource = window.d->add(resource->client(), id, resource->version()); 0252 window.d->sendInitialState(windowResource); 0253 return; 0254 } 0255 auto windowResource = (*it)->d->add(resource->client(), id, resource->version()); 0256 static_cast<PlasmaWindowInterfacePrivate::PlasmaWindowResource *>(windowResource)->wmResource = resource; 0257 (*it)->d->sendInitialState(windowResource); 0258 } 0259 0260 PlasmaWindowManagementInterface::PlasmaWindowManagementInterface(Display *display, QObject *parent) 0261 : QObject(parent) 0262 , d(new PlasmaWindowManagementInterfacePrivate(this, display)) 0263 { 0264 } 0265 0266 PlasmaWindowManagementInterface::~PlasmaWindowManagementInterface() = default; 0267 0268 void PlasmaWindowManagementInterface::setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState state) 0269 { 0270 if (d->state == state) { 0271 return; 0272 } 0273 d->state = state; 0274 d->sendShowingDesktopState(); 0275 } 0276 0277 PlasmaWindowInterface *PlasmaWindowManagementInterface::createWindow(QObject *parent, const QUuid &uuid) 0278 { 0279 PlasmaWindowInterface *window = new PlasmaWindowInterface(this, parent); 0280 0281 window->d->uuid = uuid.toString(); 0282 window->d->windowId = ++d->windowIdCounter; // NOTE the window id is deprecated 0283 0284 const auto clientResources = d->resourceMap(); 0285 for (auto resource : clientResources) { 0286 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_MANAGEMENT_WINDOW_WITH_UUID_SINCE_VERSION) { 0287 d->send_window_with_uuid(resource->handle, window->d->windowId, window->d->uuid); 0288 } else { 0289 d->send_window(resource->handle, window->d->windowId); 0290 } 0291 } 0292 d->windows << window; 0293 connect(window, &QObject::destroyed, this, [this, window] { 0294 d->windows.removeAll(window); 0295 }); 0296 return window; 0297 } 0298 0299 QList<PlasmaWindowInterface *> PlasmaWindowManagementInterface::windows() const 0300 { 0301 return d->windows; 0302 } 0303 0304 void PlasmaWindowManagementInterface::setStackingOrder(const QList<quint32> &stackingOrder) 0305 { 0306 if (d->stackingOrder == stackingOrder) { 0307 return; 0308 } 0309 d->stackingOrder = stackingOrder; 0310 d->sendStackingOrderChanged(); 0311 } 0312 0313 void PlasmaWindowManagementInterface::setStackingOrderUuids(const QList<QString> &stackingOrderUuids) 0314 { 0315 if (d->stackingOrderUuids == stackingOrderUuids) { 0316 return; 0317 } 0318 d->stackingOrderUuids = stackingOrderUuids; 0319 d->sendStackingOrderUuidsChanged(); 0320 } 0321 0322 void PlasmaWindowManagementInterface::setPlasmaVirtualDesktopManagementInterface(PlasmaVirtualDesktopManagementInterface *manager) 0323 { 0324 if (d->plasmaVirtualDesktopManagementInterface == manager) { 0325 return; 0326 } 0327 d->plasmaVirtualDesktopManagementInterface = manager; 0328 } 0329 0330 PlasmaVirtualDesktopManagementInterface *PlasmaWindowManagementInterface::plasmaVirtualDesktopManagementInterface() const 0331 { 0332 return d->plasmaVirtualDesktopManagementInterface; 0333 } 0334 0335 //////PlasmaWindow 0336 PlasmaWindowInterfacePrivate::PlasmaWindowInterfacePrivate(PlasmaWindowManagementInterface *wm, PlasmaWindowInterface *q) 0337 : QtWaylandServer::org_kde_plasma_window() 0338 , wm(wm) 0339 , q(q) 0340 { 0341 } 0342 0343 PlasmaWindowInterfacePrivate::~PlasmaWindowInterfacePrivate() 0344 { 0345 unmap(); 0346 } 0347 0348 QtWaylandServer::org_kde_plasma_window::Resource *PlasmaWindowInterfacePrivate::org_kde_plasma_window_allocate() 0349 { 0350 return new PlasmaWindowResource; 0351 } 0352 0353 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_destroy(Resource *resource) 0354 { 0355 wl_resource_destroy(resource->handle); 0356 } 0357 0358 void PlasmaWindowInterfacePrivate::sendInitialState(Resource *resource) 0359 { 0360 for (const auto &desk : std::as_const(plasmaVirtualDesktops)) { 0361 send_virtual_desktop_entered(resource->handle, desk); 0362 } 0363 for (const auto &activity : std::as_const(plasmaActivities)) { 0364 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ACTIVITY_ENTERED_SINCE_VERSION) { 0365 send_activity_entered(resource->handle, activity); 0366 } 0367 } 0368 if (!m_appId.isEmpty()) { 0369 send_app_id_changed(resource->handle, truncate(m_appId)); 0370 } 0371 if (m_pid != 0) { 0372 send_pid_changed(resource->handle, m_pid); 0373 } 0374 if (!m_title.isEmpty()) { 0375 send_title_changed(resource->handle, truncate(m_title)); 0376 } 0377 if (!m_appObjectPath.isEmpty() || !m_appServiceName.isEmpty()) { 0378 send_application_menu(resource->handle, m_appServiceName, m_appObjectPath); 0379 } 0380 send_state_changed(resource->handle, m_state); 0381 if (!m_themedIconName.isEmpty()) { 0382 send_themed_icon_name_changed(resource->handle, m_themedIconName); 0383 } else if (!m_icon.isNull()) { 0384 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) { 0385 send_icon_changed(resource->handle); 0386 } 0387 } 0388 0389 send_parent_window(resource->handle, resourceForParent(parentWindow, resource)); 0390 0391 if (geometry.isValid() && resource->version() >= ORG_KDE_PLASMA_WINDOW_GEOMETRY_SINCE_VERSION) { 0392 send_geometry(resource->handle, geometry.x(), geometry.y(), geometry.width(), geometry.height()); 0393 } 0394 0395 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_INITIAL_STATE_SINCE_VERSION) { 0396 send_initial_state(resource->handle); 0397 } 0398 if (!m_resourceName.isEmpty()) { 0399 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_RESOURCE_NAME_CHANGED_SINCE_VERSION) { 0400 send_resource_name_changed(resource->handle, m_resourceName); 0401 } 0402 } 0403 } 0404 0405 void PlasmaWindowInterfacePrivate::setAppId(const QString &appId) 0406 { 0407 if (m_appId == appId) { 0408 return; 0409 } 0410 0411 m_appId = appId; 0412 const auto clientResources = resourceMap(); 0413 0414 for (auto resource : clientResources) { 0415 send_app_id_changed(resource->handle, truncate(m_appId)); 0416 } 0417 } 0418 0419 void PlasmaWindowInterfacePrivate::setPid(quint32 pid) 0420 { 0421 if (m_pid == pid) { 0422 return; 0423 } 0424 m_pid = pid; 0425 const auto clientResources = resourceMap(); 0426 0427 for (auto resource : clientResources) { 0428 send_pid_changed(resource->handle, pid); 0429 } 0430 } 0431 0432 void PlasmaWindowInterfacePrivate::setThemedIconName(const QString &iconName) 0433 { 0434 if (m_themedIconName == iconName) { 0435 return; 0436 } 0437 m_themedIconName = iconName; 0438 const auto clientResources = resourceMap(); 0439 0440 for (auto resource : clientResources) { 0441 send_themed_icon_name_changed(resource->handle, m_themedIconName); 0442 } 0443 } 0444 0445 void PlasmaWindowInterfacePrivate::setIcon(const QIcon &icon) 0446 { 0447 m_icon = icon; 0448 setThemedIconName(m_icon.name()); 0449 0450 const auto clientResources = resourceMap(); 0451 for (auto resource : clientResources) { 0452 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) { 0453 send_icon_changed(resource->handle); 0454 } 0455 } 0456 } 0457 0458 void PlasmaWindowInterfacePrivate::setResourceName(const QString &resourceName) 0459 { 0460 if (m_resourceName == resourceName) { 0461 return; 0462 } 0463 m_resourceName = resourceName; 0464 0465 const auto clientResources = resourceMap(); 0466 for (auto resource : clientResources) { 0467 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_RESOURCE_NAME_CHANGED_SINCE_VERSION) { 0468 send_resource_name_changed(resource->handle, resourceName); 0469 } 0470 } 0471 } 0472 0473 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_get_icon(Resource *resource, int32_t fd) 0474 { 0475 QThreadPool::globalInstance()->start([fd, icon = m_icon]() { 0476 QFile file; 0477 file.open(fd, QIODevice::WriteOnly, QFileDevice::AutoCloseHandle); 0478 QDataStream ds(&file); 0479 ds << icon; 0480 file.close(); 0481 }); 0482 } 0483 0484 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_enter_virtual_desktop(Resource *resource, const QString &id) 0485 { 0486 Q_EMIT q->enterPlasmaVirtualDesktopRequested(id); 0487 } 0488 0489 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_enter_new_virtual_desktop(Resource *resource) 0490 { 0491 Q_EMIT q->enterNewPlasmaVirtualDesktopRequested(); 0492 } 0493 0494 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_leave_virtual_desktop(Resource *resource, const QString &id) 0495 { 0496 Q_EMIT q->leavePlasmaVirtualDesktopRequested(id); 0497 } 0498 0499 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_enter_activity(Resource *resource, const QString &id) 0500 { 0501 Q_EMIT q->enterPlasmaActivityRequested(id); 0502 } 0503 0504 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_leave_activity(Resource *resource, const QString &id) 0505 { 0506 Q_EMIT q->leavePlasmaActivityRequested(id); 0507 } 0508 0509 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_send_to_output(Resource *resource, struct wl_resource *output) 0510 { 0511 Q_EMIT q->sendToOutput(OutputInterface::get(output)); 0512 } 0513 0514 void PlasmaWindowInterfacePrivate::setTitle(const QString &title) 0515 { 0516 if (m_title == title) { 0517 return; 0518 } 0519 m_title = title; 0520 const auto clientResources = resourceMap(); 0521 0522 for (auto resource : clientResources) { 0523 send_title_changed(resource->handle, truncate(m_title)); 0524 } 0525 } 0526 0527 void PlasmaWindowInterfacePrivate::unmap() 0528 { 0529 if (unmapped) { 0530 return; 0531 } 0532 unmapped = true; 0533 const auto clientResources = resourceMap(); 0534 0535 for (auto resource : clientResources) { 0536 send_unmapped(resource->handle); 0537 } 0538 } 0539 0540 void PlasmaWindowInterfacePrivate::setState(org_kde_plasma_window_management_state flag, bool set) 0541 { 0542 quint32 newState = m_state; 0543 if (set) { 0544 newState |= flag; 0545 } else { 0546 newState &= ~flag; 0547 } 0548 if (newState == m_state) { 0549 return; 0550 } 0551 m_state = newState; 0552 const auto clientResources = resourceMap(); 0553 0554 for (auto resource : clientResources) { 0555 send_state_changed(resource->handle, m_state); 0556 } 0557 } 0558 0559 wl_resource *PlasmaWindowInterfacePrivate::resourceForParent(PlasmaWindowInterface *parent, Resource *child) const 0560 { 0561 if (!parent) { 0562 return nullptr; 0563 } 0564 0565 const auto parentResource = parent->d->resourceMap(); 0566 0567 for (auto resource : parentResource) { 0568 if (static_cast<PlasmaWindowResource *>(child)->wmResource == static_cast<PlasmaWindowResource *>(resource)->wmResource) { 0569 return resource->handle; 0570 } 0571 } 0572 return nullptr; 0573 } 0574 0575 void PlasmaWindowInterfacePrivate::setParentWindow(PlasmaWindowInterface *window) 0576 { 0577 if (parentWindow == window) { 0578 return; 0579 } 0580 QObject::disconnect(parentWindowDestroyConnection); 0581 parentWindowDestroyConnection = QMetaObject::Connection(); 0582 parentWindow = window; 0583 if (parentWindow) { 0584 parentWindowDestroyConnection = QObject::connect(window, &QObject::destroyed, q, [this] { 0585 parentWindow = nullptr; 0586 parentWindowDestroyConnection = QMetaObject::Connection(); 0587 const auto clientResources = resourceMap(); 0588 for (auto resource : clientResources) { 0589 send_parent_window(resource->handle, nullptr); 0590 } 0591 }); 0592 } 0593 const auto clientResources = resourceMap(); 0594 for (auto resource : clientResources) { 0595 send_parent_window(resource->handle, resourceForParent(window, resource)); 0596 } 0597 } 0598 0599 void PlasmaWindowInterfacePrivate::setGeometry(const QRect &geo) 0600 { 0601 if (geometry == geo) { 0602 return; 0603 } 0604 geometry = geo; 0605 if (!geometry.isValid()) { 0606 return; 0607 } 0608 0609 const auto clientResources = resourceMap(); 0610 for (auto resource : clientResources) { 0611 if (resource->version() < ORG_KDE_PLASMA_WINDOW_GEOMETRY_SINCE_VERSION) { 0612 continue; 0613 } 0614 send_geometry(resource->handle, geometry.x(), geometry.y(), geometry.width(), geometry.height()); 0615 } 0616 } 0617 0618 void PlasmaWindowInterfacePrivate::setApplicationMenuPaths(const QString &service, const QString &object) 0619 { 0620 if (m_appServiceName == service && m_appObjectPath == object) { 0621 return; 0622 } 0623 m_appServiceName = service; 0624 m_appObjectPath = object; 0625 const auto clientResources = resourceMap(); 0626 for (auto resource : clientResources) { 0627 if (resource->version() < ORG_KDE_PLASMA_WINDOW_APPLICATION_MENU_SINCE_VERSION) { 0628 continue; 0629 } 0630 send_application_menu(resource->handle, service, object); 0631 } 0632 } 0633 0634 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_close(Resource *resource) 0635 { 0636 Q_EMIT q->closeRequested(); 0637 } 0638 0639 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_move(Resource *resource) 0640 { 0641 Q_EMIT q->moveRequested(); 0642 } 0643 0644 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_request_resize(Resource *resource) 0645 { 0646 Q_EMIT q->resizeRequested(); 0647 } 0648 0649 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_set_virtual_desktop(Resource *resource, uint32_t number) 0650 { 0651 // This method is intentionally left blank. 0652 } 0653 0654 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_set_state(Resource *resource, uint32_t flags, uint32_t state) 0655 { 0656 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE) { 0657 Q_EMIT q->activeRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE); 0658 } 0659 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED) { 0660 Q_EMIT q->minimizedRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED); 0661 } 0662 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED) { 0663 Q_EMIT q->maximizedRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED); 0664 } 0665 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN) { 0666 Q_EMIT q->fullscreenRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN); 0667 } 0668 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE) { 0669 Q_EMIT q->keepAboveRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE); 0670 } 0671 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW) { 0672 Q_EMIT q->keepBelowRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW); 0673 } 0674 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION) { 0675 Q_EMIT q->demandsAttentionRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION); 0676 } 0677 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE) { 0678 Q_EMIT q->closeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE); 0679 } 0680 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE) { 0681 Q_EMIT q->minimizeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE); 0682 } 0683 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE) { 0684 Q_EMIT q->maximizeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE); 0685 } 0686 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE) { 0687 Q_EMIT q->fullscreenableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE); 0688 } 0689 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR) { 0690 Q_EMIT q->skipTaskbarRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR); 0691 } 0692 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER) { 0693 Q_EMIT q->skipSwitcherRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER); 0694 } 0695 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE) { 0696 Q_EMIT q->shadeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE); 0697 } 0698 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED) { 0699 Q_EMIT q->shadedRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED); 0700 } 0701 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE) { 0702 Q_EMIT q->movableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE); 0703 } 0704 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE) { 0705 Q_EMIT q->resizableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE); 0706 } 0707 if (flags & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE) { 0708 Q_EMIT q->virtualDesktopChangeableRequested(state & ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE); 0709 } 0710 } 0711 0712 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_set_minimized_geometry(Resource *resource, 0713 wl_resource *panel, 0714 uint32_t x, 0715 uint32_t y, 0716 uint32_t width, 0717 uint32_t height) 0718 { 0719 SurfaceInterface *panelSurface = SurfaceInterface::get(panel); 0720 0721 if (!panelSurface) { 0722 return; 0723 } 0724 0725 if (minimizedGeometries.value(panelSurface) == QRect(x, y, width, height)) { 0726 return; 0727 } 0728 0729 minimizedGeometries[panelSurface] = QRect(x, y, width, height); 0730 Q_EMIT q->minimizedGeometriesChanged(); 0731 QObject::connect(panelSurface, &QObject::destroyed, q, [this, panelSurface]() { 0732 if (minimizedGeometries.remove(panelSurface)) { 0733 Q_EMIT q->minimizedGeometriesChanged(); 0734 } 0735 }); 0736 } 0737 0738 void PlasmaWindowInterfacePrivate::org_kde_plasma_window_unset_minimized_geometry(Resource *resource, wl_resource *panel) 0739 { 0740 SurfaceInterface *panelSurface = SurfaceInterface::get(panel); 0741 0742 if (!panelSurface) { 0743 return; 0744 } 0745 if (!minimizedGeometries.contains(panelSurface)) { 0746 return; 0747 } 0748 minimizedGeometries.remove(panelSurface); 0749 Q_EMIT q->minimizedGeometriesChanged(); 0750 } 0751 0752 PlasmaWindowInterface::PlasmaWindowInterface(PlasmaWindowManagementInterface *wm, QObject *parent) 0753 : QObject(parent) 0754 , d(new PlasmaWindowInterfacePrivate(wm, this)) 0755 { 0756 } 0757 0758 PlasmaWindowInterface::~PlasmaWindowInterface() = default; 0759 0760 void PlasmaWindowInterface::setAppId(const QString &appId) 0761 { 0762 d->setAppId(appId); 0763 } 0764 0765 void PlasmaWindowInterface::setPid(quint32 pid) 0766 { 0767 d->setPid(pid); 0768 } 0769 0770 void PlasmaWindowInterface::setTitle(const QString &title) 0771 { 0772 d->setTitle(title); 0773 } 0774 0775 void PlasmaWindowInterface::unmap() 0776 { 0777 d->unmap(); 0778 } 0779 0780 QHash<SurfaceInterface *, QRect> PlasmaWindowInterface::minimizedGeometries() const 0781 { 0782 return d->minimizedGeometries; 0783 } 0784 0785 void PlasmaWindowInterface::setActive(bool set) 0786 { 0787 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE, set); 0788 } 0789 0790 void PlasmaWindowInterface::setFullscreen(bool set) 0791 { 0792 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN, set); 0793 } 0794 0795 void PlasmaWindowInterface::setKeepAbove(bool set) 0796 { 0797 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE, set); 0798 } 0799 0800 void PlasmaWindowInterface::setKeepBelow(bool set) 0801 { 0802 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW, set); 0803 } 0804 0805 void PlasmaWindowInterface::setMaximized(bool set) 0806 { 0807 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED, set); 0808 } 0809 0810 void PlasmaWindowInterface::setMinimized(bool set) 0811 { 0812 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED, set); 0813 } 0814 0815 void PlasmaWindowInterface::setOnAllDesktops(bool set) 0816 { 0817 // the deprecated vd management 0818 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ON_ALL_DESKTOPS, set); 0819 0820 if (!d->wm->plasmaVirtualDesktopManagementInterface()) { 0821 return; 0822 } 0823 const auto clientResources = d->resourceMap(); 0824 // the current vd management 0825 if (set) { 0826 if (d->plasmaVirtualDesktops.isEmpty()) { 0827 return; 0828 } 0829 // leaving everything means on all desktops 0830 for (auto desk : plasmaVirtualDesktops()) { 0831 for (auto resource : clientResources) { 0832 d->send_virtual_desktop_left(resource->handle, desk); 0833 } 0834 } 0835 d->plasmaVirtualDesktops.clear(); 0836 } else { 0837 if (!d->plasmaVirtualDesktops.isEmpty()) { 0838 return; 0839 } 0840 // enters the desktops which are active (usually only one but not a given) 0841 const auto desktops = d->wm->plasmaVirtualDesktopManagementInterface()->desktops(); 0842 for (const auto desktop : desktops) { 0843 if (desktop->isActive() && !d->plasmaVirtualDesktops.contains(desktop->id())) { 0844 d->plasmaVirtualDesktops << desktop->id(); 0845 for (auto resource : clientResources) { 0846 d->send_virtual_desktop_entered(resource->handle, desktop->id()); 0847 } 0848 } 0849 } 0850 } 0851 } 0852 0853 void PlasmaWindowInterface::setDemandsAttention(bool set) 0854 { 0855 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION, set); 0856 } 0857 0858 void PlasmaWindowInterface::setCloseable(bool set) 0859 { 0860 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE, set); 0861 } 0862 0863 void PlasmaWindowInterface::setFullscreenable(bool set) 0864 { 0865 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE, set); 0866 } 0867 0868 void PlasmaWindowInterface::setMaximizeable(bool set) 0869 { 0870 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE, set); 0871 } 0872 0873 void PlasmaWindowInterface::setMinimizeable(bool set) 0874 { 0875 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE, set); 0876 } 0877 0878 void PlasmaWindowInterface::setSkipTaskbar(bool set) 0879 { 0880 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR, set); 0881 } 0882 0883 void PlasmaWindowInterface::setSkipSwitcher(bool skip) 0884 { 0885 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER, skip); 0886 } 0887 0888 void PlasmaWindowInterface::setIcon(const QIcon &icon) 0889 { 0890 d->setIcon(icon); 0891 } 0892 0893 void PlasmaWindowInterface::setResourceName(const QString &resourceName) 0894 { 0895 d->setResourceName(resourceName); 0896 } 0897 0898 void PlasmaWindowInterface::addPlasmaVirtualDesktop(const QString &id) 0899 { 0900 // don't add a desktop we're not sure it exists 0901 if (!d->wm->plasmaVirtualDesktopManagementInterface() || d->plasmaVirtualDesktops.contains(id)) { 0902 return; 0903 } 0904 0905 PlasmaVirtualDesktopInterface *desktop = d->wm->plasmaVirtualDesktopManagementInterface()->desktop(id); 0906 0907 if (!desktop) { 0908 return; 0909 } 0910 0911 d->plasmaVirtualDesktops << id; 0912 0913 // if the desktop dies, remove it from or list 0914 connect(desktop, &QObject::destroyed, this, [this, id]() { 0915 removePlasmaVirtualDesktop(id); 0916 }); 0917 0918 const auto clientResources = d->resourceMap(); 0919 for (auto resource : clientResources) { 0920 d->send_virtual_desktop_entered(resource->handle, id); 0921 } 0922 } 0923 0924 void PlasmaWindowInterface::removePlasmaVirtualDesktop(const QString &id) 0925 { 0926 if (!d->plasmaVirtualDesktops.contains(id)) { 0927 return; 0928 } 0929 0930 d->plasmaVirtualDesktops.removeAll(id); 0931 const auto clientResources = d->resourceMap(); 0932 for (auto resource : clientResources) { 0933 d->send_virtual_desktop_left(resource->handle, id); 0934 } 0935 0936 // we went on all desktops 0937 if (d->plasmaVirtualDesktops.isEmpty()) { 0938 setOnAllDesktops(true); 0939 } 0940 } 0941 0942 QStringList PlasmaWindowInterface::plasmaVirtualDesktops() const 0943 { 0944 return d->plasmaVirtualDesktops; 0945 } 0946 0947 void PlasmaWindowInterface::addPlasmaActivity(const QString &id) 0948 { 0949 if (d->plasmaActivities.contains(id)) { 0950 return; 0951 } 0952 0953 d->plasmaActivities << id; 0954 0955 const auto clientResources = d->resourceMap(); 0956 for (auto resource : clientResources) { 0957 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ACTIVITY_ENTERED_SINCE_VERSION) { 0958 d->send_activity_entered(resource->handle, id); 0959 } 0960 } 0961 } 0962 0963 void PlasmaWindowInterface::removePlasmaActivity(const QString &id) 0964 { 0965 if (!d->plasmaActivities.removeOne(id)) { 0966 return; 0967 } 0968 0969 const auto clientResources = d->resourceMap(); 0970 for (auto resource : clientResources) { 0971 if (resource->version() >= ORG_KDE_PLASMA_WINDOW_ACTIVITY_LEFT_SINCE_VERSION) { 0972 d->send_activity_left(resource->handle, id); 0973 } 0974 } 0975 } 0976 0977 QStringList PlasmaWindowInterface::plasmaActivities() const 0978 { 0979 return d->plasmaActivities; 0980 } 0981 0982 void PlasmaWindowInterface::setShadeable(bool set) 0983 { 0984 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE, set); 0985 } 0986 0987 void PlasmaWindowInterface::setShaded(bool set) 0988 { 0989 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED, set); 0990 } 0991 0992 void PlasmaWindowInterface::setMovable(bool set) 0993 { 0994 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE, set); 0995 } 0996 0997 void PlasmaWindowInterface::setResizable(bool set) 0998 { 0999 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE, set); 1000 } 1001 1002 void PlasmaWindowInterface::setVirtualDesktopChangeable(bool set) 1003 { 1004 d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE, set); 1005 } 1006 1007 void PlasmaWindowInterface::setParentWindow(PlasmaWindowInterface *parentWindow) 1008 { 1009 d->setParentWindow(parentWindow); 1010 } 1011 1012 void PlasmaWindowInterface::setGeometry(const QRect &geometry) 1013 { 1014 d->setGeometry(geometry); 1015 } 1016 1017 void PlasmaWindowInterface::setApplicationMenuPaths(const QString &serviceName, const QString &objectPath) 1018 { 1019 d->setApplicationMenuPaths(serviceName, objectPath); 1020 } 1021 1022 quint32 PlasmaWindowInterface::internalId() const 1023 { 1024 return d->windowId; 1025 } 1026 1027 QString PlasmaWindowInterface::uuid() const 1028 { 1029 return d->uuid; 1030 } 1031 1032 class PlasmaWindowActivationFeedbackInterfacePrivate : public QtWaylandServer::org_kde_plasma_activation_feedback 1033 { 1034 public: 1035 explicit PlasmaWindowActivationFeedbackInterfacePrivate(Display *display); 1036 1037 protected: 1038 void org_kde_plasma_activation_feedback_destroy(Resource *resource) override; 1039 }; 1040 1041 class PlasmaWindowActivationInterfacePrivate : public QtWaylandServer::org_kde_plasma_activation 1042 { 1043 public: 1044 explicit PlasmaWindowActivationInterfacePrivate(PlasmaWindowActivationInterface *q) 1045 : QtWaylandServer::org_kde_plasma_activation() 1046 , q(q) 1047 { 1048 } 1049 1050 PlasmaWindowActivationInterface *const q; 1051 }; 1052 1053 PlasmaWindowActivationFeedbackInterfacePrivate::PlasmaWindowActivationFeedbackInterfacePrivate(Display *display) 1054 : QtWaylandServer::org_kde_plasma_activation_feedback(*display, s_activationVersion) 1055 { 1056 } 1057 1058 void PlasmaWindowActivationFeedbackInterfacePrivate::org_kde_plasma_activation_feedback_destroy(Resource *resource) 1059 { 1060 wl_resource_destroy(resource->handle); 1061 } 1062 1063 PlasmaWindowActivationFeedbackInterface::PlasmaWindowActivationFeedbackInterface(Display *display, QObject *parent) 1064 : QObject(parent) 1065 , d(new PlasmaWindowActivationFeedbackInterfacePrivate(display)) 1066 { 1067 } 1068 1069 PlasmaWindowActivationFeedbackInterface::~PlasmaWindowActivationFeedbackInterface() 1070 { 1071 } 1072 1073 std::unique_ptr<PlasmaWindowActivationInterface> PlasmaWindowActivationFeedbackInterface::createActivation(const QString &appid) 1074 { 1075 std::unique_ptr<PlasmaWindowActivationInterface> activation(new PlasmaWindowActivationInterface()); 1076 const auto resources = d->resourceMap(); 1077 for (auto resource : resources) { 1078 auto activationResource = activation->d->add(resource->client(), resource->version()); 1079 d->send_activation(resource->handle, activationResource->handle); 1080 } 1081 activation->sendAppId(appid); 1082 return activation; 1083 } 1084 1085 PlasmaWindowActivationInterface::PlasmaWindowActivationInterface() 1086 : d(new PlasmaWindowActivationInterfacePrivate(this)) 1087 { 1088 } 1089 1090 PlasmaWindowActivationInterface::~PlasmaWindowActivationInterface() 1091 { 1092 const auto clientResources = d->resourceMap(); 1093 for (auto resource : clientResources) { 1094 d->send_finished(resource->handle); 1095 } 1096 } 1097 1098 void PlasmaWindowActivationInterface::sendAppId(const QString &appid) 1099 { 1100 const auto clientResources = d->resourceMap(); 1101 for (auto resource : clientResources) { 1102 d->send_app_id(resource->handle, appid); 1103 } 1104 } 1105 1106 } 1107 1108 #include "moc_plasmawindowmanagement.cpp"