[wayland] Properly handle Cursor set on focused PointerInterface

This replaces getting the Cursor through the X11CursorTracker which
is now completely dropped. The Cursor data is now passed through from
the Wayland server and forwared to the WaylandBackend.
This commit is contained in:
Martin Gräßlin 2015-02-27 17:46:41 +01:00
parent 9ca992a329
commit f600e2f6f4
3 changed files with 47 additions and 175 deletions

View file

@ -33,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "libinput/connection.h"
#endif
#if HAVE_WAYLAND
#include "wayland_backend.h"
#include "wayland_server.h"
#include <KWayland/Server/seat_interface.h>
#endif
@ -267,10 +268,17 @@ void InputRedirection::updatePointerWindow()
// disconnect old surface
if (oldWindow) {
disconnect(oldWindow.data(), &Toplevel::geometryChanged, this, &InputRedirection::updateFocusedPointerPosition);
if (Wayland::WaylandBackend *w = Wayland::WaylandBackend::self()) {
disconnect(seat->focusedPointer()->cursor(), &KWayland::Server::Cursor::changed, w, &Wayland::WaylandBackend::installCursorFromServer);
}
}
if (t && t->surface()) {
seat->setFocusedPointerSurface(t->surface(), t->pos());
connect(t, &Toplevel::geometryChanged, this, &InputRedirection::updateFocusedPointerPosition);
if (Wayland::WaylandBackend *w = Wayland::WaylandBackend::self()) {
w->installCursorFromServer();
connect(seat->focusedPointer()->cursor(), &KWayland::Server::Cursor::changed, w, &Wayland::WaylandBackend::installCursorFromServer);
}
} else {
seat->setFocusedPointerSurface(nullptr);
t = nullptr;

View file

@ -41,15 +41,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Client/subcompositor.h>
#include <KWayland/Client/subsurface.h>
#include <KWayland/Client/surface.h>
#include <KWayland/Server/buffer_interface.h>
#include <KWayland/Server/seat_interface.h>
#include <KWayland/Server/surface_interface.h>
// Qt
#include <QAbstractEventDispatcher>
#include <QCoreApplication>
#include <QDebug>
#include <QMetaMethod>
#include <QThread>
// xcb
#include <xcb/xfixes.h>
// Wayland
#include <wayland-client-protocol.h>
#include <wayland-cursor.h>
@ -61,97 +61,6 @@ namespace Wayland
using namespace KWayland::Client;
CursorData::CursorData()
: m_valid(init())
{
}
CursorData::~CursorData()
{
}
bool CursorData::init()
{
QScopedPointer<xcb_xfixes_get_cursor_image_reply_t, QScopedPointerPodDeleter> cursor(
xcb_xfixes_get_cursor_image_reply(connection(),
xcb_xfixes_get_cursor_image_unchecked(connection()),
NULL));
if (cursor.isNull()) {
return false;
}
QImage cursorImage((uchar *) xcb_xfixes_get_cursor_image_cursor_image(cursor.data()), cursor->width, cursor->height,
QImage::Format_ARGB32_Premultiplied);
if (cursorImage.isNull()) {
return false;
}
// the backend for the cursorImage is destroyed once the xcb cursor goes out of scope
// because of that we create a copy
m_cursor = cursorImage.copy();
m_hotSpot = QPoint(cursor->xhot, cursor->yhot);
return true;
}
X11CursorTracker::X11CursorTracker(WaylandBackend *backend, QObject* parent)
: QObject(parent)
, m_backend(backend)
, m_lastX11Cursor(0)
{
Cursor::self()->startCursorTracking();
connect(Cursor::self(), SIGNAL(cursorChanged(uint32_t)), SLOT(cursorChanged(uint32_t)));
}
X11CursorTracker::~X11CursorTracker()
{
if (Cursor::self()) {
// Cursor might have been destroyed before Wayland backend gets destroyed
Cursor::self()->stopCursorTracking();
}
}
void X11CursorTracker::cursorChanged(uint32_t serial)
{
if (m_lastX11Cursor == serial) {
// not changed;
return;
}
m_lastX11Cursor = serial;
QHash<uint32_t, CursorData>::iterator it = m_cursors.find(serial);
if (it != m_cursors.end()) {
installCursor(it.value());
return;
}
ShmPool *pool = m_backend->shmPool();
if (!pool->isValid()) {
return;
}
CursorData cursor;
if (cursor.isValid()) {
// TODO: discard unused cursors after some time?
m_cursors.insert(serial, cursor);
}
installCursor(cursor);
}
void X11CursorTracker::installCursor(const CursorData& cursor)
{
const QImage &cursorImage = cursor.cursor();
auto buffer = m_backend->shmPool()->createBuffer(cursorImage);
if (!buffer) {
return;
}
emit cursorImageChanged(buffer, cursorImage.size(), cursor.hotSpot());
}
void X11CursorTracker::resetCursor()
{
QHash<uint32_t, CursorData>::iterator it = m_cursors.find(m_lastX11Cursor);
if (it != m_cursors.end()) {
installCursor(it.value());
}
}
WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend)
: QObject(NULL)
, m_seat(new Seat(this))
@ -244,14 +153,6 @@ WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend)
input()->processPointerAxis(toAxis(), delta, time);
}
);
connect(m_backend->cursorTracker(), &X11CursorTracker::cursorImageChanged, this,
[this](Buffer::Ptr image, const QSize &size, const QPoint &hotspot) {
if (image.isNull()) {
return;
}
installCursorImage(image.toStrongRef()->buffer(), size, hotspot);
}
);
} else {
destroyPointer();
}
@ -317,6 +218,11 @@ void WaylandSeat::installCursorImage(Qt::CursorShape shape)
QPoint(image->hotspot_x, image->hotspot_y));
}
void WaylandSeat::installCursorImage(const QImage &image, const QPoint &hotSpot)
{
installCursorImage(*(m_backend->shmPool()->createBuffer(image).data()), image.size(), hotSpot);
}
void WaylandSeat::setInstallCursor(bool install)
{
// TODO: remove, add?
@ -381,14 +287,6 @@ WaylandCursor::WaylandCursor(Surface *parentSurface, WaylandBackend *backend)
auto surface = backend->compositor()->createSurface(this);
m_subSurface = backend->subCompositor()->createSubSurface(QPointer<Surface>(surface), QPointer<Surface>(parentSurface), this);
connect(m_backend->cursorTracker(), &X11CursorTracker::cursorImageChanged, this,
[this](Buffer::Ptr image, const QSize &size, const QPoint &hotspot) {
if (image.isNull()) {
return;
}
setCursorImage(image.toStrongRef()->buffer(), size, hotspot);
}
);
connect(Cursor::self(), &Cursor::posChanged, this,
[this](const QPoint &pos) {
m_subSurface->setPosition(pos - m_hotSpot);
@ -432,6 +330,11 @@ void WaylandCursor::setCursorImage(wl_buffer *image, const QSize &size, const QP
parent->commit(Surface::CommitFlag::None);
}
void WaylandCursor::setCursorImage(const QImage &image, const QPoint &hotspot)
{
setCursorImage(*(m_backend->shmPool()->createBuffer(image).data()), image.size(), hotspot);
}
void WaylandCursor::setCursorImage(Qt::CursorShape shape)
{
wl_cursor_image *image = m_theme->get(shape);
@ -462,7 +365,6 @@ WaylandBackend::WaylandBackend(QObject *parent)
, m_shellSurface(NULL)
, m_seat()
, m_shm(new ShmPool(this))
, m_cursorTracker()
, m_connectionThreadObject(nullptr)
, m_connectionThread(nullptr)
, m_fullscreenShell(new FullscreenShell(this))
@ -558,14 +460,12 @@ void WaylandBackend::initConnection()
// setup registry
m_registry->create(m_display);
m_registry->setup();
m_cursorTracker.reset(new X11CursorTracker(this, this));
},
Qt::QueuedConnection);
connect(m_connectionThreadObject, &ConnectionThread::connectionDied, this,
[this]() {
m_ready = false;
emit systemCompositorDied();
m_cursorTracker.reset();
m_seat.reset();
m_shm->destroy();
destroyOutputs();
@ -609,6 +509,30 @@ void WaylandBackend::installCursorImage(Qt::CursorShape shape)
}
}
void WaylandBackend::installCursorFromServer()
{
if (!waylandServer() || !waylandServer()->seat()->focusedPointer()) {
return;
}
auto c = waylandServer()->seat()->focusedPointer()->cursor();
if (c) {
auto cursorSurface = c->surface();
if (!cursorSurface.isNull()) {
auto buffer = cursorSurface.data()->buffer();
if (buffer) {
// set cursor
if (!m_seat.isNull() && m_seat->isInstallCursor()) {
m_seat->installCursorImage(buffer->data(), c->hotspot());
} else if (m_cursor) {
m_cursor->setCursorImage(buffer->data(), c->hotspot());
}
return;
}
}
}
// TODO: unset cursor
}
void WaylandBackend::createSurface()
{
m_surface = m_compositor->createSurface(this);
@ -642,7 +566,6 @@ void WaylandBackend::createSurface()
// map the surface as fullscreen
m_shellSurface = m_shell->createSurface(m_surface, this);
m_shellSurface->setFullscreen();
connect(m_shellSurface, &ShellSurface::pinged, m_cursorTracker.data(), &X11CursorTracker::resetCursor);
connect(m_shellSurface, &ShellSurface::sizeChanged, this, &WaylandBackend::shellSurfaceSizeChanged);
}
}

View file

@ -68,42 +68,6 @@ namespace Wayland
class WaylandBackend;
class WaylandSeat;
class CursorData
{
public:
CursorData();
~CursorData();
bool isValid() const;
const QPoint &hotSpot() const;
const QImage &cursor() const;
private:
bool init();
QImage m_cursor;
QPoint m_hotSpot;
bool m_valid;
};
class X11CursorTracker : public QObject
{
Q_OBJECT
public:
explicit X11CursorTracker(WaylandBackend *backend, QObject* parent = 0);
virtual ~X11CursorTracker();
void resetCursor();
Q_SIGNALS:
void cursorImageChanged(QWeakPointer<KWayland::Client::Buffer> image, const QSize &size, const QPoint &hotSpot);
private Q_SLOTS:
void cursorChanged(uint32_t serial);
private:
void installCursor(const CursorData &cursor);
QHash<uint32_t, CursorData> m_cursors;
WaylandBackend *m_backend;
uint32_t m_installedCursor;
uint32_t m_lastX11Cursor;
};
class WaylandCursorTheme : public QObject
{
Q_OBJECT
@ -129,6 +93,7 @@ public:
void installCursorImage(wl_buffer *image, const QSize &size, const QPoint &hotspot);
void installCursorImage(Qt::CursorShape shape);
void installCursorImage(const QImage &image, const QPoint &hotspot);
void setInstallCursor(bool install);
bool isInstallCursor() const {
return m_installCursor;
@ -157,6 +122,7 @@ public:
return m_hotSpot;
}
void setCursorImage(wl_buffer *image, const QSize &size, const QPoint &hotspot);
void setCursorImage(const QImage &image, const QPoint &hotspot);
void setCursorImage(Qt::CursorShape shape);
Q_SIGNALS:
@ -185,11 +151,11 @@ public:
const QList<KWayland::Client::Output*> &outputs() const;
KWayland::Client::ShmPool *shmPool();
KWayland::Client::SubCompositor *subCompositor();
X11CursorTracker *cursorTracker();
KWayland::Client::Surface *surface() const;
QSize shellSurfaceSize() const;
void installCursorImage(Qt::CursorShape shape);
void installCursorFromServer();
protected:
void connectNotify(const QMetaMethod &signal) override;
@ -214,7 +180,6 @@ private:
KWayland::Client::ShellSurface *m_shellSurface;
QScopedPointer<WaylandSeat> m_seat;
KWayland::Client::ShmPool *m_shm;
QScopedPointer<X11CursorTracker> m_cursorTracker;
QList<KWayland::Client::Output*> m_outputs;
KWayland::Client::ConnectionThread *m_connectionThreadObject;
QThread *m_connectionThread;
@ -226,24 +191,6 @@ private:
KWIN_SINGLETON(WaylandBackend)
};
inline
bool CursorData::isValid() const
{
return m_valid;
}
inline
const QPoint& CursorData::hotSpot() const
{
return m_hotSpot;
}
inline
const QImage &CursorData::cursor() const
{
return m_cursor;
}
inline
wl_display *WaylandBackend::display()
{
@ -268,12 +215,6 @@ KWayland::Client::ShmPool* WaylandBackend::shmPool()
return m_shm;
}
inline
X11CursorTracker *WaylandBackend::cursorTracker()
{
return m_cursorTracker.data();
}
inline
KWayland::Client::Surface *WaylandBackend::surface() const
{