From a63fe2f0fb1a28520e8e84e6da5e149d17204ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 29 Jun 2015 10:04:51 +0200 Subject: [PATCH] Better handle the creation of PlasmaWindow in PlasmaWindowManagementInterface Sending a new PlasmaWindow as an event is quite problematic. The main problem here is that it sends an id of 0 and this doesn't make sense when the interface gets bound and all existing windows are send to the client. This changes the interaction to have the client create the resource for the PlasmaWindow instead of the server creating it. The server generates "window ids" and sends those to the client. The client now binds a PlasmaWindow with the "window id" in the normal way. In case the server doesn't know the id any more, it directly sends an unmapped and destroyes the newly created resource again. It is not a protocol error as that can happen (common example: file open dialog of Qt 5 applications on Xwayland). --- .../plasmawindowmanagement_interface.cpp | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/wayland/plasmawindowmanagement_interface.cpp b/src/wayland/plasmawindowmanagement_interface.cpp index ec7012986f..6e3b6dbf46 100644 --- a/src/wayland/plasmawindowmanagement_interface.cpp +++ b/src/wayland/plasmawindowmanagement_interface.cpp @@ -44,10 +44,12 @@ public: ShowingDesktopState state = ShowingDesktopState::Disabled; QVector resources; QList windows; + quint32 windowIdCounter = 0; private: static void unbind(wl_resource *resource); static void showDesktopCallback(wl_client *client, wl_resource *resource, uint32_t state); + static void getWindowCallback(wl_client *client, wl_resource *resource, uint32_t id, uint32_t internalWindowId); void bind(wl_client *client, uint32_t version, uint32_t id) override; void sendShowingDesktopState(wl_resource *r); @@ -62,7 +64,7 @@ public: Private(PlasmaWindowManagementInterface *wm, PlasmaWindowInterface *q); ~Private(); - void createResource(wl_resource *parent); + void createResource(wl_resource *parent, uint32_t id); void setTitle(const QString &title); void setAppId(const QString &appId); void setThemedIconName(const QString &iconName); @@ -75,6 +77,7 @@ public: wl_listener *destroyListener; }; QList resources; + quint32 windowId = 0; private: static void unbind(wl_resource *resource); @@ -104,7 +107,8 @@ PlasmaWindowManagementInterface::Private::Private(PlasmaWindowManagementInterfac } const struct org_kde_plasma_window_management_interface PlasmaWindowManagementInterface::Private::s_interface = { - showDesktopCallback + showDesktopCallback, + getWindowCallback }; void PlasmaWindowManagementInterface::Private::sendShowingDesktopState() @@ -147,6 +151,27 @@ void PlasmaWindowManagementInterface::Private::showDesktopCallback(wl_client *cl emit reinterpret_cast(wl_resource_get_user_data(resource))->q->requestChangeShowingDesktop(s); } +void PlasmaWindowManagementInterface::Private::getWindowCallback(wl_client *client, wl_resource *resource, uint32_t id, uint32_t internalWindowId) +{ + auto p = reinterpret_cast(wl_resource_get_user_data(resource)); + auto it = std::find_if(p->windows.constBegin(), p->windows.constEnd(), + [internalWindowId] (PlasmaWindowInterface *window) { + return window->d->windowId == internalWindowId; + } + ); + if (it == p->windows.constEnd()) { + ClientConnection *c = p->q->display()->getConnection(client); + wl_resource *r = c->createResource(&org_kde_plasma_window_interface, wl_resource_get_version(resource), id); + if (!r) { + return; + } + org_kde_plasma_window_send_unmapped(r); + wl_resource_destroy(r); + return; + } + (*it)->d->createResource(resource, id); +} + PlasmaWindowManagementInterface::PlasmaWindowManagementInterface(Display *display, QObject *parent) : Global(new Private(this, display), parent) { @@ -165,7 +190,7 @@ void PlasmaWindowManagementInterface::Private::bind(wl_client *client, uint32_t wl_resource_set_implementation(shell, &s_interface, this, unbind); resources << shell; for (auto it = windows.constBegin(); it != windows.constEnd(); ++it) { - (*it)->d->createResource(shell); + org_kde_plasma_window_management_send_window(shell, (*it)->d->windowId); } } @@ -194,8 +219,10 @@ PlasmaWindowInterface *PlasmaWindowManagementInterface::createWindow(QObject *pa { Q_D(); PlasmaWindowInterface *window = new PlasmaWindowInterface(this, parent); + // TODO: improve window ids so that it cannot wrap around + window->d->windowId = ++d->windowIdCounter; for (auto it = d->resources.constBegin(); it != d->resources.constEnd(); ++it) { - window->d->createResource(*it); + org_kde_plasma_window_management_send_window(*it, window->d->windowId); } d->windows << window; connect(window, &QObject::destroyed, this, @@ -242,9 +269,6 @@ void PlasmaWindowInterface::Private::unbind(wl_resource *resource) it++; } } - if (p->resources.isEmpty()) { - p->q->deleteLater(); - } } void PlasmaWindowInterface::Private::destroyListenerCallback(wl_listener *listener, void *data) @@ -253,10 +277,10 @@ void PlasmaWindowInterface::Private::destroyListenerCallback(wl_listener *listen Private::unbind(reinterpret_cast(data)); } -void PlasmaWindowInterface::Private::createResource(wl_resource *parent) +void PlasmaWindowInterface::Private::createResource(wl_resource *parent, uint32_t id) { ClientConnection *c = wm->display()->getConnection(wl_resource_get_client(parent)); - wl_resource *resource = c->createResource(&org_kde_plasma_window_interface, wl_resource_get_version(parent), 0); + wl_resource *resource = c->createResource(&org_kde_plasma_window_interface, wl_resource_get_version(parent), id); if (!resource) { return; } @@ -270,7 +294,6 @@ void PlasmaWindowInterface::Private::createResource(wl_resource *parent) wl_resource_add_destroy_listener(resource, r.destroyListener); resources << r; - org_kde_plasma_window_management_send_window_created(parent, resource); org_kde_plasma_window_send_virtual_desktop_changed(resource, m_virtualDesktop); if (!m_appId.isEmpty()) { org_kde_plasma_window_send_app_id_changed(resource, m_appId.toUtf8().constData());