diff --git a/autotests/client/test_plasma_window_model.cpp b/autotests/client/test_plasma_window_model.cpp --- a/autotests/client/test_plasma_window_model.cpp +++ b/autotests/client/test_plasma_window_model.cpp @@ -187,9 +187,6 @@ m_display->dispatchEvents(); QSignalSpy dataChangedSpy(model, &PlasmaWindowModel::dataChanged); VERIFY(dataChangedSpy.isValid()); - // just creating sends one changed, this could be improved in the protocol - VERIFY(dataChangedSpy.wait()); - dataChangedSpy.clear(); const QModelIndex index = model->index(0); COMPARE(model->data(index, role).toBool(), false); @@ -454,9 +451,6 @@ m_display->dispatchEvents(); QSignalSpy dataChangedSpy(model, &PlasmaWindowModel::dataChanged); QVERIFY(dataChangedSpy.isValid()); - // just creating sends one changed, this could be improved in the protocol - QVERIFY(dataChangedSpy.wait()); - dataChangedSpy.clear(); const QModelIndex index = model->index(0); QCOMPARE(model->data(index, Qt::DisplayRole).toString(), QString()); @@ -482,9 +476,6 @@ m_display->dispatchEvents(); QSignalSpy dataChangedSpy(model, &PlasmaWindowModel::dataChanged); QVERIFY(dataChangedSpy.isValid()); - // just creating sends one changed, this could be improved in the protocol - QVERIFY(dataChangedSpy.wait()); - dataChangedSpy.clear(); const QModelIndex index = model->index(0); QCOMPARE(model->data(index, PlasmaWindowModel::AppId).toString(), QString()); @@ -510,9 +501,6 @@ m_display->dispatchEvents(); QSignalSpy dataChangedSpy(model, &PlasmaWindowModel::dataChanged); QVERIFY(dataChangedSpy.isValid()); - // just creating sends one changed, this could be improved in the protocol - QVERIFY(dataChangedSpy.wait()); - dataChangedSpy.clear(); const QModelIndex index = model->index(0); QCOMPARE(model->data(index, PlasmaWindowModel::VirtualDesktop).toInt(), 0); diff --git a/autotests/client/test_wayland_windowmanagement.cpp b/autotests/client/test_wayland_windowmanagement.cpp --- a/autotests/client/test_wayland_windowmanagement.cpp +++ b/autotests/client/test_wayland_windowmanagement.cpp @@ -313,23 +313,24 @@ void TestWindowManagement::testCreateAfterUnmap() { // this test verifies that we don't get a protocol error on client side when creating an already unmapped window. - QSignalSpy windowSpy(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::windowCreated); - QVERIFY(windowSpy.isValid()); + QCOMPARE(m_windowManagement->children().count(), 1); // create and unmap in one go // client will first handle the create, the unmap will be sent once the server side is bound auto serverWindow = m_windowManagementInterface->createWindow(this); serverWindow->unmap(); QCOMPARE(m_windowManagementInterface->children().count(), 0); - QVERIFY(windowSpy.wait()); - QCOMPARE(windowSpy.count(), 1); - auto window = windowSpy.first().first().value(); + QCoreApplication::instance()->processEvents(); + QCoreApplication::instance()->processEvents(QEventLoop::WaitForMoreEvents); + QTRY_COMPARE(m_windowManagement->children().count(), 2); + auto window = dynamic_cast(m_windowManagement->children().last()); QVERIFY(window); // now this is not yet on the server, on the server it will be after next roundtrip // which we can trigger by waiting for destroy of the newly created window. // why destroy? Because we will get the unmap which triggers a destroy QSignalSpy clientDestroyedSpy(window, &QObject::destroyed); QVERIFY(clientDestroyedSpy.isValid()); QVERIFY(clientDestroyedSpy.wait()); + QCOMPARE(m_windowManagement->children().count(), 1); // the server side created a helper PlasmaWindowInterface with PlasmaWindowManagementInterface as parent // it emitted unmapped so we can be sure it will be destroyed directly QCOMPARE(m_windowManagementInterface->children().count(), 1); diff --git a/src/client/plasmawindowmanagement.cpp b/src/client/plasmawindowmanagement.cpp --- a/src/client/plasmawindowmanagement.cpp +++ b/src/client/plasmawindowmanagement.cpp @@ -55,6 +55,73 @@ PlasmaWindowManagement *q; }; +class PlasmaWindow::Private +{ +public: + Private(org_kde_plasma_window *window, quint32 internalId, PlasmaWindow *q); + WaylandPointer window; + quint32 internalId; + QString title; + QString appId; + quint32 desktop = 0; + bool active = false; + bool minimized = false; + bool maximized = false; + bool fullscreen = false; + bool keepAbove = false; + bool keepBelow = false; + bool onAllDesktops = false; + bool demandsAttention = false; + bool closeable = false; + bool minimizeable = false; + bool maximizeable = false; + bool fullscreenable = false; + bool skipTaskbar = false; + bool shadeable = false; + bool shaded = false; + bool movable = false; + bool resizable = false; + bool virtualDesktopChangeable = false; + QIcon icon; + PlasmaWindowManagement *wm = nullptr; + bool unmapped = false; + +private: + static void titleChangedCallback(void *data, org_kde_plasma_window *window, const char *title); + static void appIdChangedCallback(void *data, org_kde_plasma_window *window, const char *app_id); + static void stateChangedCallback(void *data, org_kde_plasma_window *window, uint32_t state); + static void virtualDesktopChangedCallback(void *data, org_kde_plasma_window *window, int32_t number); + static void themedIconNameChangedCallback(void *data, org_kde_plasma_window *window, const char *name); + static void unmappedCallback(void *data, org_kde_plasma_window *window); + static void initialStateCallback(void *data, org_kde_plasma_window *window); + void setActive(bool set); + void setMinimized(bool set); + void setMaximized(bool set); + void setFullscreen(bool set); + void setKeepAbove(bool set); + void setKeepBelow(bool set); + void setOnAllDesktops(bool set); + void setDemandsAttention(bool set); + void setCloseable(bool set); + void setMinimizeable(bool set); + void setMaximizeable(bool set); + void setFullscreenable(bool set); + void setSkipTaskbar(bool skip); + void setShadeable(bool set); + void setShaded(bool set); + void setMovable(bool set); + void setResizable(bool set); + void setVirtualDesktopChangeable(bool set); + + static Private *cast(void *data) { + return reinterpret_cast(data); + } + + PlasmaWindow *q; + + static struct org_kde_plasma_window_listener s_listener; +}; + PlasmaWindowManagement::Private::Private(PlasmaWindowManagement *q) : q(q) { @@ -121,6 +188,7 @@ queue->addProxy(id); } PlasmaWindow *window = new PlasmaWindow(q, id, internalId); + window->d->wm = q; windows << window; QObject::connect(window, &QObject::destroyed, q, [this, window] { @@ -155,7 +223,9 @@ } } ); - emit q->windowCreated(window); + if (org_kde_plasma_window_get_version(id) < 4) { + emit q->windowCreated(window); + } } PlasmaWindowManagement::PlasmaWindowManagement(QObject *parent) @@ -252,80 +322,25 @@ return new PlasmaWindowModel(this); } - -class PlasmaWindow::Private -{ -public: - Private(org_kde_plasma_window *window, quint32 internalId, PlasmaWindow *q); - WaylandPointer window; - quint32 internalId; - QString title; - QString appId; - quint32 desktop = 0; - bool active = false; - bool minimized = false; - bool maximized = false; - bool fullscreen = false; - bool keepAbove = false; - bool keepBelow = false; - bool onAllDesktops = false; - bool demandsAttention = false; - bool closeable = false; - bool minimizeable = false; - bool maximizeable = false; - bool fullscreenable = false; - bool skipTaskbar = false; - bool shadeable = false; - bool shaded = false; - bool movable = false; - bool resizable = false; - bool virtualDesktopChangeable = false; - QIcon icon; - -private: - static void titleChangedCallback(void *data, org_kde_plasma_window *window, const char *title); - static void appIdChangedCallback(void *data, org_kde_plasma_window *window, const char *app_id); - static void stateChangedCallback(void *data, org_kde_plasma_window *window, uint32_t state); - static void virtualDesktopChangedCallback(void *data, org_kde_plasma_window *window, int32_t number); - static void themedIconNameChangedCallback(void *data, org_kde_plasma_window *window, const char *name); - static void unmappedCallback(void *data, org_kde_plasma_window *window); - void setActive(bool set); - void setMinimized(bool set); - void setMaximized(bool set); - void setFullscreen(bool set); - void setKeepAbove(bool set); - void setKeepBelow(bool set); - void setOnAllDesktops(bool set); - void setDemandsAttention(bool set); - void setCloseable(bool set); - void setMinimizeable(bool set); - void setMaximizeable(bool set); - void setFullscreenable(bool set); - void setSkipTaskbar(bool skip); - void setShadeable(bool set); - void setShaded(bool set); - void setMovable(bool set); - void setResizable(bool set); - void setVirtualDesktopChangeable(bool set); - - static Private *cast(void *data) { - return reinterpret_cast(data); - } - - PlasmaWindow *q; - - static struct org_kde_plasma_window_listener s_listener; -}; - org_kde_plasma_window_listener PlasmaWindow::Private::s_listener = { titleChangedCallback, appIdChangedCallback, stateChangedCallback, virtualDesktopChangedCallback, themedIconNameChangedCallback, - unmappedCallback + unmappedCallback, + initialStateCallback }; +void PlasmaWindow::Private::initialStateCallback(void *data, org_kde_plasma_window *window) +{ + Q_UNUSED(window) + Private *p = cast(data); + if (!p->unmapped) { + emit p->wm->windowCreated(p->q); + } +} + void PlasmaWindow::Private::titleChangedCallback(void *data, org_kde_plasma_window *window, const char *title) { Q_UNUSED(window) @@ -365,6 +380,7 @@ { auto p = cast(data); Q_UNUSED(window); + p->unmapped = true; emit p->q->unmapped(); p->q->deleteLater(); } @@ -397,8 +413,13 @@ { auto p = cast(data); Q_UNUSED(window); - QIcon icon = QIcon::fromTheme(QString::fromUtf8(name)); - p->icon = icon; + const QString themedName = QString::fromUtf8(name); + if (!themedName.isEmpty()) { + QIcon icon = QIcon::fromTheme(themedName); + p->icon = icon; + } else { + p->icon = QIcon(); + } emit p->q->iconChanged(); } diff --git a/src/client/protocols/plasma-window-management.xml b/src/client/protocols/plasma-window-management.xml --- a/src/client/protocols/plasma-window-management.xml +++ b/src/client/protocols/plasma-window-management.xml @@ -211,5 +211,13 @@ and its surface is unmapped. + + + + This event will be sent immediately after all initial state been sent to the client. + If the Plasma window is already unmapped, the unmapped event will be sent before the + initial_state event. + + diff --git a/src/server/plasmawindowmanagement_interface.cpp b/src/server/plasmawindowmanagement_interface.cpp --- a/src/server/plasmawindowmanagement_interface.cpp +++ b/src/server/plasmawindowmanagement_interface.cpp @@ -171,8 +171,8 @@ if (it == p->windows.constEnd()) { // create a temp window just for the resource and directly send an unmapped PlasmaWindowInterface *window = new PlasmaWindowInterface(p->q, p->q); + window->d->unmapped = true; window->d->createResource(resource, id); - window->unmap(); return; } (*it)->d->createResource(resource, id); @@ -320,6 +320,14 @@ } org_kde_plasma_window_send_state_changed(resource, m_state); org_kde_plasma_window_send_themed_icon_name_changed(resource, m_themedIconName.toUtf8().constData()); + + if (unmapped) { + org_kde_plasma_window_send_unmapped(resource); + } + + if (wl_resource_get_version(resource) >= ORG_KDE_PLASMA_WINDOW_INITIAL_STATE_SINCE_VERSION) { + org_kde_plasma_window_send_initial_state(resource); + } c->flush(); }