From d52485ffb7931aef787a3dc4b4b00378451cedc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 6 Jun 2016 15:06:33 +0200 Subject: [PATCH] Add a parent_window event to Plasma Window interface Summary: This change adds a parent_window event to Plasma Window. From server side it's possible to specify that a window is a transient for another window - that is it has a parent window. On client side this is exposed respectively with a new change signal. Reviewers: #plasma_on_wayland, hein Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D1779 --- .../client/test_wayland_windowmanagement.cpp | 39 ++++++++++++++ .../plasmawindowmanagement_interface.cpp | 53 ++++++++++++++++++- .../plasmawindowmanagement_interface.h | 8 +++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/wayland/autotests/client/test_wayland_windowmanagement.cpp b/src/wayland/autotests/client/test_wayland_windowmanagement.cpp index 8678934e97..7d51dffb45 100644 --- a/src/wayland/autotests/client/test_wayland_windowmanagement.cpp +++ b/src/wayland/autotests/client/test_wayland_windowmanagement.cpp @@ -64,6 +64,7 @@ private Q_SLOTS: void testShowingDesktop(); void testRequestShowingDesktop_data(); void testRequestShowingDesktop(); + void testParentWindow(); void cleanup(); @@ -470,5 +471,43 @@ void TestWindowManagement::testRequestShowingDesktop() QTEST(requestSpy.first().first().value(), "expectedValue"); } +void TestWindowManagement::testParentWindow() +{ + using namespace KWayland::Client; + // this test verifies the functionality of ParentWindows + QCOMPARE(m_windowManagement->windows().count(), 1); + auto parentWindow = m_windowManagement->windows().first(); + QVERIFY(parentWindow); + QVERIFY(parentWindow->parentWindow().isNull()); + + // now let's create a second window + QSignalSpy windowAddedSpy(m_windowManagement, &PlasmaWindowManagement::windowCreated); + QVERIFY(windowAddedSpy.isValid()); + auto serverTransient = m_windowManagementInterface->createWindow(this); + serverTransient->setParentWindow(m_windowInterface); + QVERIFY(windowAddedSpy.wait()); + auto transient = windowAddedSpy.first().first().value(); + QCOMPARE(transient->parentWindow().data(), parentWindow); + + // let's unset the parent + QSignalSpy parentWindowChangedSpy(transient, &PlasmaWindow::parentWindowChanged); + QVERIFY(parentWindowChangedSpy.isValid()); + serverTransient->setParentWindow(nullptr); + QVERIFY(parentWindowChangedSpy.wait()); + QVERIFY(transient->parentWindow().isNull()); + + // and set it again + serverTransient->setParentWindow(m_windowInterface); + QVERIFY(parentWindowChangedSpy.wait()); + QCOMPARE(transient->parentWindow().data(), parentWindow); + + // now let's try to unmap the parent + m_windowInterface->unmap(); + m_window = nullptr; + m_windowInterface = nullptr; + QVERIFY(parentWindowChangedSpy.wait()); + QVERIFY(transient->parentWindow().isNull()); +} + QTEST_GUILESS_MAIN(TestWindowManagement) #include "test_wayland_windowmanagement.moc" diff --git a/src/wayland/plasmawindowmanagement_interface.cpp b/src/wayland/plasmawindowmanagement_interface.cpp index 8f46e10f80..b340b97be2 100644 --- a/src/wayland/plasmawindowmanagement_interface.cpp +++ b/src/wayland/plasmawindowmanagement_interface.cpp @@ -73,6 +73,8 @@ public: void setVirtualDesktop(quint32 desktop); void unmap(); void setState(org_kde_plasma_window_management_state flag, bool set); + void setParentWindow(PlasmaWindowInterface *parent); + wl_resource *resourceForParent(PlasmaWindowInterface *parent, wl_resource *child) const; QVector resources; quint32 windowId = 0; @@ -80,6 +82,8 @@ public: PlasmaWindowManagementInterface *wm; bool unmapped = false; + PlasmaWindowInterface *parentWindow = nullptr; + QMetaObject::Connection parentWindowDestroyConnection; private: static void unbind(wl_resource *resource); @@ -105,7 +109,7 @@ private: static const struct org_kde_plasma_window_interface s_interface; }; -const quint32 PlasmaWindowManagementInterface::Private::s_version = 4; +const quint32 PlasmaWindowManagementInterface::Private::s_version = 5; PlasmaWindowManagementInterface::Private::Private(PlasmaWindowManagementInterface *q, Display *d) : Global::Private(d, &org_kde_plasma_window_management_interface, s_version) @@ -321,6 +325,8 @@ void PlasmaWindowInterface::Private::createResource(wl_resource *parent, uint32_ org_kde_plasma_window_send_state_changed(resource, m_state); org_kde_plasma_window_send_themed_icon_name_changed(resource, m_themedIconName.toUtf8().constData()); + org_kde_plasma_window_send_parent_window(resource, resourceForParent(parentWindow, resource)); + if (unmapped) { org_kde_plasma_window_send_unmapped(resource); } @@ -406,6 +412,46 @@ void PlasmaWindowInterface::Private::setState(org_kde_plasma_window_management_s } } +wl_resource *PlasmaWindowInterface::Private::resourceForParent(PlasmaWindowInterface *parent, wl_resource *child) const +{ + if (!parent) { + return nullptr; + } + auto it = std::find_if(parent->d->resources.begin(), parent->d->resources.end(), + [child] (wl_resource *parentResource) { + return wl_resource_get_client(child) == wl_resource_get_client(parentResource); + } + ); + if (it != parent->d->resources.end()) { + return *it; + } + return nullptr; +} + +void PlasmaWindowInterface::Private::setParentWindow(PlasmaWindowInterface *window) +{ + if (parentWindow == window) { + return; + } + QObject::disconnect(parentWindowDestroyConnection); + parentWindowDestroyConnection = QMetaObject::Connection(); + parentWindow = window; + if (parentWindow) { + parentWindowDestroyConnection = QObject::connect(window, &QObject::destroyed, q, + [this] { + parentWindow = nullptr; + parentWindowDestroyConnection = QMetaObject::Connection(); + for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) { + org_kde_plasma_window_send_parent_window(*it, nullptr); + } + } + ); + } + for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) { + org_kde_plasma_window_send_parent_window(*it, resourceForParent(window, *it)); + } +} + void PlasmaWindowInterface::Private::closeCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) @@ -658,5 +704,10 @@ void PlasmaWindowInterface::setVirtualDesktopChangeable(bool set) d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE, set); } +void PlasmaWindowInterface::setParentWindow(PlasmaWindowInterface *parentWindow) +{ + d->setParentWindow(parentWindow); +} + } } diff --git a/src/wayland/plasmawindowmanagement_interface.h b/src/wayland/plasmawindowmanagement_interface.h index ef561138b3..76f9950f65 100644 --- a/src/wayland/plasmawindowmanagement_interface.h +++ b/src/wayland/plasmawindowmanagement_interface.h @@ -139,6 +139,14 @@ public: */ QHash minimizedGeometries() const; + /** + * Sets this PlasmaWindowInterface as a transient window to @p parentWindow. + * If @p parentWindow is @c nullptr, the PlasmaWindowInterface is a toplevel + * window and does not have a parent window. + * @since 5.24 + **/ + void setParentWindow(PlasmaWindowInterface *parentWindow); + Q_SIGNALS: void closeRequested(); /**