diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9f1007f4a..dd633bd0f7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -270,6 +270,7 @@ set(kwin_XCB_LIBS
set(kwin_WAYLAND_LIBS
Wayland::Client
+ Wayland::Cursor
XCB::XTEST
)
diff --git a/wayland_backend.cpp b/wayland_backend.cpp
index 729dd617dc..1c38c778a5 100644
--- a/wayland_backend.cpp
+++ b/wayland_backend.cpp
@@ -33,6 +33,7 @@ along with this program. If not, see .
#include
// Wayland
#include
+#include
// system
#include
#include
@@ -495,10 +496,12 @@ Buffer *ShmPool::getBuffer(const QSize &size, int32_t stride)
}
WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend)
- : m_seat(seat)
+ : QObject(NULL)
+ , m_seat(seat)
, m_pointer(NULL)
, m_keyboard(NULL)
, m_cursor(NULL)
+ , m_theme(NULL)
, m_enteredSerial(0)
, m_cursorTracker()
, m_backend(backend)
@@ -518,6 +521,7 @@ WaylandSeat::~WaylandSeat()
if (m_cursor) {
wl_surface_destroy(m_cursor);
}
+ destroyTheme();
}
void WaylandSeat::destroyPointer()
@@ -580,6 +584,42 @@ void WaylandSeat::installCursorImage(wl_buffer *image, const QSize &size, const
wl_surface_commit(m_cursor);
}
+void WaylandSeat::installCursorImage(Qt::CursorShape shape)
+{
+ if (!m_theme) {
+ loadTheme();
+ }
+ wl_cursor *c = wl_cursor_theme_get_cursor(m_theme, Cursor::self()->cursorName(shape).constData());
+ if (c->image_count <= 0) {
+ return;
+ }
+ wl_cursor_image *image = c->images[0];
+ installCursorImage(wl_cursor_image_get_buffer(image),
+ QSize(image->width, image->height),
+ QPoint(image->hotspot_x, image->hotspot_y));
+}
+
+void WaylandSeat::loadTheme()
+{
+ Cursor *c = Cursor::self();
+ if (!m_theme) {
+ // so far the theme had not been created, this means we need to start tracking theme changes
+ connect(c, SIGNAL(themeChanged()), SLOT(loadTheme()));
+ } else {
+ destroyTheme();
+ }
+ m_theme = wl_cursor_theme_load(c->themeName().toUtf8().constData(),
+ c->themeSize(), m_backend->shmPool()->shm());
+}
+
+void WaylandSeat::destroyTheme()
+{
+ if (m_theme) {
+ wl_cursor_theme_destroy(m_theme);
+ m_theme = NULL;
+ }
+}
+
WaylandBackend *WaylandBackend::s_self = 0;
WaylandBackend *WaylandBackend::create(QObject *parent)
{
@@ -652,6 +692,14 @@ void WaylandBackend::createSeat(uint32_t name)
m_seat.reset(new WaylandSeat(seat, this));
}
+void WaylandBackend::installCursorImage(Qt::CursorShape shape)
+{
+ if (m_seat.isNull()) {
+ return;
+ }
+ m_seat->installCursorImage(shape);
+}
+
void WaylandBackend::createSurface()
{
m_surface = wl_compositor_create_surface(m_compositor);
diff --git a/wayland_backend.h b/wayland_backend.h
index fa64166b26..21f9b35bce 100644
--- a/wayland_backend.h
+++ b/wayland_backend.h
@@ -32,6 +32,7 @@ along with this program. If not, see .
class QTemporaryFile;
class QImage;
+struct wl_cursor_theme;
struct wl_buffer;
struct wl_shm;
@@ -112,6 +113,7 @@ public:
wl_buffer *createBuffer(const QSize &size, int32_t stride, const void *src);
void *poolAddress() const;
Buffer *getBuffer(const QSize &size, int32_t stride);
+ wl_shm *shm();
Q_SIGNALS:
void poolResized();
private:
@@ -127,8 +129,9 @@ private:
QList m_buffers;
};
-class WaylandSeat
+class WaylandSeat : public QObject
{
+ Q_OBJECT
public:
WaylandSeat(wl_seat *seat, WaylandBackend *backend);
virtual ~WaylandSeat();
@@ -138,13 +141,18 @@ public:
void pointerEntered(uint32_t serial);
void resetCursor();
void installCursorImage(wl_buffer *image, const QSize &size, const QPoint &hotspot);
+ void installCursorImage(Qt::CursorShape shape);
+private Q_SLOTS:
+ void loadTheme();
private:
void destroyPointer();
void destroyKeyboard();
+ void destroyTheme();
wl_seat *m_seat;
wl_pointer *m_pointer;
wl_keyboard *m_keyboard;
wl_surface *m_cursor;
+ wl_cursor_theme *m_theme;
uint32_t m_enteredSerial;
QScopedPointer m_cursorTracker;
WaylandBackend *m_backend;
@@ -175,6 +183,7 @@ public:
wl_surface *surface() const;
const QSize &shellSurfaceSize() const;
void setShellSurfaceSize(const QSize &size);
+ void installCursorImage(Qt::CursorShape shape);
void dispatchEvents();
Q_SIGNALS:
@@ -232,6 +241,12 @@ void* ShmPool::poolAddress() const
return m_poolData;
}
+inline
+wl_shm *ShmPool::shm()
+{
+ return m_shm;
+}
+
inline
wl_display *WaylandBackend::display()
{