backends/wayland: Provide a cursor per output
It allows us to track cursor state per output and make it more straightforward to introduce cursor layers in general.
This commit is contained in:
parent
68517a5806
commit
245dcd2b80
4 changed files with 114 additions and 95 deletions
|
@ -18,19 +18,14 @@
|
|||
#include "wayland_output.h"
|
||||
#include "wayland_qpainter_backend.h"
|
||||
|
||||
#include "cursor.h"
|
||||
#include "dpmsinputeventfilter.h"
|
||||
#include "input.h"
|
||||
|
||||
#include <KWayland/Client/buffer.h>
|
||||
#include <KWayland/Client/compositor.h>
|
||||
#include <KWayland/Client/keyboard.h>
|
||||
#include <KWayland/Client/pointer.h>
|
||||
#include <KWayland/Client/pointerconstraints.h>
|
||||
#include <KWayland/Client/pointergestures.h>
|
||||
#include <KWayland/Client/relativepointer.h>
|
||||
#include <KWayland/Client/seat.h>
|
||||
#include <KWayland/Client/shm_pool.h>
|
||||
#include <KWayland/Client/surface.h>
|
||||
#include <KWayland/Client/touch.h>
|
||||
|
||||
|
@ -41,7 +36,6 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "../drm/gbm_dmabuf.h"
|
||||
#include <cmath>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
#define QSIZE_TO_QPOINT(size) QPointF(size.width(), size.height())
|
||||
|
@ -53,63 +47,6 @@ namespace Wayland
|
|||
|
||||
using namespace KWayland::Client;
|
||||
|
||||
WaylandCursor::WaylandCursor(WaylandBackend *backend)
|
||||
: m_backend(backend)
|
||||
, m_surface(backend->display()->compositor()->createSurface())
|
||||
{
|
||||
}
|
||||
|
||||
WaylandCursor::~WaylandCursor() = default;
|
||||
|
||||
void WaylandCursor::enable()
|
||||
{
|
||||
Q_ASSERT(m_disableCount > 0);
|
||||
--m_disableCount;
|
||||
if (m_disableCount == 0) {
|
||||
install();
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandCursor::disable()
|
||||
{
|
||||
++m_disableCount;
|
||||
if (m_disableCount == 1) {
|
||||
uninstall();
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandCursor::install()
|
||||
{
|
||||
const QImage image = Cursors::self()->currentCursor()->image();
|
||||
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();
|
||||
|
||||
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::uninstall()
|
||||
{
|
||||
auto *pointer = m_backend->seat()->pointerDevice()->nativePointer();
|
||||
if (!pointer || !pointer->isValid()) {
|
||||
return;
|
||||
}
|
||||
pointer->hideCursor();
|
||||
}
|
||||
|
||||
WaylandInputDevice::WaylandInputDevice(KWayland::Client::Keyboard *keyboard, WaylandSeat *seat)
|
||||
: m_seat(seat)
|
||||
, m_keyboard(keyboard)
|
||||
|
@ -138,7 +75,19 @@ WaylandInputDevice::WaylandInputDevice(KWayland::Client::Pointer *pointer, Wayla
|
|||
, m_pointer(pointer)
|
||||
{
|
||||
connect(pointer, &Pointer::entered, this, [this](quint32 serial, const QPointF &relativeToSurface) {
|
||||
m_seat->backend()->cursor()->install();
|
||||
WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface());
|
||||
Q_ASSERT(output);
|
||||
output->cursor()->setPointer(m_pointer.get());
|
||||
});
|
||||
connect(pointer, &Pointer::left, this, [this]() {
|
||||
// wl_pointer.leave carries the wl_surface, but KWayland::Client::Pointer::left does not.
|
||||
const auto outputs = m_seat->backend()->outputs();
|
||||
for (Output *output : outputs) {
|
||||
WaylandOutput *waylandOutput = static_cast<WaylandOutput *>(output);
|
||||
if (waylandOutput->cursor()->pointer()) {
|
||||
waylandOutput->cursor()->setPointer(nullptr);
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(pointer, &Pointer::motion, this, [this](const QPointF &relativeToSurface, quint32 time) {
|
||||
WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface());
|
||||
|
@ -479,7 +428,6 @@ WaylandBackend::~WaylandBackend()
|
|||
|
||||
destroyOutputs();
|
||||
|
||||
m_waylandCursor.reset();
|
||||
m_seat.reset();
|
||||
m_display.reset();
|
||||
|
||||
|
@ -499,22 +447,16 @@ bool WaylandBackend::initialize()
|
|||
createOutputs();
|
||||
|
||||
m_seat = std::make_unique<WaylandSeat>(m_display->seat(), this);
|
||||
m_waylandCursor = std::make_unique<WaylandCursor>(this);
|
||||
|
||||
QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance();
|
||||
QObject::connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_display.get(), &WaylandDisplay::flush);
|
||||
QObject::connect(dispatcher, &QAbstractEventDispatcher::awake, m_display.get(), &WaylandDisplay::flush);
|
||||
|
||||
connect(Cursors::self(), &Cursors::currentCursorChanged, this, [this]() {
|
||||
m_waylandCursor->install();
|
||||
});
|
||||
connect(this, &WaylandBackend::pointerLockChanged, this, [this](bool locked) {
|
||||
if (locked) {
|
||||
m_waylandCursor->disable();
|
||||
m_seat->createRelativePointer();
|
||||
} else {
|
||||
m_seat->destroyRelativePointer();
|
||||
m_waylandCursor->enable();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <QPoint>
|
||||
#include <QSize>
|
||||
|
||||
struct wl_buffer;
|
||||
struct wl_display;
|
||||
struct gbm_device;
|
||||
struct gbm_bo;
|
||||
|
@ -56,24 +55,6 @@ class WaylandOutput;
|
|||
class WaylandEglBackend;
|
||||
class WaylandDisplay;
|
||||
|
||||
class WaylandCursor
|
||||
{
|
||||
public:
|
||||
explicit WaylandCursor(WaylandBackend *backend);
|
||||
~WaylandCursor();
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
void install();
|
||||
void uninstall();
|
||||
|
||||
private:
|
||||
WaylandBackend *const m_backend;
|
||||
std::unique_ptr<KWayland::Client::Surface> m_surface;
|
||||
int m_disableCount = 0;
|
||||
};
|
||||
|
||||
class WaylandInputDevice : public InputDevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -218,10 +199,6 @@ public:
|
|||
{
|
||||
return m_seat.get();
|
||||
}
|
||||
WaylandCursor *cursor() const
|
||||
{
|
||||
return m_waylandCursor.get();
|
||||
}
|
||||
|
||||
bool supportsPointerLock();
|
||||
void togglePointerLock();
|
||||
|
@ -267,7 +244,6 @@ private:
|
|||
std::unique_ptr<WaylandSeat> m_seat;
|
||||
WaylandEglBackend *m_eglBackend = nullptr;
|
||||
QVector<WaylandOutput *> m_outputs;
|
||||
std::unique_ptr<WaylandCursor> m_waylandCursor;
|
||||
std::unique_ptr<DpmsInputEventFilter> m_dpmsFilter;
|
||||
bool m_pointerLockRequested = false;
|
||||
#if HAVE_WAYLAND_EGL
|
||||
|
|
|
@ -8,17 +8,22 @@
|
|||
*/
|
||||
#include "wayland_output.h"
|
||||
#include "core/renderloop_p.h"
|
||||
#include "cursor.h"
|
||||
#include "wayland_backend.h"
|
||||
#include "wayland_display.h"
|
||||
#include "wayland_server.h"
|
||||
|
||||
#include <KWayland/Client/compositor.h>
|
||||
#include <KWayland/Client/pointer.h>
|
||||
#include <KWayland/Client/pointerconstraints.h>
|
||||
#include <KWayland/Client/shm_pool.h>
|
||||
#include <KWayland/Client/surface.h>
|
||||
#include <KWayland/Client/xdgdecoration.h>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
namespace Wayland
|
||||
|
@ -27,12 +32,73 @@ namespace Wayland
|
|||
using namespace KWayland::Client;
|
||||
static const int s_refreshRate = 60000; // TODO: can we get refresh rate data from Wayland host?
|
||||
|
||||
WaylandCursor::WaylandCursor(WaylandBackend *backend)
|
||||
: m_backend(backend)
|
||||
, m_surface(backend->display()->compositor()->createSurface())
|
||||
{
|
||||
}
|
||||
|
||||
WaylandCursor::~WaylandCursor() = default;
|
||||
|
||||
KWayland::Client::Pointer *WaylandCursor::pointer() const
|
||||
{
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
void WaylandCursor::setPointer(KWayland::Client::Pointer *pointer)
|
||||
{
|
||||
if (m_pointer == pointer) {
|
||||
return;
|
||||
}
|
||||
m_pointer = pointer;
|
||||
if (m_pointer) {
|
||||
m_pointer->setCursor(m_surface.get(), m_hotspot);
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandCursor::enable()
|
||||
{
|
||||
if (!m_enabled) {
|
||||
m_enabled = true;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandCursor::disable()
|
||||
{
|
||||
if (m_enabled) {
|
||||
m_enabled = false;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandCursor::update()
|
||||
{
|
||||
const QImage image = Cursors::self()->currentCursor()->image();
|
||||
if (!m_enabled || Cursors::self()->isCursorHidden() || image.isNull()) {
|
||||
m_surface->attachBuffer(KWayland::Client::Buffer::Ptr());
|
||||
m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
m_hotspot = QPoint();
|
||||
} else {
|
||||
m_surface->attachBuffer(m_backend->display()->shmPool()->createBuffer(image));
|
||||
m_surface->setScale(std::ceil(image.devicePixelRatio()));
|
||||
m_surface->damageBuffer(image.rect());
|
||||
m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
m_hotspot = Cursors::self()->currentCursor()->hotspot();
|
||||
}
|
||||
|
||||
if (m_pointer) {
|
||||
m_pointer->setCursor(m_surface.get(), m_hotspot);
|
||||
}
|
||||
}
|
||||
|
||||
WaylandOutput::WaylandOutput(const QString &name, WaylandBackend *backend)
|
||||
: Output(backend)
|
||||
, m_renderLoop(std::make_unique<RenderLoop>())
|
||||
, m_surface(backend->display()->compositor()->createSurface())
|
||||
, m_xdgShellSurface(backend->display()->xdgShell()->createSurface(m_surface.get()))
|
||||
, m_backend(backend)
|
||||
, m_cursor(std::make_unique<WaylandCursor>(backend))
|
||||
{
|
||||
if (KWayland::Client::XdgDecorationManager *manager = m_backend->display()->xdgDecorationManager()) {
|
||||
m_xdgDecoration.reset(manager->getToplevelDecoration(m_xdgShellSurface.get()));
|
||||
|
@ -62,6 +128,10 @@ WaylandOutput::WaylandOutput(const QString &name, WaylandBackend *backend)
|
|||
connect(m_xdgShellSurface.get(), &XdgShellSurface::closeRequested, qApp, &QCoreApplication::quit);
|
||||
connect(this, &WaylandOutput::enabledChanged, this, &WaylandOutput::updateWindowTitle);
|
||||
connect(this, &WaylandOutput::dpmsModeChanged, this, &WaylandOutput::updateWindowTitle);
|
||||
|
||||
connect(Cursors::self(), &Cursors::currentCursorChanged, this, [this]() {
|
||||
m_cursor->update();
|
||||
});
|
||||
}
|
||||
|
||||
WaylandOutput::~WaylandOutput()
|
||||
|
@ -81,6 +151,11 @@ KWayland::Client::Surface *WaylandOutput::surface() const
|
|||
return m_surface.get();
|
||||
}
|
||||
|
||||
WaylandCursor *WaylandOutput::cursor() const
|
||||
{
|
||||
return m_cursor.get();
|
||||
}
|
||||
|
||||
RenderLoop *WaylandOutput::renderLoop() const
|
||||
{
|
||||
return m_renderLoop.get();
|
||||
|
@ -191,6 +266,7 @@ void WaylandOutput::lockPointer(Pointer *pointer, bool lock)
|
|||
m_hasPointerLock = false;
|
||||
if (surfaceWasLocked) {
|
||||
updateWindowTitle();
|
||||
m_cursor->enable();
|
||||
Q_EMIT m_backend->pointerLockChanged(false);
|
||||
}
|
||||
return;
|
||||
|
@ -205,12 +281,14 @@ void WaylandOutput::lockPointer(Pointer *pointer, bool lock)
|
|||
connect(m_pointerLock.get(), &LockedPointer::locked, this, [this]() {
|
||||
m_hasPointerLock = true;
|
||||
updateWindowTitle();
|
||||
m_cursor->disable();
|
||||
Q_EMIT m_backend->pointerLockChanged(true);
|
||||
});
|
||||
connect(m_pointerLock.get(), &LockedPointer::unlocked, this, [this]() {
|
||||
m_pointerLock.reset();
|
||||
m_hasPointerLock = false;
|
||||
updateWindowTitle();
|
||||
m_cursor->enable();
|
||||
Q_EMIT m_backend->pointerLockChanged(false);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -32,6 +32,27 @@ namespace Wayland
|
|||
{
|
||||
class WaylandBackend;
|
||||
|
||||
class WaylandCursor
|
||||
{
|
||||
public:
|
||||
explicit WaylandCursor(WaylandBackend *backend);
|
||||
~WaylandCursor();
|
||||
|
||||
KWayland::Client::Pointer *pointer() const;
|
||||
void setPointer(KWayland::Client::Pointer *pointer);
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
void update();
|
||||
|
||||
private:
|
||||
WaylandBackend *const m_backend;
|
||||
KWayland::Client::Pointer *m_pointer = nullptr;
|
||||
std::unique_ptr<KWayland::Client::Surface> m_surface;
|
||||
QPoint m_hotspot;
|
||||
bool m_enabled = true;
|
||||
};
|
||||
|
||||
class WaylandOutput : public Output
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -46,6 +67,7 @@ public:
|
|||
|
||||
bool isReady() const;
|
||||
KWayland::Client::Surface *surface() const;
|
||||
WaylandCursor *cursor() const;
|
||||
|
||||
void lockPointer(KWayland::Client::Pointer *pointer, bool lock);
|
||||
void resize(const QSize &pixelSize);
|
||||
|
@ -63,6 +85,7 @@ private:
|
|||
std::unique_ptr<KWayland::Client::LockedPointer> m_pointerLock;
|
||||
std::unique_ptr<KWayland::Client::XdgDecoration> m_xdgDecoration;
|
||||
WaylandBackend *const m_backend;
|
||||
std::unique_ptr<WaylandCursor> m_cursor;
|
||||
QTimer m_turnOffTimer;
|
||||
bool m_hasPointerLock = false;
|
||||
bool m_ready = false;
|
||||
|
|
Loading…
Reference in a new issue