From c784217eae8625f78e9b549a2e84e2bdcbc3fdeb Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Fri, 25 Nov 2022 20:03:37 +0200 Subject: [PATCH] backends/wayland: Use software cursor when pointer is locked Currently, if the pointer is locked, the wayland backend will create a subsurface. However, when the cursor moves to one of the screen edges, it looks weird because the xdg window geometry is computed as bounding geometry of the main surface and its subsurfaces. However, even after calling xdg_surface.set_window_geometry, it still looks weird because subsurfaces are stacked above window decoration. With the proposed change, when the pointer is locked, the wayland backend will hide the host compositor and use the software cursor. If the pointer is unlocked, it will go back to using host cursor. Long term goal is to make every output have its own cursor to make output layer logic simpler. --- src/backends/wayland/wayland_backend.cpp | 143 +++++------------------ src/backends/wayland/wayland_backend.h | 47 +------- src/backends/wayland/wayland_display.cpp | 9 -- src/backends/wayland/wayland_display.h | 3 - src/backends/wayland/wayland_output.cpp | 5 + src/backends/wayland/wayland_output.h | 1 + 6 files changed, 43 insertions(+), 165 deletions(-) diff --git a/src/backends/wayland/wayland_backend.cpp b/src/backends/wayland/wayland_backend.cpp index efd08332bd..c6dfca7e66 100644 --- a/src/backends/wayland/wayland_backend.cpp +++ b/src/backends/wayland/wayland_backend.cpp @@ -21,7 +21,6 @@ #include "cursor.h" #include "dpmsinputeventfilter.h" #include "input.h" -#include "pointer_input.h" #include #include @@ -32,8 +31,6 @@ #include #include #include -#include -#include #include #include @@ -58,127 +55,59 @@ using namespace KWayland::Client; WaylandCursor::WaylandCursor(WaylandBackend *backend) : m_backend(backend) + , m_surface(backend->display()->compositor()->createSurface()) { - resetSurface(); } WaylandCursor::~WaylandCursor() = default; -void WaylandCursor::resetSurface() +void WaylandCursor::enable() { - m_surface.reset(backend()->display()->compositor()->createSurface()); + Q_ASSERT(m_disableCount > 0); + --m_disableCount; + if (m_disableCount == 0) { + install(); + } } -void WaylandCursor::init() +void WaylandCursor::disable() { - installImage(); + ++m_disableCount; + if (m_disableCount == 1) { + uninstall(); + } } -void WaylandCursor::installImage() +void WaylandCursor::install() { const QImage image = Cursors::self()->currentCursor()->image(); - if (image.isNull() || image.size().isEmpty()) { - doInstallImage(nullptr, QSize(), 1); + if (m_disableCount || image.isNull() || image.size().isEmpty()) { + uninstall(); + return; + } + + auto *pointer = m_backend->seat()->pointerDevice()->nativePointer(); + if (!pointer || !pointer->isValid()) { return; } auto buffer = m_backend->display()->shmPool()->createBuffer(image).toStrongRef(); wl_buffer *imageBuffer = *buffer.data(); - doInstallImage(imageBuffer, image.size(), image.devicePixelRatio()); + + pointer->setCursor(m_surface.get(), imageBuffer ? Cursors::self()->currentCursor()->hotspot() : QPoint()); + m_surface->attachBuffer(imageBuffer); + m_surface->setScale(std::ceil(image.devicePixelRatio())); + m_surface->damageBuffer(image.rect()); + m_surface->commit(KWayland::Client::Surface::CommitFlag::None); } -void WaylandCursor::doInstallImage(wl_buffer *image, const QSize &size, qreal scale) +void WaylandCursor::uninstall() { auto *pointer = m_backend->seat()->pointerDevice()->nativePointer(); if (!pointer || !pointer->isValid()) { return; } - pointer->setCursor(m_surface.get(), image ? Cursors::self()->currentCursor()->hotspot() : QPoint()); - drawSurface(image, size, scale); -} - -void WaylandCursor::drawSurface(wl_buffer *image, const QSize &size, qreal scale) -{ - m_surface->attachBuffer(image); - m_surface->setScale(std::ceil(scale)); - m_surface->damageBuffer(QRect(QPoint(0, 0), size)); - m_surface->commit(KWayland::Client::Surface::CommitFlag::None); -} - -WaylandSubSurfaceCursor::WaylandSubSurfaceCursor(WaylandBackend *backend) - : WaylandCursor(backend) -{ -} - -WaylandSubSurfaceCursor::~WaylandSubSurfaceCursor() = default; - -void WaylandSubSurfaceCursor::init() -{ - if (auto *pointer = backend()->seat()->pointerDevice()->nativePointer()) { - pointer->hideCursor(); - } -} - -void WaylandSubSurfaceCursor::changeOutput(WaylandOutput *output) -{ - m_subSurface.reset(); - m_output = output; - if (!output) { - return; - } - createSubSurface(); - surface()->commit(); -} - -void WaylandSubSurfaceCursor::createSubSurface() -{ - if (m_subSurface) { - return; - } - if (!m_output) { - return; - } - resetSurface(); - m_subSurface.reset(backend()->display()->subCompositor()->createSubSurface(surface(), m_output->surface())); - m_subSurface->setMode(SubSurface::Mode::Desynchronized); -} - -void WaylandSubSurfaceCursor::doInstallImage(wl_buffer *image, const QSize &size, qreal scale) -{ - if (!image) { - m_subSurface.reset(); - return; - } - createSubSurface(); - // cursor position might have changed due to different cursor hot spot - move(input()->pointer()->pos()); - drawSurface(image, size, scale); -} - -QPointF WaylandSubSurfaceCursor::absoluteToRelativePosition(const QPointF &position) -{ - return position - m_output->geometry().topLeft() - Cursors::self()->currentCursor()->hotspot(); -} - -void WaylandSubSurfaceCursor::move(const QPointF &globalPosition) -{ - auto *output = backend()->getOutputAt(globalPosition.toPoint()); - if (!m_output || (output && m_output != output)) { - changeOutput(output); - if (!m_output) { - // cursor might be off the grid - return; - } - installImage(); - return; - } - if (!m_subSurface) { - return; - } - // place the sub-surface relative to the output it is on and factor in the hotspot - const auto relativePosition = globalPosition.toPoint() - Cursors::self()->currentCursor()->hotspot() - m_output->geometry().topLeft(); - m_subSurface->setPosition(relativePosition); - m_output->renderLoop()->scheduleRepaint(); + pointer->hideCursor(); } WaylandInputDevice::WaylandInputDevice(KWayland::Client::Keyboard *keyboard, WaylandSeat *seat) @@ -577,26 +506,16 @@ bool WaylandBackend::initialize() QObject::connect(dispatcher, &QAbstractEventDispatcher::awake, m_display.get(), &WaylandDisplay::flush); connect(Cursors::self(), &Cursors::currentCursorChanged, this, [this]() { - if (!m_seat || !m_waylandCursor) { - return; - } - m_waylandCursor->installImage(); - }); - connect(Cursors::self(), &Cursors::positionChanged, this, [this](Cursor *cursor, const QPoint &position) { - if (m_waylandCursor) { - m_waylandCursor->move(position); - } + m_waylandCursor->install(); }); connect(this, &WaylandBackend::pointerLockChanged, this, [this](bool locked) { if (locked) { - m_waylandCursor = std::make_unique(this); - m_waylandCursor->move(input()->pointer()->pos()); + m_waylandCursor->disable(); m_seat->createRelativePointer(); } else { m_seat->destroyRelativePointer(); - m_waylandCursor = std::make_unique(this); + m_waylandCursor->enable(); } - m_waylandCursor->init(); }); return true; diff --git a/src/backends/wayland/wayland_backend.h b/src/backends/wayland/wayland_backend.h index 9f24f18fab..01c73af149 100644 --- a/src/backends/wayland/wayland_backend.h +++ b/src/backends/wayland/wayland_backend.h @@ -38,7 +38,6 @@ class PointerSwipeGesture; class PointerPinchGesture; class RelativePointer; class Seat; -class SubSurface; class Surface; class Touch; } @@ -61,52 +60,18 @@ class WaylandCursor { public: explicit WaylandCursor(WaylandBackend *backend); - virtual ~WaylandCursor(); + ~WaylandCursor(); - virtual void init(); - virtual void move(const QPointF &globalPosition) - { - } + void enable(); + void disable(); - void installImage(); - -protected: - void resetSurface(); - virtual void doInstallImage(wl_buffer *image, const QSize &size, qreal scale); - void drawSurface(wl_buffer *image, const QSize &size, qreal scale); - - KWayland::Client::Surface *surface() const - { - return m_surface.get(); - } - WaylandBackend *backend() const - { - return m_backend; - } + void install(); + void uninstall(); private: WaylandBackend *const m_backend; std::unique_ptr m_surface; -}; - -class WaylandSubSurfaceCursor : public WaylandCursor -{ -public: - explicit WaylandSubSurfaceCursor(WaylandBackend *backend); - ~WaylandSubSurfaceCursor() override; - - void init() override; - - void move(const QPointF &globalPosition) override; - -private: - void changeOutput(WaylandOutput *output); - void doInstallImage(wl_buffer *image, const QSize &size, qreal scale) override; - void createSubSurface(); - - QPointF absoluteToRelativePosition(const QPointF &position); - WaylandOutput *m_output = nullptr; - std::unique_ptr m_subSurface; + int m_disableCount = 0; }; class WaylandInputDevice : public InputDevice diff --git a/src/backends/wayland/wayland_display.cpp b/src/backends/wayland/wayland_display.cpp index 3f483e6424..72f3b9ce1d 100644 --- a/src/backends/wayland/wayland_display.cpp +++ b/src/backends/wayland/wayland_display.cpp @@ -162,7 +162,6 @@ WaylandDisplay::~WaylandDisplay() m_seat.reset(); m_xdgDecorationManager.reset(); m_shmPool.reset(); - m_subCompositor.reset(); m_xdgShell.reset(); if (m_registry) { @@ -230,11 +229,6 @@ KWayland::Client::ShmPool *WaylandDisplay::shmPool() const return m_shmPool.get(); } -KWayland::Client::SubCompositor *WaylandDisplay::subCompositor() const -{ - return m_subCompositor.get(); -} - KWayland::Client::Seat *WaylandDisplay::seat() const { return m_seat.get(); @@ -260,9 +254,6 @@ void WaylandDisplay::registry_global(void *data, wl_registry *registry, uint32_t } display->m_compositor = std::make_unique(); display->m_compositor->setup(static_cast(wl_registry_bind(registry, name, &wl_compositor_interface, std::min(version, 4u)))); - } else if (strcmp(interface, wl_subcompositor_interface.name) == 0) { - display->m_subCompositor = std::make_unique(); - display->m_subCompositor->setup(static_cast(wl_registry_bind(registry, name, &wl_subcompositor_interface, std::min(version, 1u)))); } else if (strcmp(interface, wl_shm_interface.name) == 0) { display->m_shmPool = std::make_unique(); display->m_shmPool->setup(static_cast(wl_registry_bind(registry, name, &wl_shm_interface, std::min(version, 1u)))); diff --git a/src/backends/wayland/wayland_display.h b/src/backends/wayland/wayland_display.h index 0975321ce4..e8dd286fec 100644 --- a/src/backends/wayland/wayland_display.h +++ b/src/backends/wayland/wayland_display.h @@ -23,7 +23,6 @@ class PointerGestures; class RelativePointerManager; class Seat; class ShmPool; -class SubCompositor; class XdgDecorationManager; class XdgShell; } @@ -54,7 +53,6 @@ public: KWayland::Client::Seat *seat() const; KWayland::Client::XdgDecorationManager *xdgDecorationManager() const; KWayland::Client::ShmPool *shmPool() const; - KWayland::Client::SubCompositor *subCompositor() const; KWayland::Client::XdgShell *xdgShell() const; public Q_SLOTS: @@ -74,7 +72,6 @@ private: std::unique_ptr m_seat; std::unique_ptr m_xdgDecorationManager; std::unique_ptr m_shmPool; - std::unique_ptr m_subCompositor; std::unique_ptr m_xdgShell; }; diff --git a/src/backends/wayland/wayland_output.cpp b/src/backends/wayland/wayland_output.cpp index 5625093f52..b4ca9638e9 100644 --- a/src/backends/wayland/wayland_output.cpp +++ b/src/backends/wayland/wayland_output.cpp @@ -86,6 +86,11 @@ RenderLoop *WaylandOutput::renderLoop() const return m_renderLoop.get(); } +bool WaylandOutput::usesSoftwareCursor() const +{ + return m_hasPointerLock; +} + void WaylandOutput::init(const QSize &pixelSize, qreal scale) { m_renderLoop->setRefreshRate(s_refreshRate); diff --git a/src/backends/wayland/wayland_output.h b/src/backends/wayland/wayland_output.h index 46635efecf..b1d05538af 100644 --- a/src/backends/wayland/wayland_output.h +++ b/src/backends/wayland/wayland_output.h @@ -40,6 +40,7 @@ public: ~WaylandOutput() override; RenderLoop *renderLoop() const override; + bool usesSoftwareCursor() const override; void init(const QSize &pixelSize, qreal scale);