From 83261fc82aac8bf5f6a2d552ee015c5683cc87bd Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 8 Mar 2023 10:07:39 +0200 Subject: [PATCH] wayland: Implement kde-screen-edge-v1 It's needed to port the plasma panel to the layer shell protocol. --- autotests/integration/CMakeLists.txt | 1 + autotests/integration/kwin_wayland_test.h | 18 +++ .../integration/layershellv1window_test.cpp | 58 ++++++- autotests/integration/test_helpers.cpp | 38 +++++ src/layershellv1window.cpp | 54 +++++++ src/layershellv1window.h | 10 ++ src/wayland/CMakeLists.txt | 5 + src/wayland/screenedge_v1_interface.cpp | 149 ++++++++++++++++++ src/wayland/screenedge_v1_interface.h | 59 +++++++ src/wayland_server.cpp | 9 ++ 10 files changed, 400 insertions(+), 1 deletion(-) create mode 100644 src/wayland/screenedge_v1_interface.cpp create mode 100644 src/wayland/screenedge_v1_interface.h diff --git a/autotests/integration/CMakeLists.txt b/autotests/integration/CMakeLists.txt index 769cfed0aa..b8eb24dbb6 100644 --- a/autotests/integration/CMakeLists.txt +++ b/autotests/integration/CMakeLists.txt @@ -17,6 +17,7 @@ qt6_generate_wayland_protocol_client_sources(KWinIntegrationTestFramework ${WaylandProtocols_DATADIR}/staging/fractional-scale/fractional-scale-v1.xml ${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-output-device-v2.xml ${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-output-management-v2.xml + ${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-screen-edge-v1.xml ${PLASMA_WAYLAND_PROTOCOLS_DIR}/zkde-screencast-unstable-v1.xml ) diff --git a/autotests/integration/kwin_wayland_test.h b/autotests/integration/kwin_wayland_test.h index 432c0921dd..d33e7246ed 100644 --- a/autotests/integration/kwin_wayland_test.h +++ b/autotests/integration/kwin_wayland_test.h @@ -24,6 +24,7 @@ #include "qwayland-input-method-unstable-v1.h" #include "qwayland-kde-output-device-v2.h" #include "qwayland-kde-output-management-v2.h" +#include "qwayland-kde-screen-edge-v1.h" #include "qwayland-text-input-unstable-v3.h" #include "qwayland-wlr-layer-shell-unstable-v1.h" #include "qwayland-xdg-decoration-unstable-v1.h" @@ -487,6 +488,21 @@ private: int m_preferredScale = 120; }; +class ScreenEdgeManagerV1 : public QObject, public QtWayland::kde_screen_edge_manager_v1 +{ + Q_OBJECT +public: + ~ScreenEdgeManagerV1() override; +}; + +class AutoHideScreenEdgeV1 : public QObject, public QtWayland::kde_auto_hide_screen_edge_v1 +{ + Q_OBJECT +public: + AutoHideScreenEdgeV1(ScreenEdgeManagerV1 *manager, KWayland::Client::Surface *surface, uint32_t border); + ~AutoHideScreenEdgeV1() override; +}; + enum class AdditionalWaylandInterface { Seat = 1 << 0, Decoration = 1 << 1, @@ -505,6 +521,7 @@ enum class AdditionalWaylandInterface { OutputDeviceV2 = 1 << 14, FractionalScaleManagerV1 = 1 << 15, ScreencastingV1 = 1 << 16, + ScreenEdgeV1 = 1 << 17, }; Q_DECLARE_FLAGS(AdditionalWaylandInterfaces, AdditionalWaylandInterface) @@ -650,6 +667,7 @@ XdgPopup *createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface * XdgToplevelDecorationV1 *createXdgToplevelDecorationV1(XdgToplevel *toplevel, QObject *parent = nullptr); IdleInhibitorV1 *createIdleInhibitorV1(KWayland::Client::Surface *surface); +AutoHideScreenEdgeV1 *createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border); /** * Creates a shared memory buffer of @p size in @p color and attaches it to the @p surface. diff --git a/autotests/integration/layershellv1window_test.cpp b/autotests/integration/layershellv1window_test.cpp index 6791725f12..c1d26741ca 100644 --- a/autotests/integration/layershellv1window_test.cpp +++ b/autotests/integration/layershellv1window_test.cpp @@ -51,6 +51,7 @@ private Q_SLOTS: void testActivate_data(); void testActivate(); void testUnmap(); + void testScreenEdge(); }; void LayerShellV1WindowTest::initTestCase() @@ -72,7 +73,7 @@ void LayerShellV1WindowTest::initTestCase() void LayerShellV1WindowTest::init() { - QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::LayerShellV1)); + QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::LayerShellV1 | Test::AdditionalWaylandInterface::ScreenEdgeV1)); workspace()->setActiveOutput(QPoint(640, 512)); input()->pointer()->warp(QPoint(640, 512)); @@ -610,6 +611,61 @@ void LayerShellV1WindowTest::testUnmap() QVERIFY(Test::waitForWindowClosed(window)); } +void LayerShellV1WindowTest::testScreenEdge() +{ + // Create a layer shell surface. + std::unique_ptr surface(Test::createSurface()); + std::unique_ptr shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test"))); + std::unique_ptr screenEdge(Test::createAutoHideScreenEdgeV1(surface.get(), Test::ScreenEdgeManagerV1::border_bottom)); + + // Set the initial state of the layer surface. + shellSurface->set_layer(Test::LayerShellV1::layer_top); + shellSurface->set_anchor(Test::LayerSurfaceV1::anchor_bottom); + shellSurface->set_size(100, 50); + surface->commit(KWayland::Client::Surface::CommitFlag::None); + + // Wait for the compositor to position the surface. + QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested); + QVERIFY(configureRequestedSpy.wait()); + const QSize requestedSize = configureRequestedSpy.last().at(1).toSize(); + + // Map the layer surface. + shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt()); + Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red); + QVERIFY(window); + QVERIFY(!window->isActive()); + + // The layer surface will be hidden and shown when the screen edge is activated or deactivated. + QSignalSpy windowShowSpy(window, &Window::windowShown); + QSignalSpy windowHiddenSpy(window, &Window::windowHidden); + screenEdge->activate(); + QVERIFY(windowHiddenSpy.wait()); + QVERIFY(!window->isShown()); + + screenEdge->deactivate(); + QVERIFY(windowShowSpy.wait()); + QVERIFY(window->isShown()); + + // The layer surface will be shown when the screen edge is triggered. + screenEdge->activate(); + QVERIFY(windowHiddenSpy.wait()); + QVERIFY(!window->isShown()); + + Test::pointerMotion(QPointF(640, 1023), 0); + Test::pointerMotion(QPointF(640, 512), 1); + QVERIFY(windowShowSpy.wait()); + QVERIFY(window->isShown()); + + // The layer surface will be shown when the screen edge is destroyed. + screenEdge->activate(); + QVERIFY(windowHiddenSpy.wait()); + QVERIFY(!window->isShown()); + + screenEdge.reset(); + QVERIFY(windowShowSpy.wait()); + QVERIFY(window->isShown()); +} + } // namespace KWin WAYLANDTEST_MAIN(KWin::LayerShellV1WindowTest) diff --git a/autotests/integration/test_helpers.cpp b/autotests/integration/test_helpers.cpp index 0678980f4f..3f650314e2 100644 --- a/autotests/integration/test_helpers.cpp +++ b/autotests/integration/test_helpers.cpp @@ -227,6 +227,21 @@ IdleInhibitorV1::~IdleInhibitorV1() destroy(); } +ScreenEdgeManagerV1::~ScreenEdgeManagerV1() +{ + destroy(); +} + +AutoHideScreenEdgeV1::AutoHideScreenEdgeV1(ScreenEdgeManagerV1 *manager, KWayland::Client::Surface *surface, uint32_t border) + : QtWayland::kde_auto_hide_screen_edge_v1(manager->get_auto_hide_screen_edge(border, *surface)) +{ +} + +AutoHideScreenEdgeV1::~AutoHideScreenEdgeV1() +{ + destroy(); +} + static struct { KWayland::Client::ConnectionThread *connection = nullptr; @@ -257,6 +272,7 @@ static struct TextInputManagerV3 *textInputManagerV3 = nullptr; FractionalScaleManagerV1 *fractionalScaleManagerV1 = nullptr; ScreencastingV1 *screencastingV1 = nullptr; + ScreenEdgeManagerV1 *screenEdgeManagerV1 = nullptr; } s_waylandConnection; MockInputMethod *inputMethod() @@ -435,6 +451,13 @@ bool setupWaylandConnection(AdditionalWaylandInterfaces flags) return; } } + if (flags & AdditionalWaylandInterface::ScreenEdgeV1) { + if (interface == kde_screen_edge_manager_v1_interface.name) { + s_waylandConnection.screenEdgeManagerV1 = new ScreenEdgeManagerV1(); + s_waylandConnection.screenEdgeManagerV1->init(*registry, name, version); + return; + } + } }); QSignalSpy allAnnounced(registry, &KWayland::Client::Registry::interfacesAnnounced); @@ -561,6 +584,10 @@ void destroyWaylandConnection() s_waylandConnection.outputManagementV2 = nullptr; delete s_waylandConnection.fractionalScaleManagerV1; s_waylandConnection.fractionalScaleManagerV1 = nullptr; + delete s_waylandConnection.screencastingV1; + s_waylandConnection.screencastingV1 = nullptr; + delete s_waylandConnection.screenEdgeManagerV1; + s_waylandConnection.screenEdgeManagerV1 = nullptr; delete s_waylandConnection.queue; // Must be destroyed last s_waylandConnection.queue = nullptr; @@ -969,6 +996,17 @@ IdleInhibitorV1 *createIdleInhibitorV1(KWayland::Client::Surface *surface) return new IdleInhibitorV1(manager, surface); } +AutoHideScreenEdgeV1 *createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border) +{ + ScreenEdgeManagerV1 *manager = s_waylandConnection.screenEdgeManagerV1; + if (!manager) { + qWarning() << "Could not create an kde_auto_hide_screen_edge_v1 because kde_screen_edge_manager_v1 global is not bound"; + return nullptr; + } + + return new AutoHideScreenEdgeV1(manager, surface, border); +} + bool waitForWindowClosed(Window *window) { QSignalSpy closedSpy(window, &Window::closed); diff --git a/src/layershellv1window.cpp b/src/layershellv1window.cpp index 1954a2194e..546ef820f8 100644 --- a/src/layershellv1window.cpp +++ b/src/layershellv1window.cpp @@ -7,8 +7,10 @@ #include "layershellv1window.h" #include "core/output.h" #include "layershellv1integration.h" +#include "screenedge.h" #include "wayland/layershell_v1_interface.h" #include "wayland/output_interface.h" +#include "wayland/screenedge_v1_interface.h" #include "wayland/surface_interface.h" #include "wayland_server.h" #include "workspace.h" @@ -173,6 +175,9 @@ bool LayerShellV1Window::hasStrut() const void LayerShellV1Window::destroyWindow() { + if (m_screenEdge) { + m_screenEdge->disconnect(this); + } m_shellSurface->disconnect(this); m_shellSurface->surface()->disconnect(this); @@ -290,4 +295,53 @@ void LayerShellV1Window::setVirtualKeyboardGeometry(const QRectF &geo) scheduleRearrange(); } +void LayerShellV1Window::showOnScreenEdge() +{ + // ShowOnScreenEdge can be called by an Edge, and hideClient could destroy the Edge + // Use the singleshot to avoid use-after-free + QTimer::singleShot(0, this, &LayerShellV1Window::deactivateScreenEdge); +} + +void LayerShellV1Window::installAutoHideScreenEdgeV1(KWaylandServer::AutoHideScreenEdgeV1Interface *edge) +{ + m_screenEdge = edge; + + connect(edge, &KWaylandServer::AutoHideScreenEdgeV1Interface::destroyed, + this, &LayerShellV1Window::deactivateScreenEdge); + connect(edge, &KWaylandServer::AutoHideScreenEdgeV1Interface::activateRequested, + this, &LayerShellV1Window::activateScreenEdge); + connect(edge, &KWaylandServer::AutoHideScreenEdgeV1Interface::deactivateRequested, + this, &LayerShellV1Window::deactivateScreenEdge); + + connect(this, &LayerShellV1Window::frameGeometryChanged, edge, [this]() { + if (m_screenEdgeActive) { + reserveScreenEdge(); + } + }); +} + +void LayerShellV1Window::reserveScreenEdge() +{ + hideClient(); + workspace()->screenEdges()->reserve(this, m_screenEdge->border()); +} + +void LayerShellV1Window::unreserveScreenEdge() +{ + showClient(); + workspace()->screenEdges()->reserve(this, ElectricNone); +} + +void LayerShellV1Window::activateScreenEdge() +{ + m_screenEdgeActive = true; + reserveScreenEdge(); +} + +void LayerShellV1Window::deactivateScreenEdge() +{ + m_screenEdgeActive = false; + unreserveScreenEdge(); +} + } // namespace KWin diff --git a/src/layershellv1window.h b/src/layershellv1window.h index 085a9100df..fa82e61eea 100644 --- a/src/layershellv1window.h +++ b/src/layershellv1window.h @@ -10,6 +10,7 @@ namespace KWaylandServer { +class AutoHideScreenEdgeV1Interface; class LayerSurfaceV1Interface; } @@ -44,6 +45,9 @@ public: void destroyWindow() override; void closeWindow() override; void setVirtualKeyboardGeometry(const QRectF &geo) override; + void showOnScreenEdge() override; + + void installAutoHideScreenEdgeV1(KWaylandServer::AutoHideScreenEdgeV1Interface *edge); protected: Layer belongsToLayer() const override; @@ -58,10 +62,16 @@ private: void handleOutputEnabledChanged(); void handleOutputDestroyed(); void scheduleRearrange(); + void activateScreenEdge(); + void deactivateScreenEdge(); + void reserveScreenEdge(); + void unreserveScreenEdge(); Output *m_desiredOutput; LayerShellV1Integration *m_integration; KWaylandServer::LayerSurfaceV1Interface *m_shellSurface; + QPointer m_screenEdge; + bool m_screenEdgeActive = false; NET::WindowType m_windowType; }; diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index 1d44b8cd00..48244b406d 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -208,6 +208,10 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml PROTOCOL ${PROJECT_SOURCE_DIR}/src/wayland/protocols/wayland-drm.xml BASENAME drm ) +ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml + PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-screen-edge-v1.xml + BASENAME kde-screen-edge-v1 +) target_sources(kwin PRIVATE abstract_data_source.cpp @@ -260,6 +264,7 @@ target_sources(kwin PRIVATE region_interface.cpp relativepointer_v1_interface.cpp screencast_v1_interface.cpp + screenedge_v1_interface.cpp seat_interface.cpp server_decoration_interface.cpp server_decoration_palette_interface.cpp diff --git a/src/wayland/screenedge_v1_interface.cpp b/src/wayland/screenedge_v1_interface.cpp new file mode 100644 index 0000000000..5341ee8cb2 --- /dev/null +++ b/src/wayland/screenedge_v1_interface.cpp @@ -0,0 +1,149 @@ +/* + SPDX-FileCopyrightText: 2023 Vlad Zahorodnii + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#include "wayland/screenedge_v1_interface.h" +#include "wayland/display.h" +#include "wayland/surface_interface.h" +#include "wayland/surfacerole_p.h" + +#include "qwayland-server-kde-screen-edge-v1.h" + +using namespace KWin; + +namespace KWaylandServer +{ + +static const int s_version = 1; + +class ScreenEdgeManagerV1InterfacePrivate : public QtWaylandServer::kde_screen_edge_manager_v1 +{ +public: + ScreenEdgeManagerV1InterfacePrivate(ScreenEdgeManagerV1Interface *q, Display *display); + + ScreenEdgeManagerV1Interface *q; + +protected: + void kde_screen_edge_manager_v1_destroy(Resource *resource) override; + void kde_screen_edge_manager_v1_get_auto_hide_screen_edge(Resource *resource, uint32_t id, uint32_t border, struct ::wl_resource *surface) override; +}; + +ScreenEdgeManagerV1InterfacePrivate::ScreenEdgeManagerV1InterfacePrivate(ScreenEdgeManagerV1Interface *q, Display *display) + : QtWaylandServer::kde_screen_edge_manager_v1(*display, s_version) + , q(q) +{ +} + +void ScreenEdgeManagerV1InterfacePrivate::kde_screen_edge_manager_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void ScreenEdgeManagerV1InterfacePrivate::kde_screen_edge_manager_v1_get_auto_hide_screen_edge(Resource *resource, uint32_t id, uint32_t border, struct ::wl_resource *surface_resource) +{ + ElectricBorder electricBorder; + switch (border) { + case border_top: + electricBorder = ElectricTop; + break; + case border_bottom: + electricBorder = ElectricBottom; + break; + case border_left: + electricBorder = ElectricLeft; + break; + case border_right: + electricBorder = ElectricRight; + break; + default: + wl_resource_post_error(resource->handle, error_invalid_border, "invalid border"); + return; + } + + SurfaceInterface *surface = SurfaceInterface::get(surface_resource); + SurfaceRole *role = SurfaceRole::get(surface); + if (!role || role->name() != "layer_surface_v1") { + wl_resource_post_error(resource->handle, error_invalid_role, "surface must have layer_surface role"); + return; + } + + wl_resource *edgeResource = wl_resource_create(resource->client(), &kde_auto_hide_screen_edge_v1_interface, resource->version(), id); + auto edge = new AutoHideScreenEdgeV1Interface(surface, electricBorder, edgeResource); + Q_EMIT q->edgeRequested(edge); +} + +ScreenEdgeManagerV1Interface::ScreenEdgeManagerV1Interface(Display *display, QObject *parent) + : d(new ScreenEdgeManagerV1InterfacePrivate(this, display)) +{ +} + +ScreenEdgeManagerV1Interface::~ScreenEdgeManagerV1Interface() +{ +} + +class AutoHideScreenEdgeV1InterfacePrivate : public QtWaylandServer::kde_auto_hide_screen_edge_v1 +{ +public: + AutoHideScreenEdgeV1InterfacePrivate(AutoHideScreenEdgeV1Interface *q, SurfaceInterface *surface, ElectricBorder border, wl_resource *resource); + + AutoHideScreenEdgeV1Interface *q; + QPointer surface; + ElectricBorder border; + +protected: + void kde_auto_hide_screen_edge_v1_destroy_resource(Resource *resource) override; + void kde_auto_hide_screen_edge_v1_destroy(Resource *resource) override; + void kde_auto_hide_screen_edge_v1_deactivate(Resource *resource) override; + void kde_auto_hide_screen_edge_v1_activate(Resource *resource) override; +}; + +AutoHideScreenEdgeV1InterfacePrivate::AutoHideScreenEdgeV1InterfacePrivate(AutoHideScreenEdgeV1Interface *q, SurfaceInterface *surface, ElectricBorder border, wl_resource *resource) + : QtWaylandServer::kde_auto_hide_screen_edge_v1(resource) + , q(q) + , surface(surface) + , border(border) +{ +} + +void AutoHideScreenEdgeV1InterfacePrivate::kde_auto_hide_screen_edge_v1_destroy_resource(Resource *resource) +{ + delete q; +} + +void AutoHideScreenEdgeV1InterfacePrivate::kde_auto_hide_screen_edge_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void AutoHideScreenEdgeV1InterfacePrivate::kde_auto_hide_screen_edge_v1_deactivate(Resource *resource) +{ + Q_EMIT q->deactivateRequested(); +} + +void AutoHideScreenEdgeV1InterfacePrivate::kde_auto_hide_screen_edge_v1_activate(Resource *resource) +{ + Q_EMIT q->activateRequested(); +} + +AutoHideScreenEdgeV1Interface::AutoHideScreenEdgeV1Interface(SurfaceInterface *surface, ElectricBorder border, wl_resource *resource) + : d(new AutoHideScreenEdgeV1InterfacePrivate(this, surface, border, resource)) +{ +} + +AutoHideScreenEdgeV1Interface::~AutoHideScreenEdgeV1Interface() +{ +} + +SurfaceInterface *AutoHideScreenEdgeV1Interface::surface() const +{ + return d->surface; +} + +ElectricBorder AutoHideScreenEdgeV1Interface::border() const +{ + return d->border; +} + +} // namespace KWaylandServer diff --git a/src/wayland/screenedge_v1_interface.h b/src/wayland/screenedge_v1_interface.h new file mode 100644 index 0000000000..00de03378c --- /dev/null +++ b/src/wayland/screenedge_v1_interface.h @@ -0,0 +1,59 @@ +/* + SPDX-FileCopyrightText: 2023 Vlad Zahorodnii + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#pragma once + +#include "kwinglobals.h" + +#include +#include + +struct wl_resource; + +namespace KWaylandServer +{ + +class Display; +class ScreenEdgeManagerV1InterfacePrivate; +class AutoHideScreenEdgeV1Interface; +class AutoHideScreenEdgeV1InterfacePrivate; +class SurfaceInterface; + +class KWIN_EXPORT ScreenEdgeManagerV1Interface : public QObject +{ + Q_OBJECT + +public: + explicit ScreenEdgeManagerV1Interface(Display *display, QObject *parent = nullptr); + ~ScreenEdgeManagerV1Interface() override; + +Q_SIGNALS: + void edgeRequested(AutoHideScreenEdgeV1Interface *edge); + +private: + std::unique_ptr d; +}; + +class KWIN_EXPORT AutoHideScreenEdgeV1Interface : public QObject +{ + Q_OBJECT + +public: + AutoHideScreenEdgeV1Interface(SurfaceInterface *surface, KWin::ElectricBorder border, wl_resource *resource); + ~AutoHideScreenEdgeV1Interface() override; + + SurfaceInterface *surface() const; + KWin::ElectricBorder border() const; + +Q_SIGNALS: + void deactivateRequested(); + void activateRequested(); + +private: + std::unique_ptr d; +}; + +} // namespace KWaylandServer diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp index 5f2cbfdb9f..491fb23bf6 100644 --- a/src/wayland_server.cpp +++ b/src/wayland_server.cpp @@ -16,6 +16,7 @@ #include "idle_inhibition.h" #include "inputpanelv1integration.h" #include "layershellv1integration.h" +#include "layershellv1window.h" #include "main.h" #include "utils/serviceutils.h" #include "virtualdesktops.h" @@ -49,6 +50,7 @@ #include "wayland/pointergestures_v1_interface.h" #include "wayland/primaryselectiondevicemanager_v1_interface.h" #include "wayland/relativepointer_v1_interface.h" +#include "wayland/screenedge_v1_interface.h" #include "wayland/seat_interface.h" #include "wayland/server_decoration_interface.h" #include "wayland/server_decoration_palette_interface.h" @@ -510,6 +512,13 @@ bool WaylandServer::init(InitializationFlags flags) m_contentTypeManager = new KWaylandServer::ContentTypeManagerV1Interface(m_display, m_display); m_tearingControlInterface = new KWaylandServer::TearingControlManagerV1Interface(m_display, m_display); + auto screenEdgeManager = new KWaylandServer::ScreenEdgeManagerV1Interface(m_display, m_display); + connect(screenEdgeManager, &KWaylandServer::ScreenEdgeManagerV1Interface::edgeRequested, this, [this](KWaylandServer::AutoHideScreenEdgeV1Interface *edge) { + if (auto window = qobject_cast(findWindow(edge->surface()))) { + window->installAutoHideScreenEdgeV1(edge); + } + }); + return true; }