diff --git a/autotests/client/CMakeLists.txt b/autotests/client/CMakeLists.txt --- a/autotests/client/CMakeLists.txt +++ b/autotests/client/CMakeLists.txt @@ -349,6 +349,17 @@ ecm_mark_as_test(testXdgShellV5) ######################################################## +# Test XdgForeign +######################################################## +set( testXdgForeign_SRCS + test_xdg_foreign.cpp + ) +add_executable(testXdgForeign ${testXdgForeign_SRCS}) +target_link_libraries( testXdgForeign Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client) +add_test(NAME kwayland-testXdgForeign COMMAND testXdgForeign) +ecm_mark_as_test(testXdgForeign) + +######################################################## # Test Pointer Constraints ######################################################## add_executable(testPointerConstraints test_pointer_constraints.cpp) diff --git a/autotests/client/test_xdg_foreign.cpp b/autotests/client/test_xdg_foreign.cpp new file mode 100644 --- /dev/null +++ b/autotests/client/test_xdg_foreign.cpp @@ -0,0 +1,401 @@ +/******************************************************************** +Copyright 2014 Martin Gräßlin +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +// Qt +#include +// KWin +#include "../../src/client/compositor.h" +#include "../../src/client/connection_thread.h" +#include "../../src/client/event_queue.h" +#include "../../src/client/region.h" +#include "../../src/client/registry.h" +#include "../../src/client/surface.h" +#include "../../src/client/xdgforeign.h" +#include "../../src/server/display.h" +#include "../../src/server/compositor_interface.h" +#include "../../src/server/surface_interface.h" +#include "../../src/server/xdgforeign_interface.h" + +using namespace KWayland::Client; + +class TestForeign : public QObject +{ + Q_OBJECT +public: + explicit TestForeign(QObject *parent = nullptr); +private Q_SLOTS: + void init(); + void cleanup(); + + void testExport(); + void testDeleteImported(); + void testDeleteChildSurface(); + void testDeleteParentSurface(); + void testDeleteExported(); + void testExportTwoTimes(); + void testImportTwoTimes(); + +private: + void doExport(); + + KWayland::Server::Display *m_display; + KWayland::Server::CompositorInterface *m_compositorInterface; + KWayland::Server::XdgForeignUnstableInterface *m_foreignInterface; + KWayland::Client::ConnectionThread *m_connection; + KWayland::Client::Compositor *m_compositor; + KWayland::Client::EventQueue *m_queue; + KWayland::Client::XdgExporterUnstable *m_exporter; + KWayland::Client::XdgImporterUnstable *m_importer; + + QPointer m_exportedSurface; + QPointer m_exportedSurfaceInterface; + + QPointer m_exported; + QPointer m_imported; + + QPointer m_childSurface; + QPointer m_childSurfaceInterface; + + QThread *m_thread; +}; + +static const QString s_socketName = QStringLiteral("kwayland-test-xdg-foreign-0"); + +TestForeign::TestForeign(QObject *parent) + : QObject(parent) + , m_display(nullptr) + , m_compositorInterface(nullptr) + , m_connection(nullptr) + , m_compositor(nullptr) + , m_queue(nullptr) + , m_exporter(nullptr) + , m_importer(nullptr) + , m_thread(nullptr) +{ +} + +void TestForeign::init() +{ + using namespace KWayland::Server; + delete m_display; + m_display = new Display(this); + m_display->setSocketName(s_socketName); + m_display->start(); + QVERIFY(m_display->isRunning()); + + qRegisterMetaType("KWayland::Server::SurfaceInterface"); + + // setup connection + m_connection = new KWayland::Client::ConnectionThread; + QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected); + QVERIFY(connectedSpy.isValid()); + m_connection->setSocketName(s_socketName); + + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait()); + + m_queue = new KWayland::Client::EventQueue(this); + QVERIFY(!m_queue->isValid()); + m_queue->setup(m_connection); + QVERIFY(m_queue->isValid()); + + Registry registry; + QSignalSpy compositorSpy(®istry, &Registry::compositorAnnounced); + QVERIFY(compositorSpy.isValid()); + + QSignalSpy exporterSpy(®istry, &Registry::exporterUnstableV1Announced); + QVERIFY(exporterSpy.isValid()); + + QSignalSpy importerSpy(®istry, &Registry::importerUnstableV1Announced); + QVERIFY(importerSpy.isValid()); + + QVERIFY(!registry.eventQueue()); + registry.setEventQueue(m_queue); + QCOMPARE(registry.eventQueue(), m_queue); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + registry.setup(); + + m_compositorInterface = m_display->createCompositor(m_display); + m_compositorInterface->create(); + QVERIFY(m_compositorInterface->isValid()); + + QVERIFY(compositorSpy.wait()); + m_compositor = registry.createCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value(), this); + + m_foreignInterface = m_display->createXdgForeignUnstableInterface(m_display); + m_foreignInterface->create(); + QVERIFY(m_foreignInterface->isValid()); + + QVERIFY(exporterSpy.wait()); + //Both importer and exporter should have been triggered by now + QCOMPARE(exporterSpy.count(), 1); + QCOMPARE(importerSpy.count(), 1); + + m_exporter = registry.createXdgExporterUnstable(exporterSpy.first().first().value(), exporterSpy.first().last().value(), this); + m_importer = registry.createXdgImporterUnstable(importerSpy.first().first().value(), importerSpy.first().last().value(), this); +} + +void TestForeign::cleanup() +{ +#define CLEANUP(variable) \ + if (variable) { \ + delete variable; \ + variable = nullptr; \ + } + + //some tests delete it beforehand + if (m_exportedSurfaceInterface) { + QSignalSpy exportedSurfaceDestroyedSpy(m_exportedSurfaceInterface.data(), &QObject::destroyed); + QVERIFY(exportedSurfaceDestroyedSpy.isValid()); + CLEANUP(m_exportedSurface) + exportedSurfaceDestroyedSpy.wait(); + } + + if (m_childSurfaceInterface) { + QSignalSpy childSurfaceDestroyedSpy(m_childSurfaceInterface.data(), &QObject::destroyed); + QVERIFY(childSurfaceDestroyedSpy.isValid()); + CLEANUP(m_childSurface) + childSurfaceDestroyedSpy.wait(); + } + + + CLEANUP(m_compositor) + CLEANUP(m_exporter) + CLEANUP(m_importer) + CLEANUP(m_queue) + if (m_connection) { + m_connection->deleteLater(); + m_connection = nullptr; + } + if (m_thread) { + m_thread->quit(); + m_thread->wait(); + delete m_thread; + m_thread = nullptr; + } + CLEANUP(m_compositorInterface) + CLEANUP(m_foreignInterface) + CLEANUP(m_display) +#undef CLEANUP +} + +void TestForeign::doExport() +{ + QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); + QVERIFY(serverSurfaceCreated.isValid()); + + m_exportedSurface = m_compositor->createSurface(); + QVERIFY(serverSurfaceCreated.wait()); + + m_exportedSurfaceInterface = serverSurfaceCreated.first().first().value(); + + //Export a window + m_exported = m_exporter->exportSurface(m_exportedSurface, this); + QVERIFY(m_exported->handle().isEmpty()); + QSignalSpy doneSpy(m_exported.data(), &XdgExportedUnstable::done); + QVERIFY(doneSpy.wait()); + QVERIFY(!m_exported->handle().isEmpty()); + + QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignUnstableInterface::transientChanged); + QVERIFY(transientSpy.isValid()); + + //Import the just exported window + m_imported = m_importer->import(m_exported->handle(), this); + QVERIFY(m_imported->isValid()); + + QSignalSpy childSurfaceInterfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); + QVERIFY(serverSurfaceCreated.isValid()); + m_childSurface = m_compositor->createSurface(); + QVERIFY(childSurfaceInterfaceCreated.wait()); + m_childSurfaceInterface = childSurfaceInterfaceCreated.first().first().value(); + m_childSurface->commit(Surface::CommitFlag::None); + + m_imported->setParentOf(m_childSurface); + QVERIFY(transientSpy.wait()); + + QCOMPARE(transientSpy.first().first().value(), m_childSurfaceInterface.data()); + QCOMPARE(transientSpy.first().at(1).value(), m_exportedSurfaceInterface.data()); + + //transientFor api + QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), m_exportedSurfaceInterface.data()); +} + +void TestForeign::testExport() +{ + doExport(); +} + +void TestForeign::testDeleteImported() +{ + doExport(); + + QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignUnstableInterface::transientChanged); + + QVERIFY(transientSpy.isValid()); + m_imported->deleteLater(); + m_imported = nullptr; + + QVERIFY(transientSpy.wait()); + + QCOMPARE(transientSpy.first().first().value(), m_childSurfaceInterface.data()); + QCOMPARE(transientSpy.first().at(1).value(), nullptr); + QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), nullptr); +} + +void TestForeign::testDeleteChildSurface() +{ + doExport(); + + QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignUnstableInterface::transientChanged); + + QVERIFY(transientSpy.isValid()); + m_childSurface->deleteLater(); + + QVERIFY(transientSpy.wait()); + + //when the client surface dies, the server one will eventually die too + QSignalSpy surfaceDestroyedSpy(m_childSurfaceInterface, SIGNAL(destroyed())); + QVERIFY(surfaceDestroyedSpy.wait()); + + QCOMPARE(transientSpy.first().at(0).value(), nullptr); + QCOMPARE(transientSpy.first().at(1).value(), m_exportedSurfaceInterface.data()); +} + +void TestForeign::testDeleteParentSurface() +{ + doExport(); + + QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignUnstableInterface::transientChanged); + + QVERIFY(transientSpy.isValid()); + m_exportedSurface->deleteLater(); + + QSignalSpy exportedSurfaceDestroyedSpy(m_exportedSurfaceInterface.data(), &QObject::destroyed); + QVERIFY(exportedSurfaceDestroyedSpy.isValid()); + exportedSurfaceDestroyedSpy.wait(); + + QVERIFY(transientSpy.wait()); + + QCOMPARE(transientSpy.first().first().value(), m_childSurfaceInterface.data()); + QCOMPARE(transientSpy.first().at(1).value(), nullptr); + QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), nullptr); +} + +void TestForeign::testDeleteExported() +{ + doExport(); + + QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignUnstableInterface::transientChanged); + QSignalSpy destroyedSpy(m_imported.data(), &KWayland::Client::XdgImportedUnstable::importedDestroyed); + + QVERIFY(transientSpy.isValid()); + m_exported->deleteLater(); + m_exported = nullptr; + + QVERIFY(transientSpy.wait()); + QVERIFY(destroyedSpy.wait()); + + QCOMPARE(transientSpy.first().first().value(), m_childSurfaceInterface.data()); + QCOMPARE(transientSpy.first().at(1).value(), nullptr); + QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), nullptr); + + QVERIFY(!m_imported->isValid()); +} + +void TestForeign::testExportTwoTimes() +{ + doExport(); + + //Export second window + KWayland::Client::XdgExportedUnstable *exported2 = m_exporter->exportSurface(m_exportedSurface, this); + QVERIFY(exported2->handle().isEmpty()); + QSignalSpy doneSpy(exported2, &XdgExportedUnstable::done); + QVERIFY(doneSpy.wait()); + QVERIFY(!exported2->handle().isEmpty()); + + QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignUnstableInterface::transientChanged); + QVERIFY(transientSpy.isValid()); + + //Import the just exported window + KWayland::Client::XdgImportedUnstable *imported2 = m_importer->import(exported2->handle(), this); + QVERIFY(imported2->isValid()); + + //create a second child surface + QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); + QVERIFY(serverSurfaceCreated.isValid()); + + KWayland::Client::Surface *childSurface2 = m_compositor->createSurface(); + QVERIFY(serverSurfaceCreated.wait()); + + KWayland::Server::SurfaceInterface *childSurface2Interface = serverSurfaceCreated.first().first().value(); + + imported2->setParentOf(childSurface2); + QVERIFY(transientSpy.wait()); + + QCOMPARE(transientSpy.first().first().value(), childSurface2Interface); + QCOMPARE(transientSpy.first().at(1).value(), m_exportedSurfaceInterface.data()); + + //transientFor api + //check the old relationship is still here + QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), m_exportedSurfaceInterface.data()); + //check the new relationship + QCOMPARE(m_foreignInterface->transientFor(childSurface2Interface), m_exportedSurfaceInterface.data()); +} + +void TestForeign::testImportTwoTimes() +{ + doExport(); + + QSignalSpy transientSpy(m_foreignInterface, &KWayland::Server::XdgForeignUnstableInterface::transientChanged); + QVERIFY(transientSpy.isValid()); + + //Import another time the exported window + KWayland::Client::XdgImportedUnstable *imported2 = m_importer->import(m_exported->handle(), this); + QVERIFY(imported2->isValid()); + + //create a second child surface + QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); + QVERIFY(serverSurfaceCreated.isValid()); + + KWayland::Client::Surface *childSurface2 = m_compositor->createSurface(); + QVERIFY(serverSurfaceCreated.wait()); + + KWayland::Server::SurfaceInterface *childSurface2Interface = serverSurfaceCreated.first().first().value(); + + imported2->setParentOf(childSurface2); + QVERIFY(transientSpy.wait()); + + QCOMPARE(transientSpy.first().first().value(), childSurface2Interface); + QCOMPARE(transientSpy.first().at(1).value(), m_exportedSurfaceInterface.data()); + + //transientFor api + //check the old relationship is still here + QCOMPARE(m_foreignInterface->transientFor(m_childSurfaceInterface), m_exportedSurfaceInterface.data()); + //check the new relationship + QCOMPARE(m_foreignInterface->transientFor(childSurface2Interface), m_exportedSurfaceInterface.data()); +} + +QTEST_GUILESS_MAIN(TestForeign) +#include "test_xdg_foreign.moc" diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -50,6 +50,8 @@ textinput_v2.cpp xdgshell.cpp xdgshell_v5.cpp + xdgforeign_v1.cpp + xdgforeign.cpp ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS @@ -138,6 +140,10 @@ PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1 ) +ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS + PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-foreign-unstable-v1.xml + BASENAME xdg-foreign-unstable-v1 +) add_library(KF5WaylandClient ${CLIENT_LIB_SRCS}) generate_export_header(KF5WaylandClient @@ -205,6 +211,7 @@ touch.h textinput.h xdgshell.h + xdgforeign_v1.h ) install(FILES diff --git a/src/client/protocols/xdg-foreign-unstable-v1.xml b/src/client/protocols/xdg-foreign-unstable-v1.xml new file mode 100644 --- /dev/null +++ b/src/client/protocols/xdg-foreign-unstable-v1.xml @@ -0,0 +1,182 @@ + + + + + Copyright © 2015-2016 Red Hat Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol specifies a way for making it possible to reference a surface + of a different client. With such a reference, a client can, by using the + interfaces provided by this protocol, manipulate the relationship between + its own surfaces and the surface of some other client. For example, stack + some of its own surface above the other clients surface. + + In order for a client A to get a reference of a surface of client B, client + B must first export its surface using xdg_exporter.export. Upon doing this, + client B will receive a handle (a unique string) that it may share with + client A in some way (for example D-Bus). After client A has received the + handle from client B, it may use xdg_importer.import to create a reference + to the surface client B just exported. See the corresponding requests for + details. + + A possible use case for this is out-of-process dialogs. For example when a + sandboxed client without file system access needs the user to select a file + on the file system, given sandbox environment support, it can export its + surface, passing the exported surface handle to an unsandboxed process that + can show a file browser dialog and stack it above the sandboxed client's + surface. + + Warning! The protocol described in this file is experimental and backward + incompatible changes may be made. Backward compatible changes may be added + together with the corresponding interface version bump. Backward + incompatible changes are done by bumping the version number in the protocol + and interface names and resetting the interface version. Once the protocol + is to be declared stable, the 'z' prefix and the version number in the + protocol and interface names are removed and the interface version number is + reset. + + + + + A global interface used for exporting surfaces that can later be imported + using xdg_importer. + + + + + Notify the compositor that the xdg_exporter object will no longer be + used. + + + + + + The export request exports the passed surface so that it can later be + imported via xdg_importer. When called, a new xdg_exported object will + be created and xdg_exported.handle will be sent immediately. See the + corresponding interface and event for details. + + A surface may be exported multiple times, and each exported handle may + be used to create a xdg_imported multiple times. Only xdg_surface + surfaces may be exported. + + + + + + + + + A global interface used for importing surfaces exported by xdg_exporter. + With this interface, a client can create a reference to a surface of + another client. + + + + + Notify the compositor that the xdg_importer object will no longer be + used. + + + + + + The import request imports a surface from any client given a handle + retrieved by exporting said surface using xdg_exporter.export. When + called, a new xdg_imported object will be created. This new object + represents the imported surface, and the importing client can + manipulate its relationship using it. See xdg_imported for details. + + + + + + + + + A xdg_exported object represents an exported reference to a surface. The + exported surface may be referenced as long as the xdg_exported object not + destroyed. Destroying the xdg_exported invalidates any relationship the + importer may have established using xdg_imported. + + + + + Revoke the previously exported surface. This invalidates any + relationship the importer may have set up using the xdg_imported created + given the handle sent via xdg_exported.handle. + + + + + + The handle event contains the unique handle of this exported surface + reference. It may be shared with any client, which then can use it to + import the surface by calling xdg_importer.import. A handle may be + used to import the surface multiple times. + + + + + + + + A xdg_imported object represents an imported reference to surface exported + by some client. A client can use this interface to manipulate + relationships between its own surfaces and the imported surface. + + + + + Notify the compositor that it will no longer use the xdg_imported + object. Any relationship that may have been set up will at this point + be invalidated. + + + + + + Set the imported surface as the parent of some surface of the client. + The passed surface must be a toplevel xdg_surface. Calling this function + sets up a surface to surface relation with the same stacking and positioning + semantics as xdg_surface.set_parent. + + + + + + + The imported surface handle has been destroyed and any relationship set + up has been invalidated. This may happen for various reasons, for + example if the exported surface or the exported surface handle has been + destroyed, if the handle used for importing was invalid. + + + + + diff --git a/src/client/registry.h b/src/client/registry.h --- a/src/client/registry.h +++ b/src/client/registry.h @@ -53,6 +53,8 @@ struct zwp_relative_pointer_manager_v1; struct zwp_pointer_gestures_v1; struct zwp_pointer_constraints_v1; +struct zxdg_exporter_v1; +struct zxdg_importer_v1; namespace KWayland { @@ -88,6 +90,10 @@ class TextInputManagerUnstableV2; class XdgShell; class RelativePointerManager; +class XdgExporterUnstableV1; +class XdgImporterUnstableV1; +class XdgExporterUnstable; +class XdgImporterUnstable; /** * @short Wrapper for the wl_registry interface. @@ -150,7 +156,9 @@ XdgShellUnstableV5, ///< Refers to xdg_shell (unstable version 5), @since 5.25 RelativePointerManagerUnstableV1, ///< Refers to zwp_relative_pointer_manager_v1, @since 5.28 PointerGesturesUnstableV1, ///< Refers to zwp_pointer_gestures_v1, @since 5.29 - PointerConstraintsUnstableV1 ///< Refers to zwp_pointer_constraints_v1, @since 5.29 + PointerConstraintsUnstableV1, ///< Refers to zwp_pointer_constraints_v1, @since 5.29 + XdgExporterUnstableV1, ///< refers to zxdg_exporter_v1, @since 5.38 + XdgImporterUnstableV1 ///< refers to zxdg_importer_v1, @since 5.38 }; explicit Registry(QObject *parent = nullptr); virtual ~Registry(); @@ -515,6 +523,9 @@ * @since 5.29 **/ zwp_pointer_constraints_v1 *bindPointerConstraintsUnstableV1(uint32_t name, uint32_t version) const; + + zxdg_exporter_v1 *bindXdgExporterUnstableV1(uint32_t name, uint32_t version) const; + zxdg_importer_v1 *bindXdgImporterUnstableV1(uint32_t name, uint32_t version) const; ///@} /** @@ -925,6 +936,9 @@ * @since 5.29 **/ PointerConstraints *createPointerConstraints(quint32 name, quint32 version, QObject *parent = nullptr); + + XdgExporterUnstable *createXdgExporterUnstable(quint32 name, quint32 version, QObject *parent = nullptr); + XdgImporterUnstable *createXdgImporterUnstable(quint32 name, quint32 version, QObject *parent = nullptr); ///@} /** @@ -1114,6 +1128,9 @@ * @since 5.29 **/ void pointerConstraintsUnstableV1Announced(quint32 name, quint32 version); + + void exporterUnstableV1Announced(quint32 name, quint32 version); + void importerUnstableV1Announced(quint32 name, quint32 version); ///@} /** * @name Interface removed signals. @@ -1267,6 +1284,9 @@ * @since 5.29 **/ void pointerConstraintsUnstableV1Removed(quint32 name); + + void exporterUnstableV1Removed(quint32 name); + void importerUnstableV1Removed(quint32 name); ///@} /** * Generic announced signal which gets emitted whenever an interface gets diff --git a/src/client/registry.cpp b/src/client/registry.cpp --- a/src/client/registry.cpp +++ b/src/client/registry.cpp @@ -49,6 +49,7 @@ #include "xdgshell.h" #include "xdgshell_p.h" #include "wayland_pointer_p.h" +#include "xdgforeign_v1.h" // Qt #include // wayland @@ -72,6 +73,7 @@ #include #include #include +#include /***** * How to add another interface: @@ -281,6 +283,20 @@ &zwp_pointer_constraints_v1_interface, &Registry::pointerConstraintsUnstableV1Announced, &Registry::pointerConstraintsUnstableV1Removed + }}, + {Registry::Interface::XdgExporterUnstableV1, { + 1, + QByteArrayLiteral("zxdg_exporter_v1"), + &zxdg_exporter_v1_interface, + &Registry::exporterUnstableV1Announced, + &Registry::exporterUnstableV1Removed + }}, + {Registry::Interface::XdgImporterUnstableV1, { + 1, + QByteArrayLiteral("zxdg_importer_v1"), + &zxdg_importer_v1_interface, + &Registry::importerUnstableV1Announced, + &Registry::importerUnstableV1Removed }} }; @@ -581,6 +597,8 @@ BIND(RelativePointerManagerUnstableV1, zwp_relative_pointer_manager_v1) BIND(PointerGesturesUnstableV1, zwp_pointer_gestures_v1) BIND(PointerConstraintsUnstableV1, zwp_pointer_constraints_v1) +BIND(XdgExporterUnstableV1, zxdg_exporter_v1) +BIND(XdgImporterUnstableV1, zxdg_importer_v1) BIND2(ShadowManager, Shadow, org_kde_kwin_shadow_manager) BIND2(BlurManager, Blur, org_kde_kwin_blur_manager) BIND2(ContrastManager, Contrast, org_kde_kwin_contrast_manager) @@ -639,6 +657,18 @@ #undef CREATE #undef CREATE2 +XdgExporterUnstable *Registry::createXdgExporterUnstable(quint32 name, quint32 version, QObject *parent) +{ + //only V1 supported for now + return d->create(name, version, parent, &Registry::bindXdgExporterUnstableV1); +} + +XdgImporterUnstable *Registry::createXdgImporterUnstable(quint32 name, quint32 version, QObject *parent) +{ + //only V1 supported for now + return d->create(name, version, parent, &Registry::bindXdgImporterUnstableV1); +} + TextInputManager *Registry::createTextInputManager(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { diff --git a/src/client/xdgforeign.h b/src/client/xdgforeign.h new file mode 100644 --- /dev/null +++ b/src/client/xdgforeign.h @@ -0,0 +1,350 @@ +/**************************************************************************** +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#ifndef KWAYLAND_CLIENT_XDGFOREIGN_H +#define KWAYLAND_CLIENT_XDGFOREIGN_H + +#include "surface.h" + +#include + +#include + +struct zxdg_exporter_v1; +struct zxdg_importer_v1; +struct zxdg_exported_v1; +struct zxdg_imported_v1; + +namespace KWayland +{ +namespace Client +{ + +class EventQueue; +class Surface; +class XdgExportedUnstable; +class XdgImportedUnstable; + +/** + * @short Wrapper for the zxdg_exporter_v1 interface. + * + * This class provides a convenient wrapper for the zxdg_exporter_v1 interface. + * + * To use this class one needs to interact with the Registry. There are two + * possible ways to create the interface: + * @code + * *c = registry->create(name, version); + * @endcode + * + * This creates the and sets it up directly. As an alternative this + * can also be done in a more low level way: + * @code + * *c = new ; + * c->setup(registry->bind(name, version)); + * @endcode + * + * The can be used as a drop-in replacement for any zxdg_exporter_v1 + * pointer as it provides matching cast operators. + * + * @see Registry + **/ +class KWAYLANDCLIENT_EXPORT XdgExporterUnstable : public QObject +{ + Q_OBJECT +public: + virtual ~XdgExporterUnstable(); + + /** + * Setup this to manage the @p . + * When using Registry::create there is no need to call this + * method. + **/ + void setup(zxdg_exporter_v1 *); + /** + * @returns @c true if managing a zxdg_exporter_v1. + **/ + bool isValid() const; + /** + * Releases the zxdg_exporter_v1 interface. + * After the interface has been released the instance is no + * longer valid and can be setup with another zxdg_exporter_v1 interface. + **/ + void release(); + /** + * Destroys the data held by this . + * This method is supposed to be used when the connection to the Wayland + * server goes away. If the connection is not valid anymore, it's not + * possible to call release anymore as that calls into the Wayland + * connection and the call would fail. This method cleans up the data, so + * that the instance can be deleted or set up to a new zxdg_exporter_v1 interface + * once there is a new connection available. + * + * It is suggested to connect this method to ConnectionThread::connectionDied: + * @code + * connect(connection, &ConnectionThread::connectionDied, , &::destroy); + * @endcode + * + * @see release + **/ + void destroy(); + + /** + * Sets the @p queue to use for creating objects with this . + **/ + void setEventQueue(EventQueue *queue); + /** + * @returns The event queue to use for creating objects with this . + **/ + EventQueue *eventQueue(); + + XdgExportedUnstable *exportSurface(Surface *surface, QObject *parent = nullptr); + + operator zxdg_exporter_v1*(); + operator zxdg_exporter_v1*() const; + +Q_SIGNALS: + /** + * The corresponding global for this interface on the Registry got removed. + * + * This signal gets only emitted if the got created by + * Registry::create + **/ + void removed(); + +protected: + class Private; + explicit XdgExporterUnstable(Private *p, QObject *parent = nullptr); + QScopedPointer d; +}; + +/** + * @short Wrapper for the zxdg_importer_v1 interface. + * + * This class provides a convenient wrapper for the zxdg_importer_v1 interface. + * + * To use this class one needs to interact with the Registry. There are two + * possible ways to create the interface: + * @code + * *c = registry->create(name, version); + * @endcode + * + * This creates the and sets it up directly. As an alternative this + * can also be done in a more low level way: + * @code + * *c = new ; + * c->setup(registry->bind(name, version)); + * @endcode + * + * The can be used as a drop-in replacement for any zxdg_importer_v1 + * pointer as it provides matching cast operators. + * + * @see Registry + **/ +class KWAYLANDCLIENT_EXPORT XdgImporterUnstable : public QObject +{ + Q_OBJECT +public: + virtual ~XdgImporterUnstable(); + + /** + * Setup this to manage the @p . + * When using Registry::create there is no need to call this + * method. + **/ + void setup(zxdg_importer_v1 *); + /** + * @returns @c true if managing a zxdg_importer_v1. + **/ + bool isValid() const; + /** + * Releases the zxdg_importer_v1 interface. + * After the interface has been released the instance is no + * longer valid and can be setup with another zxdg_importer_v1 interface. + **/ + void release(); + /** + * Destroys the data held by this . + * This method is supposed to be used when the connection to the Wayland + * server goes away. If the connection is not valid anymore, it's not + * possible to call release anymore as that calls into the Wayland + * connection and the call would fail. This method cleans up the data, so + * that the instance can be deleted or set up to a new zxdg_importer_v1 interface + * once there is a new connection available. + * + * It is suggested to connect this method to ConnectionThread::connectionDied: + * @code + * connect(connection, &ConnectionThread::connectionDied, , &::destroy); + * @endcode + * + * @see release + **/ + void destroy(); + + /** + * Sets the @p queue to use for creating objects with this . + **/ + void setEventQueue(EventQueue *queue); + /** + * @returns The event queue to use for creating objects with this . + **/ + EventQueue *eventQueue(); + + XdgImportedUnstable *import(const QString & handle, QObject *parent = nullptr); + + operator zxdg_importer_v1*(); + operator zxdg_importer_v1*() const; + +Q_SIGNALS: + /** + * The corresponding global for this interface on the Registry got removed. + * + * This signal gets only emitted if the got created by + * Registry::create + **/ + void removed(); + +protected: + class Private; + explicit XdgImporterUnstable(Private *p, QObject *parent = nullptr); + QScopedPointer d; +}; + +class KWAYLANDCLIENT_EXPORT XdgExportedUnstable : public QObject +{ + Q_OBJECT +public: + virtual ~XdgExportedUnstable(); + + /** + * Setup this to manage the @p . + * When using ::create there is no need to call this + * method. + **/ + void setup(zxdg_exported_v1 *); + /** + * @returns @c true if managing a zxdg_exported_v1. + **/ + bool isValid() const; + /** + * Releases the zxdg_exported_v1 interface. + * After the interface has been released the instance is no + * longer valid and can be setup with another zxdg_exported_v1 interface. + **/ + void release(); + /** + * Destroys the data held by this . + * This method is supposed to be used when the connection to the Wayland + * server goes away. If the connection is not valid anymore, it's not + * possible to call release anymore as that calls into the Wayland + * connection and the call would fail. This method cleans up the data, so + * that the instance can be deleted or set up to a new zxdg_exported_v1 interface + * once there is a new connection available. + * + * It is suggested to connect this method to ConnectionThread::connectionDied: + * @code + * connect(connection, &ConnectionThread::connectionDied, , &::destroy); + * @endcode + * + * @see release + **/ + void destroy(); + + QString handle() const; + + operator zxdg_exported_v1*(); + operator zxdg_exported_v1*() const; + +Q_SIGNALS: + /** + * Emitted when the exported window is fully initialized. + * the handle will be valid at this point + **/ + void done(); + +protected: + friend class XdgExporterUnstable; + class Private; + explicit XdgExportedUnstable(Private *p, QObject *parent = nullptr); + QScopedPointer d; +}; + +class KWAYLANDCLIENT_EXPORT XdgImportedUnstable : public QObject +{ + Q_OBJECT +public: + virtual ~XdgImportedUnstable(); + + /** + * Setup this to manage the @p . + * When using ::create there is no need to call this + * method. + **/ + void setup(zxdg_imported_v1 *); + /** + * @returns @c true if managing a zxdg_imported_v1. + **/ + bool isValid() const; + /** + * Releases the zxdg_imported_v1 interface. + * After the interface has been released the instance is no + * longer valid and can be setup with another zxdg_imported_v1 interface. + **/ + void release(); + /** + * Destroys the data held by this . + * This method is supposed to be used when the connection to the Wayland + * server goes away. If the connection is not valid anymore, it's not + * possible to call release anymore as that calls into the Wayland + * connection and the call would fail. This method cleans up the data, so + * that the instance can be deleted or set up to a new zxdg_imported_v1 interface + * once there is a new connection available. + * + * It is suggested to connect this method to ConnectionThread::connectionDied: + * @code + * connect(connection, &ConnectionThread::connectionDied, , &::destroy); + * @endcode + * + * @see release + **/ + void destroy(); + + void setParentOf(Surface *surface); + + operator zxdg_imported_v1*(); + operator zxdg_imported_v1*() const; + +Q_SIGNALS: + /** + * Emitted when the imported surface is not valid anymore, + * for instance because it's no longer exported on the other end + */ + void importedDestroyed(); + +protected: + friend class XdgImporterUnstable; + class Private; + explicit XdgImportedUnstable(Private *p, QObject *parent = nullptr); + QScopedPointer d; +}; + + +} +} + +#endif diff --git a/src/client/xdgforeign.cpp b/src/client/xdgforeign.cpp new file mode 100644 --- /dev/null +++ b/src/client/xdgforeign.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#include "xdgforeign.h" +#include "xdgforeign_p.h" +#include "event_queue.h" +#include "wayland_pointer_p.h" + +#include + +#include + +namespace KWayland +{ +namespace Client +{ + +XdgExporterUnstable::Private::Private() +{ +} + +XdgExporterUnstable::Private::~Private() +{ +} + +XdgExporterUnstable::XdgExporterUnstable(Private *p, QObject *parent) + : QObject(parent) + , d(p) +{ +} + +XdgExporterUnstable::~XdgExporterUnstable() +{ + release(); +} + +void XdgExporterUnstable::setup(zxdg_exporter_v1 *exporter) +{ + d->setupV1(exporter); +} + +void XdgExporterUnstable::release() +{ + d->release(); +} + +void XdgExporterUnstable::destroy() +{ + d->destroy(); +} + +XdgExporterUnstable::operator zxdg_exporter_v1*() { + return d->exporterV1(); +} + +XdgExporterUnstable::operator zxdg_exporter_v1*() const { + return d->exporterV1(); +} + +bool XdgExporterUnstable::isValid() const +{ + return d->isValid(); +} + +void XdgExporterUnstable::setEventQueue(EventQueue *queue) +{ + d->queue = queue; +} + +EventQueue *XdgExporterUnstable::eventQueue() +{ + return d->queue; +} + +XdgExportedUnstable *XdgExporterUnstable::exportSurface(Surface *surface, QObject *parent) +{ + return d->exportTopLevelV1(surface, parent); +} + + + +XdgImporterUnstable::Private::Private() +{ +} + +XdgImporterUnstable::Private::~Private() +{ +} + +XdgImporterUnstable::XdgImporterUnstable(Private *p, QObject *parent) + : QObject(parent) + , d(p) +{ +} + +XdgImporterUnstable::~XdgImporterUnstable() +{ + release(); +} + +void XdgImporterUnstable::setup(zxdg_importer_v1 *importer) +{ + d->setupV1(importer); +} + +void XdgImporterUnstable::release() +{ + d->release(); +} + +void XdgImporterUnstable::destroy() +{ + d->destroy(); +} + +XdgImporterUnstable::operator zxdg_importer_v1*() { + return d->importerV1(); +} + +XdgImporterUnstable::operator zxdg_importer_v1*() const { + return d->importerV1(); +} + +bool XdgImporterUnstable::isValid() const +{ + return d->isValid(); +} + +void XdgImporterUnstable::setEventQueue(EventQueue *queue) +{ + d->queue = queue; +} + +EventQueue *XdgImporterUnstable::eventQueue() +{ + return d->queue; +} + +XdgImportedUnstable *XdgImporterUnstable::import(const QString & handle, QObject *parent) +{ + Q_ASSERT(isValid()); + return d->importTopLevelV1(handle, parent); +} + +XdgExportedUnstable::XdgExportedUnstable(Private *p, QObject *parent) + : QObject(parent) + , d(p) +{ +} + +XdgExportedUnstable::Private::Private(XdgExportedUnstable *q) + : q(q) +{ +} + +XdgExportedUnstable::Private::~Private() +{ +} + +XdgExportedUnstable::~XdgExportedUnstable() +{ + release(); +} + +void XdgExportedUnstable::setup(zxdg_exported_v1 *exported) +{ + d->setupV1(exported); +} + +void XdgExportedUnstable::release() +{ + d->release(); +} + +void XdgExportedUnstable::destroy() +{ + d->destroy(); +} + +QString XdgExportedUnstable::handle() const +{ + return d->handle; +} + +XdgExportedUnstable::operator zxdg_exported_v1*() { + return d->exportedV1(); +} + +XdgExportedUnstable::operator zxdg_exported_v1*() const { + return d->exportedV1(); +} + +bool XdgExportedUnstable::isValid() const +{ + return d->isValid(); +} + +XdgImportedUnstable::Private::Private(XdgImportedUnstable *q) + : q(q) +{ +} + +XdgImportedUnstable::Private::~Private() +{ +} + +XdgImportedUnstable::XdgImportedUnstable(Private *p, QObject *parent) + : QObject(parent) + , d(p) +{ +} + +XdgImportedUnstable::~XdgImportedUnstable() +{ + release(); +} + +void XdgImportedUnstable::setup(zxdg_imported_v1 *imported) +{ + d->setupV1(imported); +} + +void XdgImportedUnstable::release() +{ + d->release(); +} + +void XdgImportedUnstable::destroy() +{ + d->destroy(); +} + +XdgImportedUnstable::operator zxdg_imported_v1*() { + return d->importedV1(); +} + +XdgImportedUnstable::operator zxdg_imported_v1*() const { + return d->importedV1(); +} + +bool XdgImportedUnstable::isValid() const +{ + return d->isValid(); +} + +void XdgImportedUnstable::setParentOf(Surface *surface) +{ + Q_ASSERT(isValid()); + d->setParentOf(surface); +} + + +} +} + diff --git a/src/client/xdgforeign_p.h b/src/client/xdgforeign_p.h new file mode 100644 --- /dev/null +++ b/src/client/xdgforeign_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#ifndef KWAYLAND_CLIENT_XDGFOREIGN_P_H +#define KWAYLAND_CLIENT_XDGFOREIGN_P_H + +#include "xdgforeign.h" +#include + +namespace KWayland +{ +namespace Client +{ + +class XdgExportedUnstableV1; +class XdgImportedUnstableV1; + +class Q_DECL_HIDDEN XdgExporterUnstable::Private +{ +public: + Private(); + virtual ~Private(); + + virtual XdgExportedUnstable *exportTopLevelV1(Surface *surface, QObject *parent) = 0; + + virtual void setupV1(zxdg_exporter_v1 *arg) = 0; + virtual zxdg_exporter_v1 *exporterV1() = 0; + + virtual void release() = 0; + virtual void destroy() = 0; + virtual bool isValid() = 0; + + EventQueue *queue = nullptr; +}; + +class Q_DECL_HIDDEN XdgImporterUnstable::Private +{ +public: + Private(); + virtual ~Private(); + + virtual XdgImportedUnstable *importTopLevelV1(const QString & handle, QObject *parent) = 0; + + virtual void setupV1(zxdg_importer_v1 *arg) = 0; + virtual zxdg_importer_v1 *importerV1() = 0; + + virtual void release() = 0; + virtual void destroy() = 0; + virtual bool isValid() = 0; + + EventQueue *queue = nullptr; +}; + + +class Q_DECL_HIDDEN XdgExportedUnstable::Private +{ +public: + Private(XdgExportedUnstable *q); + virtual ~Private(); + + virtual void setupV1(zxdg_exported_v1 *) = 0; + virtual zxdg_exported_v1 *exportedV1() = 0; + + virtual void release() = 0; + virtual void destroy() = 0; + virtual bool isValid() = 0; + + QString handle; + +protected: + XdgExportedUnstable *q; + +}; + + +class Q_DECL_HIDDEN XdgImportedUnstable::Private +{ +public: + Private(XdgImportedUnstable *q); + virtual ~Private(); + + virtual void setupV1(zxdg_imported_v1 *) = 0; + virtual zxdg_imported_v1 *importedV1() = 0; + + virtual void setParentOf(Surface *surface) = 0; + virtual void release() = 0; + virtual void destroy() = 0; + virtual bool isValid() = 0; + +protected: + XdgImportedUnstable *q; +}; + +} +} + +#endif diff --git a/src/client/xdgforeign_v1.h b/src/client/xdgforeign_v1.h new file mode 100644 --- /dev/null +++ b/src/client/xdgforeign_v1.h @@ -0,0 +1,153 @@ +/**************************************************************************** +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#ifndef KWAYLAND_CLIENT_XDGFOREIGN_V1_H +#define KWAYLAND_CLIENT_XDGFOREIGN_V1_H + +#include "xdgforeign.h" +#include "surface.h" + +#include + +#include + +struct zxdg_exporter_v1; +struct zxdg_importer_v1; +struct zxdg_exported_v1; +struct zxdg_imported_v1; + +namespace KWayland +{ +namespace Client +{ + +class EventQueue; +class Surface; +class XdgExportedUnstableV1; +class XdgImportedUnstableV1; + +/** + * @short Wrapper for the zxdg_exporter_v1 interface. + * + * This class provides a convenient wrapper for the zxdg_exporter_v1 interface. + * + * To use this class one needs to interact with the Registry. There are two + * possible ways to create the interface: + * @code + * *c = registry->create(name, version); + * @endcode + * + * This creates the and sets it up directly. As an alternative this + * can also be done in a more low level way: + * @code + * *c = new ; + * c->setup(registry->bind(name, version)); + * @endcode + * + * The can be used as a drop-in replacement for any zxdg_exporter_v1 + * pointer as it provides matching cast operators. + * + * @see Registry + **/ +class Q_DECL_HIDDEN XdgExporterUnstableV1 : public XdgExporterUnstable +{ + Q_OBJECT +public: + /** + * Creates a new . + * Note: after constructing the it is not yet valid and one needs + * to call setup. In order to get a ready to use prefer using + * Registry::create. + **/ + explicit XdgExporterUnstableV1(QObject *parent = nullptr); + virtual ~XdgExporterUnstableV1(); + +private: + class Private; +}; + +/** + * @short Wrapper for the zxdg_importer_v1 interface. + * + * This class provides a convenient wrapper for the zxdg_importer_v1 interface. + * + * To use this class one needs to interact with the Registry. There are two + * possible ways to create the interface: + * @code + * *c = registry->create(name, version); + * @endcode + * + * This creates the and sets it up directly. As an alternative this + * can also be done in a more low level way: + * @code + * *c = new ; + * c->setup(registry->bind(name, version)); + * @endcode + * + * The can be used as a drop-in replacement for any zxdg_importer_v1 + * pointer as it provides matching cast operators. + * + * @see Registry + **/ +class Q_DECL_HIDDEN XdgImporterUnstableV1 : public XdgImporterUnstable +{ + Q_OBJECT +public: + /** + * Creates a new . + * Note: after constructing the it is not yet valid and one needs + * to call setup. In order to get a ready to use prefer using + * Registry::create. + **/ + explicit XdgImporterUnstableV1(QObject *parent = nullptr); + virtual ~XdgImporterUnstableV1(); + +private: + class Private; +}; + +class Q_DECL_HIDDEN XdgExportedUnstableV1 : public XdgExportedUnstable +{ + Q_OBJECT +public: + virtual ~XdgExportedUnstableV1(); + +private: + friend class XdgExporterUnstableV1; + explicit XdgExportedUnstableV1(QObject *parent = nullptr); + class Private; +}; + +class Q_DECL_HIDDEN XdgImportedUnstableV1 : public XdgImportedUnstable +{ + Q_OBJECT +public: + virtual ~XdgImportedUnstableV1(); + +private: + friend class XdgImporterUnstableV1; + explicit XdgImportedUnstableV1(QObject *parent = nullptr); + class Private; +}; + + +} +} + +#endif diff --git a/src/client/xdgforeign_v1.cpp b/src/client/xdgforeign_v1.cpp new file mode 100644 --- /dev/null +++ b/src/client/xdgforeign_v1.cpp @@ -0,0 +1,337 @@ +/**************************************************************************** +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#include "xdgforeign_v1.h" +#include "xdgforeign_p.h" +#include "event_queue.h" +#include "wayland_pointer_p.h" + +#include + +#include + +namespace KWayland +{ +namespace Client +{ + +class Q_DECL_HIDDEN XdgExporterUnstableV1::Private : public XdgExporterUnstable::Private +{ +public: + Private(); + + XdgExportedUnstable *exportTopLevelV1(Surface *surface, QObject *parent) override; + void setupV1(zxdg_exporter_v1 *arg) override; + zxdg_exporter_v1 *exporterV1() override; + + void release() override; + void destroy() override; + bool isValid() override; + + WaylandPointer exporter; +}; + +XdgExporterUnstableV1::Private::Private() + : XdgExporterUnstable::Private() +{} + +zxdg_exporter_v1 *XdgExporterUnstableV1::Private::exporterV1() +{ + return exporter; +} + +void XdgExporterUnstableV1::Private::release() +{ + exporter.release(); +} + +void XdgExporterUnstableV1::Private::destroy() +{ + exporter.destroy(); +} + +bool XdgExporterUnstableV1::Private::isValid() +{ + return exporter.isValid(); +} + +XdgExportedUnstable *XdgExporterUnstableV1::Private::exportTopLevelV1(Surface *surface, QObject *parent) +{ + Q_ASSERT(isValid()); + auto p = new XdgExportedUnstableV1(parent); + auto w = zxdg_exporter_v1_export_toplevel(exporter, *surface); + if (queue) { + queue->addProxy(w); + } + p->setup(w); + return p; +} + + +XdgExporterUnstableV1::XdgExporterUnstableV1(QObject *parent) + : XdgExporterUnstable(new Private, parent) +{ +} + +void XdgExporterUnstableV1::Private::setupV1(zxdg_exporter_v1 *arg) +{ + Q_ASSERT(arg); + Q_ASSERT(!exporter); + exporter.setup(arg); +} + +XdgExporterUnstableV1::~XdgExporterUnstableV1() +{ +} + +class Q_DECL_HIDDEN XdgImporterUnstableV1::Private : public XdgImporterUnstable::Private +{ +public: + Private(); + + XdgImportedUnstable *importTopLevelV1(const QString & handle, QObject *parent) override; + void setupV1(zxdg_importer_v1 *arg) override; + zxdg_importer_v1 *importerV1() override; + + void release() override; + void destroy() override; + bool isValid() override; + + WaylandPointer importer; + EventQueue *queue = nullptr; +}; + +XdgImporterUnstableV1::Private::Private() + : XdgImporterUnstable::Private() +{} + +zxdg_importer_v1 *XdgImporterUnstableV1::Private::importerV1() +{ + return importer; +} + +void XdgImporterUnstableV1::Private::release() +{ + importer.release(); +} + +void XdgImporterUnstableV1::Private::destroy() +{ + importer.destroy(); +} + +bool XdgImporterUnstableV1::Private::isValid() +{ + return importer.isValid(); +} + +XdgImportedUnstable *XdgImporterUnstableV1::Private::importTopLevelV1(const QString & handle, QObject *parent) +{ + Q_ASSERT(isValid()); + auto p = new XdgImportedUnstableV1(parent); + auto w = zxdg_importer_v1_import_toplevel(importer, handle.toUtf8()); + if (queue) { + queue->addProxy(w); + } + p->setup(w); + return p; +} + + +XdgImporterUnstableV1::XdgImporterUnstableV1(QObject *parent) + : XdgImporterUnstable(new Private, parent) +{ +} + +void XdgImporterUnstableV1::Private::setupV1(zxdg_importer_v1 *arg) +{ + Q_ASSERT(arg); + Q_ASSERT(!importer); + importer.setup(arg); +} + +XdgImporterUnstableV1::~XdgImporterUnstableV1() +{ +} + + +class Q_DECL_HIDDEN XdgExportedUnstableV1::Private : public XdgExportedUnstable::Private +{ +public: + Private(XdgExportedUnstableV1 *q); + + void setupV1(zxdg_exported_v1 *arg) override; + zxdg_exported_v1 *exportedV1() override; + + void release() override; + void destroy() override; + bool isValid() override; + + WaylandPointer exported; + +private: + static void handleCallback(void *data, zxdg_exported_v1 *zxdg_exported_v1, const char * handle); + + static const zxdg_exported_v1_listener s_listener; +}; + +zxdg_exported_v1 *XdgExportedUnstableV1::Private::exportedV1() +{ + return exported; +} + +void XdgExportedUnstableV1::Private::release() +{ + exported.release(); +} + +void XdgExportedUnstableV1::Private::destroy() +{ + exported.destroy(); +} + +bool XdgExportedUnstableV1::Private::isValid() +{ + return exported.isValid(); +} + + +const zxdg_exported_v1_listener XdgExportedUnstableV1::Private::s_listener = { + handleCallback +}; + +void XdgExportedUnstableV1::Private::handleCallback(void *data, zxdg_exported_v1 *zxdg_exported_v1, const char * handle) +{ + auto p = reinterpret_cast(data); + Q_ASSERT(p->exported == zxdg_exported_v1); + + p->handle = handle; + emit p->q->done(); +} + +XdgExportedUnstableV1::XdgExportedUnstableV1(QObject *parent) + : XdgExportedUnstable(new Private(this), parent) +{ +} + +void XdgExportedUnstableV1::Private::setupV1(zxdg_exported_v1 *arg) +{ + Q_ASSERT(arg); + Q_ASSERT(!exported); + exported.setup(arg); + zxdg_exported_v1_add_listener(exported, &s_listener, this); +} + +XdgExportedUnstableV1::Private::Private(XdgExportedUnstableV1 *q) + : XdgExportedUnstable::Private::Private(q) +{ +} + +XdgExportedUnstableV1::~XdgExportedUnstableV1() +{ +} + +class Q_DECL_HIDDEN XdgImportedUnstableV1::Private : public XdgImportedUnstable::Private +{ +public: + Private(XdgImportedUnstableV1 *q); + + void setupV1(zxdg_imported_v1 *arg) override; + zxdg_imported_v1 *importedV1() override; + + void setParentOf(Surface *surface) override; + void release() override; + void destroy() override; + bool isValid() override; + + WaylandPointer imported; + +private: + static void destroyedCallback(void *data, zxdg_imported_v1 *zxdg_imported_v1); + + static const zxdg_imported_v1_listener s_listener; +}; + +XdgImportedUnstableV1::Private::Private(XdgImportedUnstableV1 *q) + : XdgImportedUnstable::Private::Private(q) +{ +} + +zxdg_imported_v1 *XdgImportedUnstableV1::Private::importedV1() +{ + return imported; +} + +void XdgImportedUnstableV1::Private::release() +{ + imported.release(); +} + +void XdgImportedUnstableV1::Private::destroy() +{ + imported.destroy(); +} + +bool XdgImportedUnstableV1::Private::isValid() +{ + return imported.isValid(); +} + +void XdgImportedUnstableV1::Private::setParentOf(Surface *surface) +{ + Q_ASSERT(isValid()); + zxdg_imported_v1_set_parent_of(imported, *surface); +} + +const zxdg_imported_v1_listener XdgImportedUnstableV1::Private::s_listener = { + destroyedCallback +}; + +void XdgImportedUnstableV1::Private::destroyedCallback(void *data, zxdg_imported_v1 *zxdg_imported_v1) +{ + auto p = reinterpret_cast(data); + Q_ASSERT(p->imported == zxdg_imported_v1); + + p->q->release(); + emit p->q->importedDestroyed(); +} + + + +XdgImportedUnstableV1::XdgImportedUnstableV1(QObject *parent) + : XdgImportedUnstable(new Private(this), parent) +{ +} + +void XdgImportedUnstableV1::Private::setupV1(zxdg_imported_v1 *arg) +{ + Q_ASSERT(arg); + Q_ASSERT(!imported); + imported.setup(arg); + zxdg_imported_v1_add_listener(imported, &s_listener, this); +} + +XdgImportedUnstableV1::~XdgImportedUnstableV1() +{ +} + + +} +} + diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -45,6 +45,8 @@ textinput_interface_v2.cpp xdgshell_interface.cpp xdgshell_v5_interface.cpp + xdgforeign_v1_interface.cpp + xdgforeign_interface.cpp ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS @@ -141,6 +143,11 @@ BASENAME pointer-constraints-unstable-v1 ) +ecm_add_wayland_server_protocol(SERVER_LIB_SRCS + PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-foreign-unstable-v1.xml + BASENAME xdg-foreign-unstable-v1 +) + add_library(KF5WaylandServer ${SERVER_LIB_SRCS}) generate_export_header(KF5WaylandServer BASE_NAME @@ -210,6 +217,7 @@ textinput_interface.h touch_interface.h xdgshell_interface.h + xdgforeign_interface.h ) install(FILES diff --git a/src/server/display.h b/src/server/display.h --- a/src/server/display.h +++ b/src/server/display.h @@ -80,6 +80,7 @@ class PointerGesturesInterface; enum class PointerConstraintsInterfaceVersion; class PointerConstraintsInterface; +class XdgForeignUnstableInterface; /** * @brief Class holding the Wayland server display loop. @@ -219,6 +220,7 @@ **/ PointerConstraintsInterface *createPointerConstraints(const PointerConstraintsInterfaceVersion &version, QObject *parent = nullptr); + XdgForeignUnstableInterface *createXdgForeignUnstableInterface(QObject *parent = nullptr); /** * Gets the ClientConnection for the given @p client. * If there is no ClientConnection yet for the given @p client, it will be created. diff --git a/src/server/display.cpp b/src/server/display.cpp --- a/src/server/display.cpp +++ b/src/server/display.cpp @@ -44,6 +44,7 @@ #include "subcompositor_interface.h" #include "textinput_interface_p.h" #include "xdgshell_v5_interface_p.h" +#include "xdgforeign_interface.h" #include #include @@ -408,6 +409,13 @@ return p; } +XdgForeignUnstableInterface *Display::createXdgForeignUnstableInterface(QObject *parent) +{ + XdgForeignUnstableInterface *foreign = new XdgForeignUnstableInterface(this, parent); + connect(this, &Display::aboutToTerminate, foreign, [this,foreign] { delete foreign; }); + return foreign; +} + void Display::createShm() { Q_ASSERT(d->display); diff --git a/src/server/xdgforeign_interface.h b/src/server/xdgforeign_interface.h new file mode 100644 --- /dev/null +++ b/src/server/xdgforeign_interface.h @@ -0,0 +1,76 @@ +/**************************************************************************** +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#ifndef KWAYLAND_SERVER_XDGFOREIGN_H +#define KWAYLAND_SERVER_XDGFOREIGN_H + +#include "global.h" +#include "resource.h" + +#include + +namespace KWayland +{ +namespace Server +{ + +class Display; +class SurfaceInterface; +class XdgExporterUnstableV1Interface; +class XdgImporterUnstableV1Interface; + +class KWAYLANDSERVER_EXPORT XdgForeignUnstableInterface : public QObject +{ + Q_OBJECT +public: + XdgForeignUnstableInterface(Display *display, QObject *parent = nullptr); + ~XdgForeignUnstableInterface(); + + void create(); + bool isValid(); + + /** + * if a client did set + */ + SurfaceInterface *transientFor(SurfaceInterface *surface); + +Q_SIGNALS: + /** + * A surface got a new imported transient parent + * @param parent is the surface exported by one client and imported into another, which will act as parent. + * @param child is the surface that the importer client did set as child of the surface + * that it imported. + * If one of the two paramenters is nullptr, it means that a previously relation is not + * valid anymore and either one of the surfaces has been unmapped, or the parent surface + * is not exported anymore. + */ + void transientChanged(KWayland::Server::SurfaceInterface *child, KWayland::Server::SurfaceInterface *parent); + +private: + friend class Display; + friend class XdgExporterUnstableV1Interface; + friend class XdgImporterUnstableV1Interface; + class Private; + Private *d; +}; + +} +} + +#endif diff --git a/src/server/xdgforeign_interface.cpp b/src/server/xdgforeign_interface.cpp new file mode 100644 --- /dev/null +++ b/src/server/xdgforeign_interface.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ + +#include "xdgforeign_interface.h" +#include "xdgforeign_v1_interface_p.h" +#include "display.h" +#include "global_p.h" +#include "resource_p.h" +#include "surface_interface_p.h" + +#include "wayland-xdg-foreign-unstable-v1-server-protocol.h" + +#include +#include + +namespace KWayland +{ +namespace Server +{ + +XdgForeignUnstableInterface::Private::Private(Display *display, XdgForeignUnstableInterface *q) + : q(q) +{ + exporter = new XdgExporterUnstableV1Interface(display, q); + importer = new XdgImporterUnstableV1Interface(display, q); + + connect(importer, &XdgImporterUnstableV1Interface::transientChanged, + q, &XdgForeignUnstableInterface::transientChanged); +} + +XdgForeignUnstableInterface::XdgForeignUnstableInterface(Display *display, QObject *parent) + : QObject(parent), + d(new Private(display, this)) +{ +} + +XdgForeignUnstableInterface::~XdgForeignUnstableInterface() +{ + delete d->exporter; + delete d->importer; + delete d; +} + +void XdgForeignUnstableInterface::create() +{ + d->exporter->create(); + d->importer->create(); +} + +bool XdgForeignUnstableInterface::isValid() +{ + return d->exporter->isValid() && d->importer->isValid(); +} + +SurfaceInterface *XdgForeignUnstableInterface::transientFor(SurfaceInterface *surface) +{ + return d->importer->transientFor(surface); +} + +} +} + diff --git a/src/server/xdgforeign_v1_interface.cpp b/src/server/xdgforeign_v1_interface.cpp new file mode 100644 --- /dev/null +++ b/src/server/xdgforeign_v1_interface.cpp @@ -0,0 +1,459 @@ +/**************************************************************************** +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ + +#include "xdgforeign_interface.h" +#include "xdgforeign_v1_interface_p.h" +#include "display.h" +#include "global_p.h" +#include "resource_p.h" +#include "surface_interface_p.h" + +#include "wayland-xdg-foreign-unstable-v1-server-protocol.h" + +#include +#include + +namespace KWayland +{ +namespace Server +{ + +class Q_DECL_HIDDEN XdgExporterUnstableV1Interface::Private : public Global::Private +{ +public: + Private(XdgExporterUnstableV1Interface *q, Display *d, XdgForeignUnstableInterface *foreignInterface); + + XdgForeignUnstableInterface *foreignInterface; + QHash exportedSurfaces; + +private: + void bind(wl_client *client, uint32_t version, uint32_t id) override; + + static void unbind(wl_resource *resource); + static Private *cast(wl_resource *r) { + return reinterpret_cast(wl_resource_get_user_data(r)); + } + + static void destroyCallback(wl_client *client, wl_resource *resource); + static void exportCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface); + + XdgExporterUnstableV1Interface *q; + static const struct zxdg_exporter_v1_interface s_interface; + static const quint32 s_version; +}; + +const quint32 XdgExporterUnstableV1Interface::Private::s_version = 1; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zxdg_exporter_v1_interface XdgExporterUnstableV1Interface::Private::s_interface = { + destroyCallback, + exportCallback +}; +#endif + +XdgExporterUnstableV1Interface::XdgExporterUnstableV1Interface(Display *display, XdgForeignUnstableInterface *parent) + : Global(new Private(this, display, parent), parent) +{ +} + +XdgExporterUnstableV1Interface::~XdgExporterUnstableV1Interface() +{} + +XdgExporterUnstableV1Interface::Private *XdgExporterUnstableV1Interface::d_func() const +{ + return reinterpret_cast(d.data()); +} + +XdgExportedUnstableV1Interface *XdgExporterUnstableV1Interface::exportedSurface(const QString &handle) +{ + Q_D(); + + auto it = d->exportedSurfaces.constFind(handle); + if (it != d->exportedSurfaces.constEnd()) { + return it.value(); + } + return nullptr; +} + +void XdgExporterUnstableV1Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) +} + +void XdgExporterUnstableV1Interface::Private::exportCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface) +{ + auto s = cast(resource); + QPointer e = new XdgExportedUnstableV1Interface(s->q, surface); + + e->create(s->display->getConnection(client), wl_resource_get_version(resource), id); + + if (!e->resource()) { + wl_resource_post_no_memory(resource); + delete e; + return; + } + + const QString handle = QUuid::createUuid().toString(); + + //a surface not exported anymore + connect(e.data(), &XdgExportedUnstableV1Interface::unbound, + s->q, [s, handle]() { + s->exportedSurfaces.remove(handle); + emit s->q->surfaceUnexported(handle); + }); + + //if the surface dies before this, this dies too + connect(SurfaceInterface::get(surface), &Resource::unbound, + s->q, [s, e, handle]() { + if (e) { + e->deleteLater(); + } + s->exportedSurfaces.remove(handle); + emit s->q->surfaceUnexported(handle); + }); + + s->exportedSurfaces[handle] = e; + zxdg_exported_v1_send_handle(e->resource(), handle.toUtf8().constData()); + emit s->q->surfaceExported(handle, e); +} + +XdgExporterUnstableV1Interface::Private::Private(XdgExporterUnstableV1Interface *q, Display *d,XdgForeignUnstableInterface *foreignInterface) + : Global::Private(d, &zxdg_exporter_v1_interface, s_version) + , foreignInterface(foreignInterface) + , q(q) +{ +} + +void XdgExporterUnstableV1Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id) +{ + auto c = display->getConnection(client); + wl_resource *resource = c->createResource(&zxdg_exporter_v1_interface, qMin(version, s_version), id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &s_interface, this, unbind); + // TODO: should we track? +} + +void XdgExporterUnstableV1Interface::Private::unbind(wl_resource *resource) +{ + Q_UNUSED(resource) + // TODO: implement? +} + +class Q_DECL_HIDDEN XdgImporterUnstableV1Interface::Private : public Global::Private +{ +public: + Private(XdgImporterUnstableV1Interface *q, Display *d, XdgForeignUnstableInterface *foreignInterface); + + XdgForeignUnstableInterface *foreignInterface; + + QHash importedSurfaces; + + //child->parent hash + QHash parents; + //parent->child hash + QHash children; + +private: + void bind(wl_client *client, uint32_t version, uint32_t id) override; + + static void unbind(wl_resource *resource); + static Private *cast(wl_resource *r) { + return reinterpret_cast(wl_resource_get_user_data(r)); + } + + static void destroyCallback(wl_client *client, wl_resource *resource); + static void importCallback(wl_client *client, wl_resource *resource, uint32_t id, const char * handle); + + XdgImporterUnstableV1Interface *q; + static const struct zxdg_importer_v1_interface s_interface; + static const quint32 s_version; +}; + +const quint32 XdgImporterUnstableV1Interface::Private::s_version = 1; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zxdg_importer_v1_interface XdgImporterUnstableV1Interface::Private::s_interface = { + destroyCallback, + importCallback +}; +#endif + +XdgImporterUnstableV1Interface::XdgImporterUnstableV1Interface(Display *display, XdgForeignUnstableInterface *parent) + : Global(new Private(this, display, parent), parent) +{ +} + +XdgImporterUnstableV1Interface::~XdgImporterUnstableV1Interface() +{ +} + +XdgImportedUnstableV1Interface *XdgImporterUnstableV1Interface::importedSurface(const QString &handle) +{ + Q_D(); + + auto it = d->importedSurfaces.constFind(handle); + if (it != d->importedSurfaces.constEnd()) { + return it.value(); + } + return nullptr; +} + +SurfaceInterface *XdgImporterUnstableV1Interface::transientFor(SurfaceInterface *surface) +{ + Q_D(); + + auto it = d->parents.constFind(surface); + if (it == d->parents.constEnd()) { + return nullptr; + } + return SurfaceInterface::get((*it)->parentResource()); +} + +XdgImporterUnstableV1Interface::Private *XdgImporterUnstableV1Interface::d_func() const +{ + return reinterpret_cast(d.data()); +} + +void XdgImporterUnstableV1Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) +} + +void XdgImporterUnstableV1Interface::Private::importCallback(wl_client *client, wl_resource *resource, uint32_t id, const char * handle) +{ + auto s = cast(resource); + + Q_ASSERT(s->foreignInterface); + + XdgExportedUnstableV1Interface *exp = s->foreignInterface->d->exporter->exportedSurface(QString::fromUtf8(handle)); + if (!exp) { + zxdg_imported_v1_send_destroyed(resource); + return; + } + + wl_resource *surface = exp->parentResource(); + if (!surface) { + zxdg_imported_v1_send_destroyed(resource); + return; + } + + QPointer imp = new XdgImportedUnstableV1Interface(s->q, surface); + imp->create(s->display->getConnection(client), wl_resource_get_version(resource), id); + + //surface no longer exported + connect(exp, &XdgExportedUnstableV1Interface::unbound, + s->q, [s, imp, handle]() { + //imp valid when the exported is deleted before the imported + if (imp) { + zxdg_imported_v1_send_destroyed(imp->resource()); + imp->deleteLater(); + } + s->importedSurfaces.remove(QString::fromUtf8(handle)); + emit s->q->surfaceUnimported(QString::fromUtf8(handle)); + }); + + connect(imp.data(), &XdgImportedUnstableV1Interface::childChanged, + s->q, [s, imp](SurfaceInterface *child) { + //remove any previous association + auto it = s->children.find(imp); + if (it != s->children.end()) { + s->parents.remove(*it); + s->children.erase(it); + } + + s->parents[child] = imp; + s->children[imp] = child; + SurfaceInterface *parent = SurfaceInterface::get(imp->parentResource()); + emit s->q->transientChanged(child, parent); + + //child surface destroyed + connect(child, &Resource::unbound, + s->q, [s, child]() { + auto it = s->parents.find(child); + if (it != s->parents.end()) { + s->children.remove(*it); + s->parents.erase(it); + emit s->q->transientChanged(nullptr, SurfaceInterface::get((*it)->parentResource())); + } + }); + }); + + //surface no longer imported + connect(imp.data(), &XdgImportedUnstableV1Interface::unbound, + s->q, [s, handle, imp]() { + s->importedSurfaces.remove(QString::fromUtf8(handle)); + emit s->q->surfaceUnimported(QString::fromUtf8(handle)); + + auto it = s->children.find(imp); + if (it != s->children.end()) { + s->parents.remove(*it); + s->children.erase(it); + emit s->q->transientChanged(*it, nullptr); + } + }); + + if (!imp->resource()) { + wl_resource_post_no_memory(resource); + delete imp; + return; + } + + s->importedSurfaces[QString::fromUtf8(handle)] = imp; + emit s->q->surfaceImported(QString::fromUtf8(handle), imp); +} + +XdgImporterUnstableV1Interface::Private::Private(XdgImporterUnstableV1Interface *q, Display *d, XdgForeignUnstableInterface *foreignInterface) + : Global::Private(d, &zxdg_importer_v1_interface, s_version) + , foreignInterface(foreignInterface) + , q(q) +{ +} + +void XdgImporterUnstableV1Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id) +{ + auto c = display->getConnection(client); + wl_resource *resource = c->createResource(&zxdg_importer_v1_interface, qMin(version, s_version), id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &s_interface, this, unbind); + // TODO: should we track? +} + +void XdgImporterUnstableV1Interface::Private::unbind(wl_resource *resource) +{ + Q_UNUSED(resource) + // TODO: implement? +} + +class Q_DECL_HIDDEN XdgExportedUnstableV1Interface::Private : public Resource::Private +{ +public: + Private(XdgExportedUnstableV1Interface *q, XdgExporterUnstableV1Interface *c, wl_resource *parentResource); + ~Private(); + +private: + + XdgExportedUnstableV1Interface *q_func() { + return reinterpret_cast(q); + } + + static const struct zxdg_exported_v1_interface s_interface; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zxdg_exported_v1_interface XdgExportedUnstableV1Interface::Private::s_interface = { + resourceDestroyedCallback +}; +#endif + +XdgExportedUnstableV1Interface::XdgExportedUnstableV1Interface(XdgExporterUnstableV1Interface *parent, wl_resource *parentResource) + : Resource(new Private(this, parent, parentResource)) +{ +} + +XdgExportedUnstableV1Interface::~XdgExportedUnstableV1Interface() +{} + +XdgExportedUnstableV1Interface::Private *XdgExportedUnstableV1Interface::d_func() const +{ + return reinterpret_cast(d.data()); +} + +XdgExportedUnstableV1Interface::Private::Private(XdgExportedUnstableV1Interface *q, XdgExporterUnstableV1Interface *c, wl_resource *parentResource) + : Resource::Private(q, c, parentResource, &zxdg_exported_v1_interface, &s_interface) +{ +} + +XdgExportedUnstableV1Interface::Private::~Private() +{} + +class Q_DECL_HIDDEN XdgImportedUnstableV1Interface::Private : public Resource::Private +{ +public: + Private(XdgImportedUnstableV1Interface *q, XdgImporterUnstableV1Interface *c, wl_resource *parentResource); + ~Private(); + + QPointer parentOf; + +private: + static void setParentOfCallback(wl_client *client, wl_resource *resource, wl_resource * surface); + + XdgImportedUnstableV1Interface *q_func() { + return reinterpret_cast(q); + } + + static const struct zxdg_imported_v1_interface s_interface; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zxdg_imported_v1_interface XdgImportedUnstableV1Interface::Private::s_interface = { + resourceDestroyedCallback, + setParentOfCallback +}; +#endif + +XdgImportedUnstableV1Interface::XdgImportedUnstableV1Interface(XdgImporterUnstableV1Interface *parent, wl_resource *parentResource) + : Resource(new Private(this, parent, parentResource)) +{ +} + +XdgImportedUnstableV1Interface::~XdgImportedUnstableV1Interface() +{} + +XdgImportedUnstableV1Interface::Private *XdgImportedUnstableV1Interface::d_func() const +{ + return reinterpret_cast(d.data()); +} + +SurfaceInterface *XdgImportedUnstableV1Interface::child() const +{ + Q_D(); + return d->parentOf.data(); +} + +void XdgImportedUnstableV1Interface::Private::setParentOfCallback(wl_client *client, wl_resource *resource, wl_resource * surface) +{ + auto s = cast(resource); + SurfaceInterface *surf = SurfaceInterface::get(surface); + + if (!surf) { + return; + } + + s->parentOf = surf; + emit s->q_func()->childChanged(surf); +} + +XdgImportedUnstableV1Interface::Private::Private(XdgImportedUnstableV1Interface *q, XdgImporterUnstableV1Interface *c, wl_resource *parentResource) + : Resource::Private(q, c, parentResource, &zxdg_imported_v1_interface, &s_interface) +{ +} + +XdgImportedUnstableV1Interface::Private::~Private() +{} + +} +} + diff --git a/src/server/xdgforeign_v1_interface_p.h b/src/server/xdgforeign_v1_interface_p.h new file mode 100644 --- /dev/null +++ b/src/server/xdgforeign_v1_interface_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +Copyright 2017 Marco Martin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#ifndef KWAYLAND_SERVER_XDGFOREIGNV1_P_H +#define KWAYLAND_SERVER_XDGFOREIGNV1_P_H + +#include "global.h" +#include "resource.h" + +namespace KWayland +{ +namespace Server +{ + +class Display; +class SurfaceInterface; +class XdgExportedUnstableV1Interface; +class XdgImportedUnstableV1Interface; + +class Q_DECL_HIDDEN XdgForeignUnstableInterface::Private +{ +public: + Private(Display *display, XdgForeignUnstableInterface *q); + + XdgForeignUnstableInterface *q; + XdgExporterUnstableV1Interface *exporter; + XdgImporterUnstableV1Interface *importer; +}; + +class Q_DECL_HIDDEN XdgExporterUnstableV1Interface : public Global +{ + Q_OBJECT +public: + virtual ~XdgExporterUnstableV1Interface(); + + XdgExportedUnstableV1Interface *exportedSurface(const QString &handle); + +Q_SIGNALS: + void surfaceExported(const QString &handle, XdgExportedUnstableV1Interface *exported); + void surfaceUnexported(const QString &handle); + +private: + explicit XdgExporterUnstableV1Interface(Display *display, XdgForeignUnstableInterface *parent = nullptr); + friend class Display; + friend class XdgForeignUnstableInterface; + class Private; + Private *d_func() const; +}; + +class Q_DECL_HIDDEN XdgImporterUnstableV1Interface : public Global +{ + Q_OBJECT +public: + virtual ~XdgImporterUnstableV1Interface(); + + XdgImportedUnstableV1Interface *importedSurface(const QString &handle); + SurfaceInterface *transientFor(SurfaceInterface *surface); + +Q_SIGNALS: + void surfaceImported(const QString &handle, XdgImportedUnstableV1Interface *imported); + void surfaceUnimported(const QString &handle); + void transientChanged(KWayland::Server::SurfaceInterface *child, KWayland::Server::SurfaceInterface *parent); + +private: + explicit XdgImporterUnstableV1Interface(Display *display, XdgForeignUnstableInterface *parent = nullptr); + friend class Display; + friend class XdgForeignUnstableInterface; + class Private; + Private *d_func() const; +}; + +class Q_DECL_HIDDEN XdgExportedUnstableV1Interface : public Resource +{ + Q_OBJECT +public: + virtual ~XdgExportedUnstableV1Interface(); + +private: + explicit XdgExportedUnstableV1Interface(XdgExporterUnstableV1Interface *parent, wl_resource *parentResource); + friend class XdgExporterUnstableV1Interface; + + class Private; + Private *d_func() const; +}; + +class Q_DECL_HIDDEN XdgImportedUnstableV1Interface : public Resource +{ + Q_OBJECT +public: + virtual ~XdgImportedUnstableV1Interface(); + + SurfaceInterface *child() const; + +Q_SIGNALS: + void childChanged(KWayland::Server::SurfaceInterface *child); + +private: + explicit XdgImportedUnstableV1Interface(XdgImporterUnstableV1Interface *parent, wl_resource *parentResource); + friend class XdgImporterUnstableV1Interface; + + class Private; + Private *d_func() const; +}; + +} +} + +#endif