diff --git a/autotests/client/CMakeLists.txt b/autotests/client/CMakeLists.txt --- a/autotests/client/CMakeLists.txt +++ b/autotests/client/CMakeLists.txt @@ -463,3 +463,14 @@ add_test(NAME kwayland-testXdgOutput COMMAND testXdgOutput) ecm_mark_as_test(testXdgOutput) +######################################################## +# Test XDG Decoration +######################################################## +set( testXdgdecoration_SRCS + test_xdg_decoration.cpp + ) +add_executable(testXdgDecoration ${testXdgdecoration_SRCS}) +target_link_libraries( testXdgDecoration Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client Wayland::Server) +add_test(NAME kwayland-testXdgDecoration COMMAND testXdgDecoration) +ecm_mark_as_test(testXdgDecoration) + diff --git a/autotests/client/test_xdg_decoration.cpp b/autotests/client/test_xdg_decoration.cpp new file mode 100644 --- /dev/null +++ b/autotests/client/test_xdg_decoration.cpp @@ -0,0 +1,250 @@ +/******************************************************************** +Copyright 2018 David Edmundson + +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/registry.h" +#include "../../src/client/xdgshell.h" +#include "../../src/client/xdgdecoration.h" +#include "../../src/client/surface.h" +#include "../../src/server/display.h" +#include "../../src/server/compositor_interface.h" +#include "../../src/server/xdgshell_interface.h" +#include "../../src/server/xdgdecoration_interface.h" + +class TestXdgDecoration : public QObject +{ + Q_OBJECT +public: + explicit TestXdgDecoration(QObject *parent = nullptr); +private Q_SLOTS: + void init(); + void cleanup(); + + void testDecoration_data(); + void testDecoration(); + +private: + KWayland::Server::Display *m_display = nullptr; + KWayland::Server::CompositorInterface *m_compositorInterface = nullptr; + KWayland::Server::XdgShellInterface *m_xdgShellInterface = nullptr; + KWayland::Server::XdgDecorationManagerInterface *m_xdgDecorationManagerInterface = nullptr; + + KWayland::Client::ConnectionThread *m_connection = nullptr; + KWayland::Client::Compositor *m_compositor = nullptr; + KWayland::Client::EventQueue *m_queue = nullptr; + KWayland::Client::XdgShell *m_xdgShell = nullptr; + KWayland::Client::XdgDecorationManager *m_xdgDecorationManager = nullptr; + + QThread *m_thread = nullptr; + KWayland::Client::Registry *m_registry = nullptr; +}; + +static const QString s_socketName = QStringLiteral("kwayland-test-wayland-server-side-decoration-0"); + +TestXdgDecoration::TestXdgDecoration(QObject *parent) + : QObject(parent) +{ +} + +void TestXdgDecoration::init() +{ + using namespace KWayland::Server; + using namespace KWayland::Client; + + qRegisterMetaType(); + qRegisterMetaType(); + + delete m_display; + m_display = new Display(this); + m_display->setSocketName(s_socketName); + m_display->start(); + QVERIFY(m_display->isRunning()); + + // 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 EventQueue(this); + QVERIFY(!m_queue->isValid()); + m_queue->setup(m_connection); + QVERIFY(m_queue->isValid()); + + m_registry = new Registry(); + QSignalSpy compositorSpy(m_registry, &Registry::compositorAnnounced); + QSignalSpy xdgShellSpy(m_registry, &Registry::xdgShellStableAnnounced); + QSignalSpy xdgDecorationManagerSpy(m_registry, &Registry::xdgDecorationAnnounced); + + QVERIFY(!m_registry->eventQueue()); + m_registry->setEventQueue(m_queue); + QCOMPARE(m_registry->eventQueue(), m_queue); + m_registry->create(m_connection); + QVERIFY(m_registry->isValid()); + m_registry->setup(); + + m_compositorInterface = m_display->createCompositor(m_display); + m_compositorInterface->create(); + QVERIFY(m_compositorInterface->isValid()); + + QVERIFY(compositorSpy.wait()); + m_compositor = m_registry->createCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value(), this); + + m_xdgShellInterface = m_display->createXdgShell(XdgShellInterfaceVersion::Stable, m_display); + m_xdgShellInterface->create(); + QVERIFY(m_xdgShellInterface->isValid()); + QVERIFY(xdgShellSpy.wait()); + m_xdgShell = m_registry->createXdgShell(xdgShellSpy.first().first().value(), + xdgShellSpy.first().last().value(), this); + + m_xdgDecorationManagerInterface = m_display->createXdgDecorationManager(m_xdgShellInterface, m_display); + m_xdgDecorationManagerInterface->create(); + QVERIFY(m_xdgDecorationManagerInterface->isValid()); + + QVERIFY(xdgDecorationManagerSpy.wait()); + m_xdgDecorationManager = m_registry->createXdgDecorationManager(xdgDecorationManagerSpy.first().first().value(), + xdgDecorationManagerSpy.first().last().value(), this); +} + +void TestXdgDecoration::cleanup() +{ + if (m_compositor) { + delete m_compositor; + m_compositor = nullptr; + } + if (m_xdgShell) { + delete m_xdgShell; + m_xdgShell = nullptr; + } + if (m_xdgDecorationManager) { + delete m_xdgDecorationManager; + m_xdgDecorationManager = nullptr; + } + if (m_queue) { + delete m_queue; + m_queue = nullptr; + } + if (m_registry) { + delete m_registry; + m_registry = nullptr; + } + if (m_thread) { + m_thread->quit(); + m_thread->wait(); + delete m_thread; + m_thread = nullptr; + } + delete m_connection; + m_connection = nullptr; + + delete m_display; + m_display = nullptr; +} + + +void TestXdgDecoration::testDecoration_data() +{ + using namespace KWayland::Client; + using namespace KWayland::Server; + QTest::addColumn("configuredMode"); + QTest::addColumn("configuredModeExp"); + QTest::addColumn("setMode"); + QTest::addColumn("setModeExp"); + + const auto serverClient = XdgDecorationInterface::Mode::ClientSide; + const auto serverServer = XdgDecorationInterface::Mode::ServerSide; + const auto clientClient = XdgDecoration::Mode::ClientSide; + const auto clientServer = XdgDecoration::Mode::ServerSide; + + QTest::newRow("client->client") << serverClient << clientClient << clientClient << serverClient; + QTest::newRow("client->server") << serverClient << clientClient << clientServer << serverServer; + QTest::newRow("server->client") << serverServer << clientServer << clientClient << serverClient; + QTest::newRow("server->server") << serverServer << clientServer << clientServer << serverServer; +} + +void TestXdgDecoration::testDecoration() +{ + using namespace KWayland::Client; + using namespace KWayland::Server; + + QFETCH(KWayland::Server::XdgDecorationInterface::Mode, configuredMode); + QFETCH(KWayland::Client::XdgDecoration::Mode, configuredModeExp); + QFETCH(KWayland::Client::XdgDecoration::Mode, setMode); + QFETCH(KWayland::Server::XdgDecorationInterface::Mode, setModeExp); + + + QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); + QSignalSpy shellSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); + QSignalSpy decorationCreatedSpy(m_xdgDecorationManagerInterface, &XdgDecorationManagerInterface::xdgDecorationInterfaceCreated); + + // create shell surface and deco object + QScopedPointer surface(m_compositor->createSurface()); + QScopedPointer shellSurface(m_xdgShell->createSurface(surface.data())); + QScopedPointer decoration(m_xdgDecorationManager->getToplevelDecoration(shellSurface.data())); + + //and receive all these on the "server" + QVERIFY(surfaceCreatedSpy.count() || surfaceCreatedSpy.wait()); + QVERIFY(shellSurfaceCreatedSpy.count() || shellSurfaceCreatedSpy.wait()); + QVERIFY(decorationCreatedSpy.count() || decorationCreatedSpy.wait()); + + auto shellSurfaceIface = shellSurfaceCreatedSpy.first().first().value(); + auto decorationIface = decorationCreatedSpy.first().first().value(); + + QVERIFY(decorationIface); + QVERIFY(shellSurfaceIface); + QCOMPARE(decorationIface->surface(), shellSurfaceIface); + QCOMPARE(decorationIface->requestedMode(), XdgDecorationInterface::Mode::Undefined); + + QSignalSpy clientConfiguredSpy(decoration.data(), &XdgDecoration::modeChanged); + QSignalSpy modeRequestedSpy(decorationIface, &XdgDecorationInterface::modeRequested); + + //server configuring a client + decorationIface->configure(configuredMode); + quint32 serial = shellSurfaceIface->configure({}); + QVERIFY(clientConfiguredSpy.wait()); + QCOMPARE(clientConfiguredSpy.first().first().value(), configuredModeExp); + + shellSurface->ackConfigure(serial); + + //client requesting another mode + decoration->setMode(setMode); + QVERIFY(modeRequestedSpy.wait()); + QCOMPARE(modeRequestedSpy.first().first().value(), setModeExp); + QCOMPARE(decorationIface->requestedMode(), setModeExp); + modeRequestedSpy.clear(); + + decoration->unsetMode(); + QVERIFY(modeRequestedSpy.wait()); + QCOMPARE(modeRequestedSpy.first().first().value(), XdgDecorationInterface::Mode::Undefined); +} + +QTEST_GUILESS_MAIN(TestXdgDecoration) +#include "test_xdg_decoration.moc" diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -52,6 +52,7 @@ textinput.cpp textinput_v0.cpp textinput_v2.cpp + xdgdecoration.cpp xdgshell.cpp xdgforeign_v2.cpp xdgforeign.cpp @@ -183,6 +184,11 @@ BASENAME xdg-shell ) +ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS + PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-decoration-unstable-v1.xml + BASENAME xdg-decoration-unstable-v1 +) + set(CLIENT_GENERATED_FILES ${CMAKE_CURRENT_BINARY_DIR}/wayland-fullscreen-shell-client-protocol.h @@ -209,6 +215,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-foreign-unstable-v2-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-idle-inhibit-unstable-v1-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-output-unstable-v1-client-protocol.h + ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-decoration-unstable-v1-client-protocol.h ) set_source_files_properties(${CLIENT_GENERATED_FILES} PROPERTIES SKIP_AUTOMOC ON) @@ -288,6 +295,7 @@ surface.h touch.h textinput.h + xdgdecoration.h xdgshell.h xdgforeign.h xdgoutput.h diff --git a/src/client/protocols/xdg-decoration-unstable-v1.xml b/src/client/protocols/xdg-decoration-unstable-v1.xml new file mode 100644 --- /dev/null +++ b/src/client/protocols/xdg-decoration-unstable-v1.xml @@ -0,0 +1,156 @@ + + + + Copyright © 2018 Simon Ser + + 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 interface allows a compositor to announce support for server-side + decorations. + + A window decoration is a set of window controls as deemed appropriate by + the party managing them, such as user interface components used to move, + resize and change a window's state. + + A client can use this protocol to request being decorated by a supporting + compositor. + + If compositor and client do not negotiate the use of a server-side + decoration using this protocol, clients continue to self-decorate as they + see fit. + + 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. + + + + + Destroy the decoration manager. This doesn't destroy objects created + with the manager. + + + + + + Create a new decoration object associated with the given toplevel. + + Creating an xdg_toplevel_decoration from an xdg_toplevel which has a + buffer attached or committed is a client error, and any attempts by a + client to attach or manipulate a buffer prior to the first + xdg_toplevel_decoration.configure event must also be treated as + errors. + + + + + + + + + The decoration object allows the compositor to toggle server-side window + decorations for a toplevel surface. The client can request to switch to + another mode. + + The xdg_toplevel_decoration object must be destroyed before its + xdg_toplevel. + + + + + + + + + + + Switch back to a mode without any server-side decorations at the next + commit. + + + + + + These values describe window decoration modes. + + + + + + + + Set the toplevel surface decoration mode. This informs the compositor + that the client prefers the provided decoration mode. + + After requesting a decoration mode, the compositor will respond by + emitting a xdg_surface.configure event. The client should then update + its content, drawing it without decorations if the received mode is + server-side decorations. The client must also acknowledge the configure + when committing the new content (see xdg_surface.ack_configure). + + The compositor can decide not to use the client's mode and enforce a + different mode instead. + + Clients whose decoration mode depend on the xdg_toplevel state may send + a set_mode request in response to a xdg_surface.configure event and wait + for the next xdg_surface.configure event to prevent unwanted state. + Such clients are responsible for preventing configure loops and must + make sure not to send multiple successive set_mode requests with the + same decoration mode. + + + + + + + Unset the toplevel surface decoration mode. This informs the compositor + that the client doesn't prefer a particular decoration mode. + + This request has the same semantics as set_mode. + + + + + + The configure event asks the client to change its decoration mode. The + configured state should not be applied immediately. Clients must send an + ack_configure in response to this event. See xdg_surface.configure and + xdg_surface.ack_configure for details. + + A configure event can be sent at any time. The specified mode must be + obeyed by the client. + + + + + diff --git a/src/client/registry.h b/src/client/registry.h --- a/src/client/registry.h +++ b/src/client/registry.h @@ -1,5 +1,6 @@ /******************************************************************** Copyright 2014 Martin Gräßlin +Copyright 2018 David Edmundson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -63,6 +64,7 @@ struct zxdg_importer_v2; struct zwp_idle_inhibit_manager_v1; struct zxdg_output_manager_v1; +struct zxdg_decoration_manager_v1; namespace KWayland { @@ -108,6 +110,7 @@ class XdgExporter; class XdgImporter; class XdgOutputManager; +class XdgDecorationManager; /** * @short Wrapper for the wl_registry interface. @@ -180,7 +183,8 @@ RemoteAccessManager, ///< Refers to org_kde_kwin_remote_access_manager interface, @since 5.45 PlasmaVirtualDesktopManagement, ///< Refers to org_kde_plasma_virtual_desktop_management interface @since 5.52 XdgOutputUnstableV1, ///refers to zxdg_output_v1, @since 5.47 - XdgShellStable ///refers to xdg_wm_base @since 5.48 + XdgShellStable, ///refers to xdg_wm_base @since 5.48 + XdgDecorationUnstableV1, ///refers to zxdg_decoration_manager_v1, @since 5.XDG_DECO_VERSION }; explicit Registry(QObject *parent = nullptr); virtual ~Registry(); @@ -651,6 +655,17 @@ **/ zxdg_output_manager_v1 *bindXdgOutputUnstableV1(uint32_t name, uint32_t version) const; + /** + * Binds the zxdg_decoration_manager_v1 with @p name and @p version. + * If the @p name does not exist, + * @c null will be returned. + * + * Prefer using createXdgDecorationManager instead. + * @see createXdgDecorationManager + * @since 5.XDG_DECO_VERSION + **/ + zxdg_decoration_manager_v1 *bindXdgDecorationUnstableV1(uint32_t name, uint32_t version) const; + ///@} /** @@ -1190,6 +1205,23 @@ **/ XdgOutputManager *createXdgOutputManager(quint32 name, quint32 version, QObject *parent = nullptr); + /** + * Creates an XdgDecorationManager and sets it up to manage the interface identified by + * @p name and @p version. + * + * Note: in case @p name is invalid or isn't for the zxdg_decoration_manager_v1 interface, + * the returned XdgDecorationManager will not be valid. Therefore it's recommended to call + * isValid on the created instance. + * + * @param name The name of the zxdg_decoration_manager_v1 interface to bind + * @param version The version or the zxdg_decoration_manager_v1 interface to use + * @param parent The parent for XdgDecorationManager + * + * @returns The created XdgDecorationManager. + * @since 5.XDG_DECO_VERSION + **/ + XdgDecorationManager *createXdgDecorationManager(quint32 name, quint32 version, QObject *parent = nullptr); + ///@} @@ -1459,6 +1491,13 @@ **/ void xdgShellStableAnnounced(quint32 name, quint32 version); + /** + * Emitted whenever a zxdg_decoration_manager_v1 interface gets announced. + * @param name The name for the announced interface + * @param version The maximum supported version of the announced interface + * @since 5.XDG_DECO_VERSION + **/ + void xdgDecorationAnnounced(quint32 name, quint32 version); ///@} @@ -1681,6 +1720,13 @@ **/ void xdgShellStableRemoved(quint32 name); + /** + * Emitted whenever a zxdg_decoration_manager_v1 gets removed. + * @param name The name of the removed interface + * @since 5.XDG_DECO_VERSION + **/ + void xdgDecorationRemoved(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 @@ -1,5 +1,6 @@ /******************************************************************** Copyright 2014 Martin Gräßlin +Copyright 2018 David Edmundson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -56,6 +57,7 @@ #include "appmenu.h" #include "server_decoration_palette.h" #include "xdgoutput.h" +#include "xdgdecoration.h" // Qt #include // wayland @@ -88,6 +90,7 @@ #include #include #include +#include /***** * How to add another interface: @@ -367,6 +370,13 @@ &xdg_wm_base_interface, &Registry::xdgShellStableAnnounced, &Registry::xdgShellStableRemoved + }}, + {Registry::Interface::XdgDecorationUnstableV1, { + 1, + QByteArrayLiteral("zxdg_decoration_manager_v1"), + &zxdg_decoration_manager_v1_interface, + &Registry::xdgDecorationAnnounced, + &Registry::xdgDecorationRemoved }} }; @@ -682,6 +692,7 @@ BIND2(AppMenuManager, AppMenu, org_kde_kwin_appmenu_manager) BIND2(ServerSideDecorationPaletteManager, ServerSideDecorationPalette, org_kde_kwin_server_decoration_palette_manager) BIND(XdgOutputUnstableV1, zxdg_output_manager_v1) +BIND(XdgDecorationUnstableV1, zxdg_decoration_manager_v1) #undef BIND #undef BIND2 @@ -827,6 +838,16 @@ } } +XdgDecorationManager *Registry::createXdgDecorationManager(quint32 name, quint32 version, QObject *parent) +{ + switch(d->interfaceForName(name)) { + case Interface::XdgDecorationUnstableV1: + return d->create(name, version, parent, &Registry::bindXdgDecorationUnstableV1); + default: + return nullptr; + } +} + namespace { static const wl_interface *wlInterface(Registry::Interface interface) { diff --git a/src/client/xdgdecoration.h b/src/client/xdgdecoration.h new file mode 100644 --- /dev/null +++ b/src/client/xdgdecoration.h @@ -0,0 +1,219 @@ +/**************************************************************************** +Copyright 2018 David Edmundson + +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_XDG_DECORATION_UNSTABLE_V1_H +#define KWAYLAND_CLIENT_XDG_DECORATION_UNSTABLE_V1_H + +#include + +#include + +struct zxdg_decoration_manager_v1; +struct zxdg_toplevel_decoration_v1; + +namespace KWayland +{ +namespace Client +{ + +class EventQueue; +class XdgDecoration; +class XdgShellSurface; + +/** + * @short Wrapper for the zxdg_decoration_manager_v1 interface. + * + * This class provides a convenient wrapper for the zxdg_decoration_manager_v1 interface. + * + * To use this class one needs to interact with the Registry. There are two + * possible ways to create the XdgDecorationManager interface: + * @code + * XdgDecorationManager *c = registry->createXdgDecorationManager(name, version); + * @endcode + * + * This creates the XdgDecorationManager and sets it up directly. As an alternative this + * can also be done in a more low level way: + * @code + * XdgDecorationManager *c = new XdgDecorationManager; + * c->setup(registry->bindXdgDecorationManager(name, version)); + * @endcode + * + * The XdgDecorationManager can be used as a drop-in replacement for any zxdg_decoration_manager_v1 + * pointer as it provides matching cast operators. + * + * If you use the QtWayland QPA you do not need to use this class. + * + * @see Registry + **/ +class KWAYLANDCLIENT_EXPORT XdgDecorationManager : public QObject +{ + Q_OBJECT +public: + /** + * Creates a new XdgDecorationManager. + * Note: after constructing the XdgDecorationManager it is not yet valid and one needs + * to call setup. In order to get a ready to use XdgDecorationManager prefer using + * Registry::createXdgDecorationManager. + **/ + explicit XdgDecorationManager(QObject *parent = nullptr); + virtual ~XdgDecorationManager(); + + /** + * Setup this XdgDecorationManager to manage the @p xdgdecorationmanager. + * When using Registry::createXdgDecorationManager there is no need to call this + * method. + **/ + void setup(zxdg_decoration_manager_v1 *xdgdecorationmanager); + /** + * @returns @c true if managing a zxdg_decoration_manager_v1. + **/ + bool isValid() const; + /** + * Releases the zxdg_decoration_manager_v1 interface. + * After the interface has been released the XdgDecorationManager instance is no + * longer valid and can be setup with another zxdg_decoration_manager_v1 interface. + **/ + void release(); + /** + * Destroys the data held by this XdgDecorationManager. + * 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_decoration_manager_v1 interface + * once there is a new connection available. + * + * It is suggested to connect this method to ConnectionThread::connectionDied: + * @code + * connect(connection, &ConnectionThread::connectionDied, xdgdecorationmanager, &XdgDecorationManager::destroy); + * @endcode + * + * @see release + **/ + void destroy(); + + /** + * Sets the @p queue to use for creating objects with this XdgDecorationManager. + **/ + void setEventQueue(EventQueue *queue); + /** + * @returns The event queue to use for creating objects with this XdgDecorationManager. + **/ + EventQueue *eventQueue(); + + XdgDecoration *getToplevelDecoration(XdgShellSurface *toplevel, QObject *parent = nullptr); + + operator zxdg_decoration_manager_v1*(); + operator zxdg_decoration_manager_v1*() const; + +Q_SIGNALS: + /** + * The corresponding global for this interface on the Registry got removed. + * + * This signal gets only emitted if the XdgDecorationManager got created by + * Registry::createXdgDecorationManager + **/ + void removed(); + +private: + class Private; + QScopedPointer d; +}; + +class KWAYLANDCLIENT_EXPORT XdgDecoration : public QObject +{ + Q_OBJECT +public: + enum class Mode { + ClientSide, + ServerSide + }; + + Q_ENUM(Mode) + + virtual ~XdgDecoration(); + + /** + * Setup this XdgDecoration to manage the @p xdgdecoration. + * When using XdgDecorationManager::createXdgDecoration there is no need to call this + * method. + **/ + void setup(zxdg_toplevel_decoration_v1 *xdgdecoration); + /** + * @returns @c true if managing a zxdg_toplevel_decoration_v1. + **/ + bool isValid() const; + /** + * Releases the zxdg_toplevel_decoration_v1 interface. + * After the interface has been released the XdgDecoration instance is no + * longer valid and can be setup with another zxdg_toplevel_decoration_v1 interface. + **/ + void release(); + /** + * Destroys the data held by this XdgDecoration. + * 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_toplevel_decoration_v1 interface + * once there is a new connection available. + * + * It is suggested to connect this method to ConnectionThread::connectionDied: + * @code + * connect(connection, &ConnectionThread::connectionDied, xdgdecoration, &XdgDecoration::destroy); + * @endcode + * + * @see release + **/ + void destroy(); + + /** + * @brief Request that the server puts us in a given mode. The compositor will respond with a modeChange + * The compositor may ignore this request. + */ + void setMode(Mode mode); + + /** + * @brief Unset our requested mode. The compositor can then configure this surface with the default mode + */ + void unsetMode(); + + /** + * The mode configured by the server. + */ + Mode mode() const; + + operator zxdg_toplevel_decoration_v1*(); + operator zxdg_toplevel_decoration_v1*() const; + +Q_SIGNALS: + void modeChanged(KWayland::Client::XdgDecoration::Mode mode); + +private: + friend class XdgDecorationManager; + explicit XdgDecoration(QObject *parent = nullptr); + class Private; + QScopedPointer d; +}; + + +} +} + +#endif diff --git a/src/client/xdgdecoration.cpp b/src/client/xdgdecoration.cpp new file mode 100644 --- /dev/null +++ b/src/client/xdgdecoration.cpp @@ -0,0 +1,238 @@ +/**************************************************************************** +Copyright 2018 David Edmundson + +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 "xdgdecoration.h" + +#include "event_queue.h" +#include "wayland_pointer_p.h" +#include "xdgshell.h" + +#include + +#include "wayland-xdg-decoration-unstable-v1-client-protocol.h" + +namespace KWayland +{ +namespace Client +{ + +class Q_DECL_HIDDEN XdgDecorationManager::Private +{ +public: + Private() = default; + + void setup(zxdg_decoration_manager_v1 *arg); + + WaylandPointer xdgdecorationmanager; + EventQueue *queue = nullptr; +}; + +XdgDecorationManager::XdgDecorationManager(QObject *parent) + : QObject(parent) + , d(new Private) +{ +} + +void XdgDecorationManager::Private::setup(zxdg_decoration_manager_v1 *arg) +{ + Q_ASSERT(arg); + Q_ASSERT(!xdgdecorationmanager); + xdgdecorationmanager.setup(arg); +} + +XdgDecorationManager::~XdgDecorationManager() +{ + release(); +} + +void XdgDecorationManager::setup(zxdg_decoration_manager_v1 *xdgdecorationmanager) +{ + d->setup(xdgdecorationmanager); +} + +void XdgDecorationManager::release() +{ + d->xdgdecorationmanager.release(); +} + +void XdgDecorationManager::destroy() +{ + d->xdgdecorationmanager.destroy(); +} + +XdgDecorationManager::operator zxdg_decoration_manager_v1*() { + return d->xdgdecorationmanager; +} + +XdgDecorationManager::operator zxdg_decoration_manager_v1*() const { + return d->xdgdecorationmanager; +} + +bool XdgDecorationManager::isValid() const +{ + return d->xdgdecorationmanager.isValid(); +} + +void XdgDecorationManager::setEventQueue(EventQueue *queue) +{ + d->queue = queue; +} + +EventQueue *XdgDecorationManager::eventQueue() +{ + return d->queue; +} + +XdgDecoration *XdgDecorationManager::getToplevelDecoration(XdgShellSurface *toplevel, QObject *parent) +{ + Q_ASSERT(isValid()); + xdg_toplevel *toplevel_resource = *toplevel; + if (!toplevel_resource) { //i.e using XDGShellV5 + qWarning() << "Trying to create an XdgDecoration without an XDGShell stable toplevel object"; + return nullptr; + } + auto p = new XdgDecoration(parent); + auto w = zxdg_decoration_manager_v1_get_toplevel_decoration(d->xdgdecorationmanager, toplevel_resource); + if (d->queue) { + d->queue->addProxy(w); + } + p->setup(w); + return p; +} + +class Q_DECL_HIDDEN XdgDecoration::Private +{ +public: + Private(XdgDecoration *q); + + void setup(zxdg_toplevel_decoration_v1 *arg); + + WaylandPointer xdgdecoration; + + XdgDecoration::Mode m_mode = XdgDecoration::Mode::ClientSide; +private: + XdgDecoration *q; + +private: + static void configureCallback(void *data, zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode); + + static const zxdg_toplevel_decoration_v1_listener s_listener; +}; + +const zxdg_toplevel_decoration_v1_listener XdgDecoration::Private::s_listener = { + configureCallback +}; + +void XdgDecoration::Private::configureCallback(void *data, zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t m) +{ + auto p = reinterpret_cast(data); + Q_ASSERT(p->xdgdecoration == zxdg_toplevel_decoration_v1); + switch (m) { + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: + p->m_mode = XdgDecoration::Mode::ClientSide; + break; + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: + p->m_mode = XdgDecoration::Mode::ServerSide; + break; + } + emit p->q->modeChanged(p->m_mode); +} + +XdgDecoration::Private::Private(XdgDecoration *q) + : q(q) +{ +} + +XdgDecoration::XdgDecoration(QObject *parent) + : QObject(parent) + , d(new Private(this)) +{ +} + +void XdgDecoration::Private::setup(zxdg_toplevel_decoration_v1 *arg) +{ + Q_ASSERT(arg); + Q_ASSERT(!xdgdecoration); + xdgdecoration.setup(arg); + zxdg_toplevel_decoration_v1_add_listener(xdgdecoration, &s_listener, this); +} + +XdgDecoration::~XdgDecoration() +{ + release(); +} + +void XdgDecoration::setup(zxdg_toplevel_decoration_v1 *xdgdecoration) +{ + d->setup(xdgdecoration); +} + +void XdgDecoration::release() +{ + d->xdgdecoration.release(); +} + +void XdgDecoration::destroy() +{ + d->xdgdecoration.destroy(); +} + +XdgDecoration::operator zxdg_toplevel_decoration_v1*() { + return d->xdgdecoration; +} + +XdgDecoration::operator zxdg_toplevel_decoration_v1*() const { + return d->xdgdecoration; +} + +bool XdgDecoration::isValid() const +{ + return d->xdgdecoration.isValid(); +} + +void XdgDecoration::setMode(XdgDecoration::Mode mode) +{ + Q_ASSERT(isValid()); + uint32_t mode_raw; + switch (mode) { + case XdgDecoration::Mode::ClientSide: + mode_raw = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + break; + default: + mode_raw = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + break; + } + zxdg_toplevel_decoration_v1_set_mode(d->xdgdecoration, mode_raw); +} + +void XdgDecoration::unsetMode() +{ + Q_ASSERT(isValid()); + zxdg_toplevel_decoration_v1_unset_mode(d->xdgdecoration); +} + +XdgDecoration::Mode XdgDecoration::mode() const +{ + return d->m_mode; +} + + +} +} + diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -49,6 +49,7 @@ textinput_interface.cpp textinput_interface_v0.cpp textinput_interface_v2.cpp + xdgdecoration_interface.cpp xdgshell_interface.cpp xdgshell_v5_interface.cpp xdgforeign_v2_interface.cpp @@ -196,6 +197,11 @@ BASENAME xdg-shell ) +ecm_add_wayland_server_protocol(SERVER_LIB_SRCS + PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-decoration-unstable-v1.xml + BASENAME xdg-decoration +) + set(SERVER_GENERATED_SRCS ${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-server-protocol.h @@ -248,6 +254,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/wayland-idle-inhibit-unstable-v1-server-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-output-unstable-v1-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/wayland-output-unstable-v1-server-protocol.h + ${CMAKE_CURRENT_BINARY_DIR}/wayland-output-unstable-v1-client-protocol.h + ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-decoration-server-protocol.h + ${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-decoration-client-protocol.h ) set_source_files_properties(${SERVER_GENERATED_SRCS} PROPERTIES SKIP_AUTOMOC ON) @@ -326,6 +335,7 @@ surface_interface.h textinput_interface.h touch_interface.h + xdgdecoration_interface.h xdgshell_interface.h xdgforeign_interface.h xdgoutput_interface.h diff --git a/src/server/display.h b/src/server/display.h --- a/src/server/display.h +++ b/src/server/display.h @@ -1,5 +1,6 @@ /******************************************************************** Copyright 2014 Martin Gräßlin +Copyright 2018 David Edmundson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -88,6 +89,7 @@ class ServerSideDecorationPaletteManagerInterface; class PlasmaVirtualDesktopManagementInterface; class XdgOutputManagerInterface; +class XdgDecorationManagerInterface; /** * @brief Class holding the Wayland server display loop. @@ -277,6 +279,15 @@ **/ PlasmaVirtualDesktopManagementInterface *createPlasmaVirtualDesktopManagement(QObject *parent = nullptr); + /** + * Creates the XdgDecorationManagerInterface + * @arg shellInterface A created XdgShellInterface based on XDG_WM_BASE + * + * @return the created manager + * @since 5.XDG_DECO_VERSION + */ + XdgDecorationManagerInterface *createXdgDecorationManager(XdgShellInterface *shellInterface, 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 @@ -1,5 +1,6 @@ /******************************************************************** Copyright 2014 Martin Gräßlin +Copyright 2018 David Edmundson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -53,6 +54,7 @@ #include "server_decoration_palette_interface.h" #include "plasmavirtualdesktop_interface.h" #include "xdgoutput_interface.h" +#include "xdgdecoration_interface.h" #include #include @@ -478,6 +480,13 @@ return b; } +XdgDecorationManagerInterface *Display::createXdgDecorationManager(XdgShellInterface *shellInterface, QObject *parent) +{ + auto d = new XdgDecorationManagerInterface(this, shellInterface, parent); + connect(this, &Display::aboutToTerminate, d, [d] { delete d; }); + return d; +} + void Display::createShm() { Q_ASSERT(d->display); diff --git a/src/server/xdgdecoration_interface.h b/src/server/xdgdecoration_interface.h new file mode 100644 --- /dev/null +++ b/src/server/xdgdecoration_interface.h @@ -0,0 +1,109 @@ +/**************************************************************************** +Copyright 2018 David Edmundson + +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_XDG_DECORATION_UNSTABLE_V1_H +#define KWAYLAND_SERVER_XDG_DECORATION_UNSTABLE_V1_H + +#include "global.h" +#include "resource.h" + +#include + +namespace KWayland +{ +namespace Server +{ + +class Display; +class XdgDecorationInterface; +class XdgShellInterface; +class XdgShellSurfaceInterface; + +/** + * @brief The XdgDecorationManagerInterface class + * @since 5.DECO_VERSION + */ +class KWAYLANDSERVER_EXPORT XdgDecorationManagerInterface : public Global +{ + Q_OBJECT +public: + ~XdgDecorationManagerInterface() override; +Q_SIGNALS: + void xdgDecorationInterfaceCreated(XdgDecorationInterface *iface); +private: + explicit XdgDecorationManagerInterface(Display *display, XdgShellInterface *shellInterface, QObject *parent = nullptr); + friend class Display; + class Private; +}; + +/** + * @brief The XdgDecorationInterface class + * @since 5.DECO_VERSION + */ +class KWAYLANDSERVER_EXPORT XdgDecorationInterface : public Resource +{ + Q_OBJECT +public: + enum class Mode { + Undefined, + ClientSide, + ServerSide + }; + + Q_ENUM(Mode); + + ~XdgDecorationInterface() override; + + /** + * Sets the mode the client should be using. + * It should be followed by a call to XDGShellSurface::configure() + * Once acked, it can relied upon to be applied in the next surface + */ + void configure(Mode requestedMode); + + /** + * The last mode requested by the client + */ + Mode requestedMode() const; + + /** + * The surface this decoration is attached to + */ + XdgShellSurfaceInterface *surface() const; + +Q_SIGNALS: + /** + * New mode requested by the client + */ + void modeRequested(KWayland::Server::XdgDecorationInterface::Mode requestedMode); + +private: + explicit XdgDecorationInterface(XdgDecorationManagerInterface *parent, XdgShellSurfaceInterface *surface, wl_resource *parentResource); + friend class XdgDecorationManagerInterface; + + class Private; + Private *d_func() const; +}; + + +} +} + + +#endif diff --git a/src/server/xdgdecoration_interface.cpp b/src/server/xdgdecoration_interface.cpp new file mode 100644 --- /dev/null +++ b/src/server/xdgdecoration_interface.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +Copyright 2018 David Edmundson + +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 "xdgdecoration_interface.h" + + +#include "display.h" +#include "global_p.h" +#include "resource_p.h" +#include "xdgshell_interface.h" +#include "xdgshell_stable_interface_p.h" + +#include "wayland-xdg-decoration-server-protocol.h" + +#include +#include + +namespace KWayland +{ +namespace Server +{ + +class XdgDecorationManagerInterface::Private : public Global::Private +{ +public: + Private(XdgDecorationManagerInterface *q, XdgShellInterface *shellInterface, Display *d); + + QHash m_decorations; + KWayland::Server::XdgShellStableInterface *m_shellInterface; +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 getToplevelDecorationCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * toplevel); + + XdgDecorationManagerInterface *q; + static const struct zxdg_decoration_manager_v1_interface s_interface; + static const quint32 s_version; +}; + +const quint32 XdgDecorationManagerInterface::Private::s_version = 1; + +XdgDecorationManagerInterface::XdgDecorationManagerInterface(Display *display, XdgShellInterface *shellInterface, QObject *parent): + Global(new Private(this, shellInterface, display), parent) +{ +} + +XdgDecorationManagerInterface::~XdgDecorationManagerInterface() {} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zxdg_decoration_manager_v1_interface XdgDecorationManagerInterface::Private::s_interface = { + destroyCallback, + getToplevelDecorationCallback +}; +#endif + +void XdgDecorationManagerInterface::Private::destroyCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + wl_resource_destroy(resource); +} + +void XdgDecorationManagerInterface::Private::getToplevelDecorationCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * toplevel) +{ + auto p = reinterpret_cast(wl_resource_get_user_data(resource)); + Q_ASSERT(p); + + auto shell = p->m_shellInterface->getSurface(toplevel); + if (!shell) { + wl_resource_post_error(resource, ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED, "No XDGToplevel found object"); + return; + } + if (p->m_decorations.contains(shell)) { + wl_resource_post_error(resource, ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED, "XDGDecoration already exists for this surface"); + return; + } + + auto xdgDecoration = new XdgDecorationInterface(p->q, shell, resource); + xdgDecoration->create(p->display->getConnection(client), wl_resource_get_version(resource), id); + if (!xdgDecoration->resource()) { + wl_resource_post_no_memory(resource); + delete xdgDecoration; + return; + } + p->m_decorations[shell] = xdgDecoration; + QObject::connect(xdgDecoration, &QObject::destroyed, p->q, [=]() { + p->m_decorations.remove(shell); + }); + emit p->q->xdgDecorationInterfaceCreated(xdgDecoration); +} + +XdgDecorationManagerInterface::Private::Private(XdgDecorationManagerInterface *q, XdgShellInterface *shellInterface, Display *d) + : Global::Private(d, &zxdg_decoration_manager_v1_interface, s_version) + , q(q) +{ + m_shellInterface = qobject_cast(shellInterface); + Q_ASSERT(m_shellInterface); +} + +void XdgDecorationManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) +{ + auto c = display->getConnection(client); + wl_resource *resource = c->createResource(&zxdg_decoration_manager_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); +} + +void XdgDecorationManagerInterface::Private::unbind(wl_resource *resource) +{ + Q_UNUSED(resource) +} + +class XdgDecorationInterface::Private : public Resource::Private +{ +public: + Private(XdgDecorationInterface *q, XdgDecorationManagerInterface *c, XdgShellSurfaceInterface *s, wl_resource *parentResource); + ~Private(); + Mode m_requestedMode = Mode::Undefined; + XdgShellSurfaceInterface* m_shell; + +private: + static void setModeCallback(wl_client *client, wl_resource *resource, uint32_t mode); + static void unsetModeCallback(wl_client *client, wl_resource *resource); + + XdgDecorationInterface *q_func() { + return reinterpret_cast(q); + } + + static const struct zxdg_toplevel_decoration_v1_interface s_interface; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zxdg_toplevel_decoration_v1_interface XdgDecorationInterface::Private::s_interface = { + resourceDestroyedCallback, + setModeCallback, + unsetModeCallback +}; +#endif + +void XdgDecorationInterface::Private::setModeCallback(wl_client *client, wl_resource *resource, uint32_t mode_raw) +{ + Q_UNUSED(client); + auto p = reinterpret_cast(wl_resource_get_user_data(resource)); + Q_ASSERT(p); + + Mode mode = Mode::Undefined; + switch (mode_raw) { + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: + mode = Mode::ClientSide; + break; + case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: + mode = Mode::ServerSide; + break; + default: + break; + } + + p->m_requestedMode = mode; + emit p->q_func()->modeRequested(p->m_requestedMode); +} + +void XdgDecorationInterface::Private::unsetModeCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client); + auto p = reinterpret_cast(wl_resource_get_user_data(resource)); + Q_ASSERT(p); + + p->m_requestedMode = Mode::Undefined; + emit p->q_func()->modeRequested(p->m_requestedMode); +} + +XdgDecorationInterface::Private::Private(XdgDecorationInterface *q, XdgDecorationManagerInterface *c, XdgShellSurfaceInterface *shell, wl_resource *parentResource) + : Resource::Private(q, c, parentResource, &zxdg_toplevel_decoration_v1_interface, &s_interface) + , m_shell(shell) +{ +} + +XdgDecorationInterface::Private::~Private() +{ + if (resource) { + wl_resource_destroy(resource); + resource = nullptr; + } +} + +XdgDecorationInterface::XdgDecorationInterface(XdgDecorationManagerInterface *parent, XdgShellSurfaceInterface *shell, wl_resource *parentResource) + : Resource(new Private(this, parent, shell, parentResource)) +{ +} + +XdgDecorationInterface::~XdgDecorationInterface() {} + +void XdgDecorationInterface::configure(XdgDecorationInterface::Mode mode) +{ + switch(mode) { + case Mode::ClientSide: + zxdg_toplevel_decoration_v1_send_configure(resource(), ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); + break; + case Mode::ServerSide: + zxdg_toplevel_decoration_v1_send_configure(resource(), ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + break; + default: + //configure(Mode::Undefined) should no-op, as it semantically makes no sense + break; + } +} + +XdgDecorationInterface::Mode XdgDecorationInterface::requestedMode() const +{ + Q_D(); + return d->m_requestedMode; +} + +XdgShellSurfaceInterface* XdgDecorationInterface::surface() const +{ + Q_D(); + return d->m_shell; +} + +XdgDecorationInterface::Private *XdgDecorationInterface::d_func() const +{ + return reinterpret_cast(d.data()); +} + + +} +} + diff --git a/src/server/xdgshell_interface.h b/src/server/xdgshell_interface.h --- a/src/server/xdgshell_interface.h +++ b/src/server/xdgshell_interface.h @@ -114,6 +114,7 @@ /** * @returns The XdgShellSurfaceInterface for the @p native resource. **/ + //TODO KF6 make virtual XdgShellSurfaceInterface *getSurface(wl_resource *native); /** diff --git a/src/tools/mapping.txt b/src/tools/mapping.txt --- a/src/tools/mapping.txt +++ b/src/tools/mapping.txt @@ -49,6 +49,7 @@ xdg_shell;XdgShellV5 xdg_surface;XdgSurfaceV5 xdg_popup;XdgPopupV5 +xdg_toplevel;XdgShell zxdg_shell_v6;XdgShellV6 zxdg_surface_v6;XdgSurfaceV6 zxdg_popup_v6;XdgPopupV6 @@ -66,3 +67,5 @@ org_kde_kwin_remote_buffer;RemoteBuffer zxdg_output_v1;XdgOutput zxdg_output_manager_v1;XdgOutputManager +zxdg_decoration_manager_v1;XdgDecorationManager +zxdg_toplevel_decoration_v1;XdgDecoration