Add support for Wayland Cursor themes

WaylandSeat can install a cursor based on Qt::CursorShape using the
Wayland cursor theme library.
This commit is contained in:
Martin Gräßlin 2013-06-27 09:58:04 +02:00
parent e18bb1006a
commit f9704ff0df
3 changed files with 66 additions and 2 deletions

View file

@ -270,6 +270,7 @@ set(kwin_XCB_LIBS
set(kwin_WAYLAND_LIBS set(kwin_WAYLAND_LIBS
Wayland::Client Wayland::Client
Wayland::Cursor
XCB::XTEST XCB::XTEST
) )

View file

@ -33,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <xcb/xfixes.h> #include <xcb/xfixes.h>
// Wayland // Wayland
#include <wayland-client-protocol.h> #include <wayland-client-protocol.h>
#include <wayland-cursor.h>
// system // system
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -495,10 +496,12 @@ Buffer *ShmPool::getBuffer(const QSize &size, int32_t stride)
} }
WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend) WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend)
: m_seat(seat) : QObject(NULL)
, m_seat(seat)
, m_pointer(NULL) , m_pointer(NULL)
, m_keyboard(NULL) , m_keyboard(NULL)
, m_cursor(NULL) , m_cursor(NULL)
, m_theme(NULL)
, m_enteredSerial(0) , m_enteredSerial(0)
, m_cursorTracker() , m_cursorTracker()
, m_backend(backend) , m_backend(backend)
@ -518,6 +521,7 @@ WaylandSeat::~WaylandSeat()
if (m_cursor) { if (m_cursor) {
wl_surface_destroy(m_cursor); wl_surface_destroy(m_cursor);
} }
destroyTheme();
} }
void WaylandSeat::destroyPointer() void WaylandSeat::destroyPointer()
@ -580,6 +584,42 @@ void WaylandSeat::installCursorImage(wl_buffer *image, const QSize &size, const
wl_surface_commit(m_cursor); 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::s_self = 0;
WaylandBackend *WaylandBackend::create(QObject *parent) WaylandBackend *WaylandBackend::create(QObject *parent)
{ {
@ -652,6 +692,14 @@ void WaylandBackend::createSeat(uint32_t name)
m_seat.reset(new WaylandSeat(seat, this)); 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() void WaylandBackend::createSurface()
{ {
m_surface = wl_compositor_create_surface(m_compositor); m_surface = wl_compositor_create_surface(m_compositor);

View file

@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class QTemporaryFile; class QTemporaryFile;
class QImage; class QImage;
struct wl_cursor_theme;
struct wl_buffer; struct wl_buffer;
struct wl_shm; struct wl_shm;
@ -112,6 +113,7 @@ public:
wl_buffer *createBuffer(const QSize &size, int32_t stride, const void *src); wl_buffer *createBuffer(const QSize &size, int32_t stride, const void *src);
void *poolAddress() const; void *poolAddress() const;
Buffer *getBuffer(const QSize &size, int32_t stride); Buffer *getBuffer(const QSize &size, int32_t stride);
wl_shm *shm();
Q_SIGNALS: Q_SIGNALS:
void poolResized(); void poolResized();
private: private:
@ -127,8 +129,9 @@ private:
QList<Buffer*> m_buffers; QList<Buffer*> m_buffers;
}; };
class WaylandSeat class WaylandSeat : public QObject
{ {
Q_OBJECT
public: public:
WaylandSeat(wl_seat *seat, WaylandBackend *backend); WaylandSeat(wl_seat *seat, WaylandBackend *backend);
virtual ~WaylandSeat(); virtual ~WaylandSeat();
@ -138,13 +141,18 @@ public:
void pointerEntered(uint32_t serial); void pointerEntered(uint32_t serial);
void resetCursor(); void resetCursor();
void installCursorImage(wl_buffer *image, const QSize &size, const QPoint &hotspot); void installCursorImage(wl_buffer *image, const QSize &size, const QPoint &hotspot);
void installCursorImage(Qt::CursorShape shape);
private Q_SLOTS:
void loadTheme();
private: private:
void destroyPointer(); void destroyPointer();
void destroyKeyboard(); void destroyKeyboard();
void destroyTheme();
wl_seat *m_seat; wl_seat *m_seat;
wl_pointer *m_pointer; wl_pointer *m_pointer;
wl_keyboard *m_keyboard; wl_keyboard *m_keyboard;
wl_surface *m_cursor; wl_surface *m_cursor;
wl_cursor_theme *m_theme;
uint32_t m_enteredSerial; uint32_t m_enteredSerial;
QScopedPointer<X11CursorTracker> m_cursorTracker; QScopedPointer<X11CursorTracker> m_cursorTracker;
WaylandBackend *m_backend; WaylandBackend *m_backend;
@ -175,6 +183,7 @@ public:
wl_surface *surface() const; wl_surface *surface() const;
const QSize &shellSurfaceSize() const; const QSize &shellSurfaceSize() const;
void setShellSurfaceSize(const QSize &size); void setShellSurfaceSize(const QSize &size);
void installCursorImage(Qt::CursorShape shape);
void dispatchEvents(); void dispatchEvents();
Q_SIGNALS: Q_SIGNALS:
@ -232,6 +241,12 @@ void* ShmPool::poolAddress() const
return m_poolData; return m_poolData;
} }
inline
wl_shm *ShmPool::shm()
{
return m_shm;
}
inline inline
wl_display *WaylandBackend::display() wl_display *WaylandBackend::display()
{ {