backends/wayland: Merge WaylandOutput and XdgShellOutput

This commit is contained in:
Vlad Zahorodnii 2022-11-11 10:09:08 +02:00
parent d4676cceb3
commit 6951d662d6
4 changed files with 77 additions and 146 deletions

View file

@ -13,7 +13,6 @@
#include "wayland_egl_backend.h" #include "wayland_egl_backend.h"
#include <gbm.h> #include <gbm.h>
#endif #endif
#include "core/renderloop_p.h"
#include "wayland_display.h" #include "wayland_display.h"
#include "wayland_logging.h" #include "wayland_logging.h"
#include "wayland_output.h" #include "wayland_output.h"
@ -35,7 +34,6 @@
#include <KWayland/Client/pointergestures.h> #include <KWayland/Client/pointergestures.h>
#include <KWayland/Client/relativepointer.h> #include <KWayland/Client/relativepointer.h>
#include <KWayland/Client/seat.h> #include <KWayland/Client/seat.h>
#include <KWayland/Client/server_decoration.h>
#include <KWayland/Client/shm_pool.h> #include <KWayland/Client/shm_pool.h>
#include <KWayland/Client/subcompositor.h> #include <KWayland/Client/subcompositor.h>
#include <KWayland/Client/subsurface.h> #include <KWayland/Client/subsurface.h>
@ -631,27 +629,7 @@ void WaylandBackend::createOutputs()
WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size) WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size)
{ {
std::unique_ptr<KWayland::Client::Surface> surface{m_display->compositor()->createSurface()}; WaylandOutput *waylandOutput = new WaylandOutput(name, this);
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->init(size); waylandOutput->init(size);
// Wait until the output window is configured by the host compositor. // 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()); 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; return waylandOutput;
} }
@ -752,16 +722,6 @@ void WaylandBackend::togglePointerLock()
flush(); flush();
} }
bool WaylandBackend::pointerIsLocked()
{
for (auto *output : std::as_const(m_outputs)) {
if (output->pointerIsLocked()) {
return true;
}
}
return false;
}
QVector<CompositingType> WaylandBackend::supportedCompositors() const QVector<CompositingType> WaylandBackend::supportedCompositors() const
{ {
#if HAVE_WAYLAND_EGL #if HAVE_WAYLAND_EGL

View file

@ -252,7 +252,6 @@ public:
bool supportsPointerLock(); bool supportsPointerLock();
void togglePointerLock(); void togglePointerLock();
bool pointerIsLocked();
QVector<CompositingType> supportedCompositors() const override; QVector<CompositingType> supportedCompositors() const override;
@ -298,7 +297,6 @@ private:
std::unique_ptr<WaylandCursor> m_waylandCursor; std::unique_ptr<WaylandCursor> m_waylandCursor;
std::unique_ptr<DpmsInputEventFilter> m_dpmsFilter; std::unique_ptr<DpmsInputEventFilter> m_dpmsFilter;
bool m_pointerLockRequested = false; bool m_pointerLockRequested = false;
int m_nextId = 0;
#if HAVE_WAYLAND_EGL #if HAVE_WAYLAND_EGL
FileDescriptor m_drmFileDescriptor; FileDescriptor m_drmFileDescriptor;
gbm_device *m_gbmDevice; gbm_device *m_gbmDevice;

View file

@ -7,12 +7,14 @@
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later
*/ */
#include "wayland_output.h" #include "wayland_output.h"
#include "core/renderloop.h" #include "core/renderloop_p.h"
#include "wayland_backend.h" #include "wayland_backend.h"
#include "wayland_display.h" #include "wayland_display.h"
#include "wayland_server.h" #include "wayland_server.h"
#include <KWayland/Client/compositor.h>
#include <KWayland/Client/pointerconstraints.h> #include <KWayland/Client/pointerconstraints.h>
#include <KWayland/Client/server_decoration.h>
#include <KWayland/Client/surface.h> #include <KWayland/Client/surface.h>
#include <KLocalizedString> #include <KLocalizedString>
@ -25,31 +27,80 @@ namespace Wayland
using namespace KWayland::Client; using namespace KWayland::Client;
static const int s_refreshRate = 60000; // TODO: can we get refresh rate data from Wayland host? 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> &&surface, WaylandBackend *backend) WaylandOutput::WaylandOutput(const QString &name, WaylandBackend *backend)
: Output(backend) : Output(backend)
, m_renderLoop(std::make_unique<RenderLoop>()) , m_renderLoop(std::make_unique<RenderLoop>())
, m_surface(std::move(surface)) , m_surface(backend->display()->compositor()->createSurface())
, m_xdgShellSurface(backend->display()->xdgShell()->createSurface(m_surface.get()))
, m_backend(backend) , 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{ setInformation(Information{
.name = name, .name = name,
.model = name, .model = name,
.capabilities = Capability::Dpms, .capabilities = Capability::Dpms,
}); });
connect(m_surface.get(), &Surface::frameRendered, this, &WaylandOutput::frameRendered);
m_turnOffTimer.setSingleShot(true); m_turnOffTimer.setSingleShot(true);
m_turnOffTimer.setInterval(dimAnimationTime()); m_turnOffTimer.setInterval(dimAnimationTime());
connect(&m_turnOffTimer, &QTimer::timeout, this, [this] { connect(&m_turnOffTimer, &QTimer::timeout, this, [this] {
updateDpmsMode(DpmsMode::Off); 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() WaylandOutput::~WaylandOutput()
{ {
m_xdgShellSurface->destroy();
m_surface->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 RenderLoop *WaylandOutput::renderLoop() const
{ {
return m_renderLoop.get(); return m_renderLoop.get();
@ -66,6 +117,8 @@ void WaylandOutput::init(const QSize &pixelSize)
initialState.currentMode = mode; initialState.currentMode = mode;
initialState.scale = m_backend->initialOutputScale(); initialState.scale = m_backend->initialOutputScale();
setState(initialState); setState(initialState);
m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
} }
void WaylandOutput::resize(const QSize &pixelSize) void WaylandOutput::resize(const QSize &pixelSize)
@ -113,49 +166,7 @@ void WaylandOutput::updateEnabled(bool enabled)
setState(next); setState(next);
} }
XdgShellOutput::XdgShellOutput(const QString &name, std::unique_ptr<Surface> &&waylandSurface, XdgShell *xdgShell, WaylandBackend *backend, int number) void WaylandOutput::handleConfigure(const QSize &size, XdgShellSurface::States states, quint32 serial)
: 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)
{ {
m_xdgShellSurface->ackConfigure(serial); m_xdgShellSurface->ackConfigure(serial);
if (size.width() > 0 && size.height() > 0) { if (size.width() > 0 && size.height() > 0) {
@ -168,17 +179,17 @@ void XdgShellOutput::handleConfigure(const QSize &size, XdgShellSurface::States
m_ready = true; m_ready = true;
} }
void XdgShellOutput::updateWindowTitle() void WaylandOutput::updateWindowTitle()
{ {
QString grab; QString grab;
if (m_hasPointerLock) { if (m_hasPointerLock) {
grab = i18n("Press right control to ungrab pointer"); 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"); grab = i18n("Press right control key to grab pointer");
} }
QString title = i18nc("Title of nested KWin Wayland with Wayland socket identifier as argument", 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()) { if (!isEnabled()) {
title += i18n("- Output disabled"); title += i18n("- Output disabled");
@ -190,32 +201,32 @@ void XdgShellOutput::updateWindowTitle()
m_xdgShellSurface->setTitle(title); m_xdgShellSurface->setTitle(title);
} }
void XdgShellOutput::lockPointer(Pointer *pointer, bool lock) void WaylandOutput::lockPointer(Pointer *pointer, bool lock)
{ {
if (!lock) { if (!lock) {
const bool surfaceWasLocked = m_pointerLock && m_hasPointerLock; const bool surfaceWasLocked = m_pointerLock && m_hasPointerLock;
m_pointerLock.reset(); m_pointerLock.reset();
m_hasPointerLock = false; m_hasPointerLock = false;
if (surfaceWasLocked) { if (surfaceWasLocked) {
Q_EMIT backend()->pointerLockChanged(false); Q_EMIT m_backend->pointerLockChanged(false);
} }
return; return;
} }
Q_ASSERT(!m_pointerLock); 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()) { if (!m_pointerLock->isValid()) {
m_pointerLock.reset(); m_pointerLock.reset();
return; return;
} }
connect(m_pointerLock.get(), &LockedPointer::locked, this, [this]() { connect(m_pointerLock.get(), &LockedPointer::locked, this, [this]() {
m_hasPointerLock = true; m_hasPointerLock = true;
Q_EMIT backend()->pointerLockChanged(true); Q_EMIT m_backend->pointerLockChanged(true);
}); });
connect(m_pointerLock.get(), &LockedPointer::unlocked, this, [this]() { connect(m_pointerLock.get(), &LockedPointer::unlocked, this, [this]() {
m_pointerLock.reset(); m_pointerLock.reset();
m_hasPointerLock = false; m_hasPointerLock = false;
Q_EMIT backend()->pointerLockChanged(false); Q_EMIT m_backend->pointerLockChanged(false);
}); });
} }

View file

@ -20,12 +20,9 @@ namespace KWayland
namespace Client namespace Client
{ {
class Surface; class Surface;
class Shell;
class ShellSurface;
class Pointer; class Pointer;
class LockedPointer; class LockedPointer;
class ServerSideDecoration;
} }
} }
@ -39,71 +36,36 @@ class WaylandOutput : public Output
{ {
Q_OBJECT Q_OBJECT
public: public:
WaylandOutput(const QString &name, std::unique_ptr<KWayland::Client::Surface> &&surface, WaylandBackend *backend); WaylandOutput(const QString &name, WaylandBackend *backend);
~WaylandOutput() override; ~WaylandOutput() override;
RenderLoop *renderLoop() const override; RenderLoop *renderLoop() const override;
void init(const QSize &pixelSize); void init(const QSize &pixelSize);
virtual void lockPointer(KWayland::Client::Pointer *pointer, bool lock) bool isReady() const;
{ KWayland::Client::Surface *surface() const;
}
virtual bool pointerIsLocked()
{
return false;
}
void lockPointer(KWayland::Client::Pointer *pointer, bool lock);
void resize(const QSize &pixelSize); void resize(const QSize &pixelSize);
KWayland::Client::Surface *surface() const
{
return m_surface.get();
}
void setDpmsMode(DpmsMode mode) override; void setDpmsMode(DpmsMode mode) override;
void updateDpmsMode(DpmsMode dpmsMode); void updateDpmsMode(DpmsMode dpmsMode);
void updateEnabled(bool enabled); void updateEnabled(bool enabled);
Q_SIGNALS: Q_SIGNALS:
void sizeChanged(const QSize &size); void sizeChanged(const QSize &size);
void frameRendered();
protected:
WaylandBackend *backend()
{
return m_backend;
}
private:
std::unique_ptr<RenderLoop> m_renderLoop;
std::unique_ptr<KWayland::Client::Surface> m_surface;
WaylandBackend *m_backend;
QTimer m_turnOffTimer;
};
class XdgShellOutput : public WaylandOutput
{
public:
XdgShellOutput(const QString &name,
std::unique_ptr<KWayland::Client::Surface> &&surface,
KWayland::Client::XdgShell *xdgShell,
WaylandBackend *backend, int number);
~XdgShellOutput() override;
void lockPointer(KWayland::Client::Pointer *pointer, bool lock) override;
bool isReady() const;
private: private:
void handleConfigure(const QSize &size, KWayland::Client::XdgShellSurface::States states, quint32 serial); void handleConfigure(const QSize &size, KWayland::Client::XdgShellSurface::States states, quint32 serial);
void updateWindowTitle(); void updateWindowTitle();
std::unique_ptr<RenderLoop> m_renderLoop;
std::unique_ptr<KWayland::Client::Surface> m_surface;
std::unique_ptr<KWayland::Client::XdgShellSurface> m_xdgShellSurface; std::unique_ptr<KWayland::Client::XdgShellSurface> m_xdgShellSurface;
int m_number;
std::unique_ptr<KWayland::Client::LockedPointer> m_pointerLock; std::unique_ptr<KWayland::Client::LockedPointer> m_pointerLock;
std::unique_ptr<KWayland::Client::ServerSideDecoration> m_serverDecoration;
WaylandBackend *const m_backend;
QTimer m_turnOffTimer;
bool m_hasPointerLock = false; bool m_hasPointerLock = false;
bool m_ready = false; bool m_ready = false;
}; };