diff --git a/src/backends/wayland/wayland_backend.cpp b/src/backends/wayland/wayland_backend.cpp index 906c8262c6..22643f99e4 100644 --- a/src/backends/wayland/wayland_backend.cpp +++ b/src/backends/wayland/wayland_backend.cpp @@ -13,7 +13,6 @@ #include "wayland_egl_backend.h" #include #endif -#include "core/renderloop_p.h" #include "wayland_display.h" #include "wayland_logging.h" #include "wayland_output.h" @@ -35,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -631,27 +629,7 @@ void WaylandBackend::createOutputs() WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size) { - std::unique_ptr surface{m_display->compositor()->createSurface()}; - if (!surface || !surface->isValid()) { - qCCritical(KWIN_WAYLAND_BACKEND) << "Creating Wayland Surface failed"; - return nullptr; - } - - if (KWayland::Client::ServerSideDecorationManager *ssdManager = m_display->serverSideDecorationManager()) { - auto decoration = ssdManager->create(surface.get(), surface.get()); - connect(decoration, &ServerSideDecoration::modeChanged, this, [decoration] { - if (decoration->mode() != ServerSideDecoration::Mode::Server) { - decoration->requestMode(ServerSideDecoration::Mode::Server); - } - }); - } - - XdgShellOutput *waylandOutput = waylandOutput = new XdgShellOutput(name, std::move(surface), m_display->xdgShell(), this, m_nextId++); - if (!waylandOutput) { - qCCritical(KWIN_WAYLAND_BACKEND) << "Binding to all shell interfaces failed for output"; - return nullptr; - } - + WaylandOutput *waylandOutput = new WaylandOutput(name, this); waylandOutput->init(size); // Wait until the output window is configured by the host compositor. @@ -659,14 +637,6 @@ WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &si wl_display_roundtrip(m_display->nativeDisplay()); } - connect(waylandOutput, &WaylandOutput::frameRendered, this, [waylandOutput]() { - // The current time of the monotonic clock is a pretty good estimate when the frame - // has been presented, however it will be much better if we check whether the host - // compositor supports the wp_presentation protocol. - RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(waylandOutput->renderLoop()); - renderLoopPrivate->notifyFrameCompleted(std::chrono::steady_clock::now().time_since_epoch()); - }); - return waylandOutput; } @@ -752,16 +722,6 @@ void WaylandBackend::togglePointerLock() flush(); } -bool WaylandBackend::pointerIsLocked() -{ - for (auto *output : std::as_const(m_outputs)) { - if (output->pointerIsLocked()) { - return true; - } - } - return false; -} - QVector WaylandBackend::supportedCompositors() const { #if HAVE_WAYLAND_EGL diff --git a/src/backends/wayland/wayland_backend.h b/src/backends/wayland/wayland_backend.h index ddfa0163d3..80f92c0f7f 100644 --- a/src/backends/wayland/wayland_backend.h +++ b/src/backends/wayland/wayland_backend.h @@ -252,7 +252,6 @@ public: bool supportsPointerLock(); void togglePointerLock(); - bool pointerIsLocked(); QVector supportedCompositors() const override; @@ -298,7 +297,6 @@ private: std::unique_ptr m_waylandCursor; std::unique_ptr m_dpmsFilter; bool m_pointerLockRequested = false; - int m_nextId = 0; #if HAVE_WAYLAND_EGL FileDescriptor m_drmFileDescriptor; gbm_device *m_gbmDevice; diff --git a/src/backends/wayland/wayland_output.cpp b/src/backends/wayland/wayland_output.cpp index d8f93e0589..9d4c9c55d7 100644 --- a/src/backends/wayland/wayland_output.cpp +++ b/src/backends/wayland/wayland_output.cpp @@ -7,12 +7,14 @@ SPDX-License-Identifier: GPL-2.0-or-later */ #include "wayland_output.h" -#include "core/renderloop.h" +#include "core/renderloop_p.h" #include "wayland_backend.h" #include "wayland_display.h" #include "wayland_server.h" +#include #include +#include #include #include @@ -25,31 +27,80 @@ namespace Wayland using namespace KWayland::Client; static const int s_refreshRate = 60000; // TODO: can we get refresh rate data from Wayland host? -WaylandOutput::WaylandOutput(const QString &name, std::unique_ptr &&surface, WaylandBackend *backend) +WaylandOutput::WaylandOutput(const QString &name, WaylandBackend *backend) : Output(backend) , m_renderLoop(std::make_unique()) - , m_surface(std::move(surface)) + , m_surface(backend->display()->compositor()->createSurface()) + , m_xdgShellSurface(backend->display()->xdgShell()->createSurface(m_surface.get())) , m_backend(backend) { + if (KWayland::Client::ServerSideDecorationManager *ssdManager = backend->display()->serverSideDecorationManager()) { + m_serverDecoration.reset(ssdManager->create(m_surface.get())); + connect(m_serverDecoration.get(), &KWayland::Client::ServerSideDecoration::modeChanged, this, [this] { + if (m_serverDecoration->mode() != KWayland::Client::ServerSideDecoration::Mode::Server) { + m_serverDecoration->requestMode(KWayland::Client::ServerSideDecoration::Mode::Server); + } + }); + } + setInformation(Information{ .name = name, .model = name, .capabilities = Capability::Dpms, }); - connect(m_surface.get(), &Surface::frameRendered, this, &WaylandOutput::frameRendered); m_turnOffTimer.setSingleShot(true); m_turnOffTimer.setInterval(dimAnimationTime()); connect(&m_turnOffTimer, &QTimer::timeout, this, [this] { updateDpmsMode(DpmsMode::Off); }); + + connect(m_surface.get(), &KWayland::Client::Surface::frameRendered, this, [this]() { + RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(renderLoop()); + renderLoopPrivate->notifyFrameCompleted(std::chrono::steady_clock::now().time_since_epoch()); + }); + + updateWindowTitle(); + + connect(m_xdgShellSurface.get(), &XdgShellSurface::configureRequested, this, &WaylandOutput::handleConfigure); + connect(m_xdgShellSurface.get(), &XdgShellSurface::closeRequested, qApp, &QCoreApplication::quit); + connect(this, &WaylandOutput::enabledChanged, this, &WaylandOutput::updateWindowTitle); + connect(this, &WaylandOutput::dpmsModeChanged, this, &WaylandOutput::updateWindowTitle); + + connect(backend, &WaylandBackend::pointerLockSupportedChanged, this, &WaylandOutput::updateWindowTitle); + connect(backend, &WaylandBackend::pointerLockChanged, this, [this](bool locked) { + if (locked) { + if (!m_hasPointerLock) { + // some other output has locked the pointer + // this surface can stop trying to lock the pointer + lockPointer(nullptr, false); + // set it true for the other surface + m_hasPointerLock = true; + } + } else { + // just try unlocking + lockPointer(nullptr, false); + } + updateWindowTitle(); + }); } WaylandOutput::~WaylandOutput() { + m_xdgShellSurface->destroy(); m_surface->destroy(); } +bool WaylandOutput::isReady() const +{ + return m_ready; +} + +KWayland::Client::Surface *WaylandOutput::surface() const +{ + return m_surface.get(); +} + RenderLoop *WaylandOutput::renderLoop() const { return m_renderLoop.get(); @@ -66,6 +117,8 @@ void WaylandOutput::init(const QSize &pixelSize) initialState.currentMode = mode; initialState.scale = m_backend->initialOutputScale(); setState(initialState); + + m_surface->commit(KWayland::Client::Surface::CommitFlag::None); } void WaylandOutput::resize(const QSize &pixelSize) @@ -113,49 +166,7 @@ void WaylandOutput::updateEnabled(bool enabled) setState(next); } -XdgShellOutput::XdgShellOutput(const QString &name, std::unique_ptr &&waylandSurface, XdgShell *xdgShell, WaylandBackend *backend, int number) - : WaylandOutput(name, std::move(waylandSurface), backend) - , m_xdgShellSurface(xdgShell->createSurface(surface())) - , m_number(number) -{ - updateWindowTitle(); - - connect(m_xdgShellSurface.get(), &XdgShellSurface::configureRequested, this, &XdgShellOutput::handleConfigure); - connect(m_xdgShellSurface.get(), &XdgShellSurface::closeRequested, qApp, &QCoreApplication::quit); - connect(this, &WaylandOutput::enabledChanged, this, &XdgShellOutput::updateWindowTitle); - connect(this, &WaylandOutput::dpmsModeChanged, this, &XdgShellOutput::updateWindowTitle); - - connect(backend, &WaylandBackend::pointerLockSupportedChanged, this, &XdgShellOutput::updateWindowTitle); - connect(backend, &WaylandBackend::pointerLockChanged, this, [this](bool locked) { - if (locked) { - if (!m_hasPointerLock) { - // some other output has locked the pointer - // this surface can stop trying to lock the pointer - lockPointer(nullptr, false); - // set it true for the other surface - m_hasPointerLock = true; - } - } else { - // just try unlocking - lockPointer(nullptr, false); - } - updateWindowTitle(); - }); - - surface()->commit(KWayland::Client::Surface::CommitFlag::None); -} - -XdgShellOutput::~XdgShellOutput() -{ - m_xdgShellSurface->destroy(); -} - -bool XdgShellOutput::isReady() const -{ - return m_ready; -} - -void XdgShellOutput::handleConfigure(const QSize &size, XdgShellSurface::States states, quint32 serial) +void WaylandOutput::handleConfigure(const QSize &size, XdgShellSurface::States states, quint32 serial) { m_xdgShellSurface->ackConfigure(serial); if (size.width() > 0 && size.height() > 0) { @@ -168,17 +179,17 @@ void XdgShellOutput::handleConfigure(const QSize &size, XdgShellSurface::States m_ready = true; } -void XdgShellOutput::updateWindowTitle() +void WaylandOutput::updateWindowTitle() { QString grab; if (m_hasPointerLock) { grab = i18n("Press right control to ungrab pointer"); - } else if (backend()->display()->pointerConstraints()) { + } else if (m_backend->display()->pointerConstraints()) { grab = i18n("Press right control key to grab pointer"); } QString title = i18nc("Title of nested KWin Wayland with Wayland socket identifier as argument", - "KDE Wayland Compositor #%1 (%2)", m_number, waylandServer()->socketName()); + "KDE Wayland Compositor %1 (%2)", name(), waylandServer()->socketName()); if (!isEnabled()) { title += i18n("- Output disabled"); @@ -190,32 +201,32 @@ void XdgShellOutput::updateWindowTitle() m_xdgShellSurface->setTitle(title); } -void XdgShellOutput::lockPointer(Pointer *pointer, bool lock) +void WaylandOutput::lockPointer(Pointer *pointer, bool lock) { if (!lock) { const bool surfaceWasLocked = m_pointerLock && m_hasPointerLock; m_pointerLock.reset(); m_hasPointerLock = false; if (surfaceWasLocked) { - Q_EMIT backend()->pointerLockChanged(false); + Q_EMIT m_backend->pointerLockChanged(false); } return; } Q_ASSERT(!m_pointerLock); - m_pointerLock.reset(backend()->display()->pointerConstraints()->lockPointer(surface(), pointer, nullptr, PointerConstraints::LifeTime::OneShot)); + m_pointerLock.reset(m_backend->display()->pointerConstraints()->lockPointer(surface(), pointer, nullptr, PointerConstraints::LifeTime::OneShot)); if (!m_pointerLock->isValid()) { m_pointerLock.reset(); return; } connect(m_pointerLock.get(), &LockedPointer::locked, this, [this]() { m_hasPointerLock = true; - Q_EMIT backend()->pointerLockChanged(true); + Q_EMIT m_backend->pointerLockChanged(true); }); connect(m_pointerLock.get(), &LockedPointer::unlocked, this, [this]() { m_pointerLock.reset(); m_hasPointerLock = false; - Q_EMIT backend()->pointerLockChanged(false); + Q_EMIT m_backend->pointerLockChanged(false); }); } diff --git a/src/backends/wayland/wayland_output.h b/src/backends/wayland/wayland_output.h index 615515b721..f53d3b0fc6 100644 --- a/src/backends/wayland/wayland_output.h +++ b/src/backends/wayland/wayland_output.h @@ -20,12 +20,9 @@ namespace KWayland namespace Client { class Surface; - -class Shell; -class ShellSurface; - class Pointer; class LockedPointer; +class ServerSideDecoration; } } @@ -39,71 +36,36 @@ class WaylandOutput : public Output { Q_OBJECT public: - WaylandOutput(const QString &name, std::unique_ptr &&surface, WaylandBackend *backend); + WaylandOutput(const QString &name, WaylandBackend *backend); ~WaylandOutput() override; RenderLoop *renderLoop() const override; void init(const QSize &pixelSize); - virtual void lockPointer(KWayland::Client::Pointer *pointer, bool lock) - { - } - - virtual bool pointerIsLocked() - { - return false; - } + bool isReady() const; + KWayland::Client::Surface *surface() const; + void lockPointer(KWayland::Client::Pointer *pointer, bool lock); void resize(const QSize &pixelSize); - - KWayland::Client::Surface *surface() const - { - return m_surface.get(); - } - void setDpmsMode(DpmsMode mode) override; - void updateDpmsMode(DpmsMode dpmsMode); void updateEnabled(bool enabled); Q_SIGNALS: void sizeChanged(const QSize &size); - void frameRendered(); - -protected: - WaylandBackend *backend() - { - return m_backend; - } - -private: - std::unique_ptr m_renderLoop; - std::unique_ptr m_surface; - WaylandBackend *m_backend; - QTimer m_turnOffTimer; -}; - -class XdgShellOutput : public WaylandOutput -{ -public: - XdgShellOutput(const QString &name, - std::unique_ptr &&surface, - KWayland::Client::XdgShell *xdgShell, - WaylandBackend *backend, int number); - ~XdgShellOutput() override; - - void lockPointer(KWayland::Client::Pointer *pointer, bool lock) override; - - bool isReady() const; private: void handleConfigure(const QSize &size, KWayland::Client::XdgShellSurface::States states, quint32 serial); void updateWindowTitle(); + std::unique_ptr m_renderLoop; + std::unique_ptr m_surface; std::unique_ptr m_xdgShellSurface; - int m_number; std::unique_ptr m_pointerLock; + std::unique_ptr m_serverDecoration; + WaylandBackend *const m_backend; + QTimer m_turnOffTimer; bool m_hasPointerLock = false; bool m_ready = false; };