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 <gbm.h>
#endif
#include "core/renderloop_p.h"
#include "wayland_display.h"
#include "wayland_logging.h"
#include "wayland_output.h"
@ -35,7 +34,6 @@
#include <KWayland/Client/pointergestures.h>
#include <KWayland/Client/relativepointer.h>
#include <KWayland/Client/seat.h>
#include <KWayland/Client/server_decoration.h>
#include <KWayland/Client/shm_pool.h>
#include <KWayland/Client/subcompositor.h>
#include <KWayland/Client/subsurface.h>
@ -631,27 +629,7 @@ void WaylandBackend::createOutputs()
WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size)
{
std::unique_ptr<KWayland::Client::Surface> 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<CompositingType> WaylandBackend::supportedCompositors() const
{
#if HAVE_WAYLAND_EGL

View file

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

View file

@ -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 <KWayland/Client/compositor.h>
#include <KWayland/Client/pointerconstraints.h>
#include <KWayland/Client/server_decoration.h>
#include <KWayland/Client/surface.h>
#include <KLocalizedString>
@ -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> &&surface, WaylandBackend *backend)
WaylandOutput::WaylandOutput(const QString &name, WaylandBackend *backend)
: Output(backend)
, 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)
{
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<Surface> &&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);
});
}

View file

@ -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<KWayland::Client::Surface> &&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<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:
void handleConfigure(const QSize &size, KWayland::Client::XdgShellSurface::States states, quint32 serial);
void updateWindowTitle();
std::unique_ptr<RenderLoop> m_renderLoop;
std::unique_ptr<KWayland::Client::Surface> m_surface;
std::unique_ptr<KWayland::Client::XdgShellSurface> m_xdgShellSurface;
int m_number;
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_ready = false;
};