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