summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiulio Camuffo <giuliocamuffo@gmail.com>2012-11-05 21:19:39 +0100
committerAndy Nichols <andy.nichols@digia.com>2013-01-18 14:09:24 +0100
commit7bd2d367a3eafc403a6c2d3264c5812119768f60 (patch)
tree6355be3b118d78c3443e403472d9fe8655938843
parent1dffceac360e07542902c0877332c7ad47f4f17d (diff)
Fix the pointer cursor handling.
Change-Id: I23527bf06b88c8f612f9bfe7d48f61e80aa6bec3 Reviewed-by: Andy Nichols <andy.nichols@digia.com>
-rw-r--r--src/plugins/platforms/wayland/qwaylandcursor.cpp271
-rw-r--r--src/plugins/platforms/wayland/qwaylandcursor.h14
-rw-r--r--src/plugins/platforms/wayland/qwaylanddecoration.cpp7
-rw-r--r--src/plugins/platforms/wayland/qwaylanddisplay.h2
-rw-r--r--src/plugins/platforms/wayland/qwaylandinputdevice.cpp26
-rw-r--r--src/plugins/platforms/wayland/qwaylandinputdevice.h4
-rw-r--r--src/plugins/platforms/wayland/wayland.pro4
7 files changed, 182 insertions, 146 deletions
diff --git a/src/plugins/platforms/wayland/qwaylandcursor.cpp b/src/plugins/platforms/wayland/qwaylandcursor.cpp
index d966111c6..99ac0fd4f 100644
--- a/src/plugins/platforms/wayland/qwaylandcursor.cpp
+++ b/src/plugins/platforms/wayland/qwaylandcursor.cpp
@@ -49,182 +49,199 @@
#include <QtGui/QImageReader>
#include <QDebug>
-#define DATADIR "/usr/share"
-
-static const struct pointer_image {
- const char *filename;
- int hotspot_x, hotspot_y;
-} pointer_images[] = {
- /* FIXME: Half of these are wrong... */
- /* Qt::ArrowCursor */
- { DATADIR "/wayland/left_ptr.png", 10, 5 },
- /* Qt::UpArrowCursor */
- { DATADIR "/wayland/top_side.png", 18, 8 },
- /* Qt::CrossCursor */
- { DATADIR "/wayland/top_side.png", 18, 8 },
- /* Qt::WaitCursor */
- { DATADIR "/wayland/top_side.png", 18, 8 },
- /* Qt::IBeamCursor */
- { DATADIR "/wayland/xterm.png", 15, 15 },
- /* Qt::SizeVerCursor */
- { DATADIR "/wayland/top_side.png", 18, 8 },
- /* Qt::SizeHorCursor */
- { DATADIR "/wayland/bottom_left_corner.png", 6, 30 },
- /* Qt::SizeBDiagCursor */
- { DATADIR "/wayland/bottom_right_corner.png", 28, 28 },
- /* Qt::SizeFDiagCursor */
- { DATADIR "/wayland/bottom_side.png", 16, 20 },
- /* Qt::SizeAllCursor */
- { DATADIR "/wayland/left_side.png", 10, 20 },
- /* Qt::BlankCursor */
- { DATADIR "/wayland/right_side.png", 30, 19 },
- /* Qt::SplitVCursor */
- { DATADIR "/wayland/sb_v_double_arrow.png", 15, 15 },
- /* Qt::SplitHCursor */
- { DATADIR "/wayland/sb_h_double_arrow.png", 15, 15 },
- /* Qt::PointingHandCursor */
- { DATADIR "/wayland/hand2.png", 14, 8 },
- /* Qt::ForbiddenCursor */
- { DATADIR "/wayland/top_right_corner.png", 26, 8 },
- /* Qt::WhatsThisCursor */
- { DATADIR "/wayland/top_right_corner.png", 26, 8 },
- /* Qt::BusyCursor */
- { DATADIR "/wayland/top_right_corner.png", 26, 8 },
- /* Qt::OpenHandCursor */
- { DATADIR "/wayland/hand1.png", 18, 11 },
- /* Qt::ClosedHandCursor */
- { DATADIR "/wayland/grabbing.png", 20, 17 },
- /* Qt::DragCopyCursor */
- { DATADIR "/wayland/dnd-copy.png", 13, 13 },
- /* Qt::DragMoveCursor */
- { DATADIR "/wayland/dnd-move.png", 13, 13 },
- /* Qt::DragLinkCursor */
- { DATADIR "/wayland/dnd-link.png", 13, 13 },
+#include <wayland-cursor.h>
+
+#define ARRAY_LENGTH(a) sizeof(a) / sizeof(a[0])
+
+/*
+ * The following correspondences between file names and cursors was copied
+ * from: https://bugs.kde.org/attachment.cgi?id=67313
+ */
+
+static const char *bottom_left_corners[] = {
+ "size_fdiag",
+ "bottom_left_corner",
+ "sw-resize"
+};
+
+static const char *bottom_right_corners[] = {
+ "size_bdiag",
+ "bottom_right_corner",
+ "se-resize"
+};
+
+static const char *bottom_sides[] = {
+ "bottom_side",
+ "s-resize"
+};
+
+static const char *grabbings[] = {
+ "grabbing",
+ "closedhand",
+ "208530c400c041818281048008011002"
+};
+
+static const char *left_ptrs[] = {
+ "left_ptr",
+ "default",
+ "top_left_arrow",
+ "left-arrow"
+};
+
+static const char *left_sides[] = {
+ "left_side",
+ "w-resize"
+};
+
+static const char *right_sides[] = {
+ "right_side",
+ "e-resize"
+};
+
+static const char *top_left_corners[] = {
+ "top_left_corner",
+ "nw-resize"
+};
+
+static const char *top_right_corners[] = {
+ "top_right_corner",
+ "ne-resize"
+};
+
+static const char *top_sides[] = {
+ "top_side",
+ "n-resize"
+};
+
+static const char *xterms[] = {
+ "xterm",
+ "ibeam",
+ "text"
+};
+
+static const char *hand1s[] = {
+ "hand1",
+ "pointer",
+ "pointing_hand",
+ "e29285e634086352946a0e7090d73106"
+};
+
+static const char *watches[] = {
+ "watch",
+ "wait",
+ "0426c94ea35c87780ff01dc239897213"
+};
+
+struct cursor_alternatives {
+ const char **names;
+ size_t count;
+};
+
+static const struct cursor_alternatives cursors[] = {
+ {left_ptrs, ARRAY_LENGTH(left_ptrs)},
+ {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
+ {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
+ {bottom_sides, ARRAY_LENGTH(bottom_sides)},
+ {grabbings, ARRAY_LENGTH(grabbings)},
+ {left_sides, ARRAY_LENGTH(left_sides)},
+ {right_sides, ARRAY_LENGTH(right_sides)},
+ {top_left_corners, ARRAY_LENGTH(top_left_corners)},
+ {top_right_corners, ARRAY_LENGTH(top_right_corners)},
+ {top_sides, ARRAY_LENGTH(top_sides)},
+ {xterms, ARRAY_LENGTH(xterms)},
+ {hand1s, ARRAY_LENGTH(hand1s)},
+ {watches, ARRAY_LENGTH(watches)},
};
QWaylandCursor::QWaylandCursor(QWaylandScreen *screen)
- : mBuffer(0)
- , mDisplay(screen->display())
- , mSurface(0)
+ : mDisplay(screen->display())
{
-}
+ //TODO: Make wl_cursor_theme_load arguments configurable here
+ mCursorTheme = wl_cursor_theme_load("default", 32, mDisplay->shm());
+ mCursors = new wl_cursor*[ARRAY_LENGTH(cursors)];
-QWaylandCursor::~QWaylandCursor()
-{
- if (mSurface)
- wl_surface_destroy(mSurface);
+ for (uint i = 0; i < ARRAY_LENGTH(cursors); i++) {
+ struct wl_cursor *cursor = NULL;
+ for (uint j = 0; !cursor && j < cursors[i].count; ++j)
+ cursor = wl_cursor_theme_get_cursor(mCursorTheme, cursors[i].names[j]);
- delete mBuffer;
-}
+ if (!cursor)
+ qDebug() << "could not load cursor" << cursors[i].names[0];
-void QWaylandCursor::ensureSurface(const QSize &size)
-{
- if (!mBuffer || mBuffer->size() != size) {
- delete mBuffer;
- mBuffer = new QWaylandShmBuffer(mDisplay, size,
- QImage::Format_ARGB32);
+ mCursors[i] = cursor;
}
+}
- if (!mSurface)
- mSurface = mDisplay->createSurface(0);
-
- wl_surface_attach(mSurface, mBuffer->buffer(), 0, 0);
+QWaylandCursor::~QWaylandCursor()
+{
+ wl_cursor_theme_destroy(mCursorTheme);
+ delete[] mCursors;
}
void QWaylandCursor::changeCursor(QCursor *cursor, QWindow *window)
{
- const struct pointer_image *p;
+ Q_UNUSED(window)
- if (window == NULL)
- return;
-
- p = NULL;
- bool isBitmap = false;
-
- const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
- switch (newShape) {
- case Qt::ArrowCursor:
- p = &pointer_images[newShape];
- break;
+ int pointer = 0;
+ switch (cursor->shape()) {
case Qt::UpArrowCursor:
case Qt::CrossCursor:
case Qt::WaitCursor:
break;
case Qt::IBeamCursor:
- p = &pointer_images[newShape];
- break;
- case Qt::SizeVerCursor: /* 5 */
+ case Qt::SizeVerCursor: /* 5 */
case Qt::SizeHorCursor:
case Qt::SizeBDiagCursor:
+ pointer = 2;
+ break;
case Qt::SizeFDiagCursor:
+ pointer = 1;
+ break;
case Qt::SizeAllCursor:
- case Qt::BlankCursor: /* 10 */
+ case Qt::BlankCursor: /* 10 */
break;
case Qt::SplitVCursor:
+ pointer = 3;
+ break;
case Qt::SplitHCursor:
- case Qt::PointingHandCursor:
- p = &pointer_images[newShape];
+ pointer = 6;
break;
+ case Qt::PointingHandCursor:
case Qt::ForbiddenCursor:
- case Qt::WhatsThisCursor: /* 15 */
+ case Qt::WhatsThisCursor: /* 15 */
case Qt::BusyCursor:
- break;
case Qt::OpenHandCursor:
case Qt::ClosedHandCursor:
+ pointer = 4;
+ break;
case Qt::DragCopyCursor:
case Qt::DragMoveCursor: /* 20 */
case Qt::DragLinkCursor:
- p = &pointer_images[newShape];
- break;
-
case Qt::BitmapCursor:
- isBitmap = true;
- break;
-
default:
break;
}
- if (!p && !isBitmap) {
- p = &pointer_images[0];
- qWarning("unhandled cursor %d", newShape);
- }
+ struct wl_cursor *cur = mCursors[pointer];
+ if (!cur)
+ return;
- if (isBitmap && !cursor->pixmap().isNull()) {
- setupPixmapCursor(cursor);
- } else if (isBitmap && cursor->bitmap()) {
- qWarning("unsupported QBitmap cursor");
- } else {
- QImageReader reader(p->filename);
- if (!reader.canRead())
- return;
- ensureSurface(reader.size());
- reader.read(mBuffer->image());
- mDisplay->setCursor(mSurface, p->hotspot_x, p->hotspot_y);
- }
-}
+ struct wl_cursor_image *image = cur->images[0];
-void QWaylandCursor::setupPixmapCursor(QCursor *cursor)
-{
- if (!cursor) {
- delete mBuffer;
- mBuffer = 0;
+ struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
+ if (!buffer)
return;
- }
- ensureSurface(cursor->pixmap().size());
- QImage src = cursor->pixmap().toImage().convertToFormat(QImage::Format_ARGB32);
- for (int y = 0; y < src.height(); ++y)
- memcpy(mBuffer->image()->scanLine(y), src.scanLine(y), src.bytesPerLine());
- mDisplay->setCursor(mSurface, cursor->hotSpot().x(), cursor->hotSpot().y());
+
+ mDisplay->setCursor(buffer, image);
}
-void QWaylandDisplay::setCursor(wl_surface *surface, int32_t x, int32_t y)
+void QWaylandDisplay::setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image)
{
/* Qt doesn't tell us which input device we should set the cursor
* for, so set it for all devices. */
for (int i = 0; i < mInputDevices.count(); i++) {
QWaylandInputDevice *inputDevice = mInputDevices.at(i);
- inputDevice->setCursor(surface, x, y);
+ inputDevice->setCursor(buffer, image);
}
}
diff --git a/src/plugins/platforms/wayland/qwaylandcursor.h b/src/plugins/platforms/wayland/qwaylandcursor.h
index a8ab40805..aa8dbfb03 100644
--- a/src/plugins/platforms/wayland/qwaylandcursor.h
+++ b/src/plugins/platforms/wayland/qwaylandcursor.h
@@ -44,10 +44,9 @@
#include <qpa/qplatformcursor.h>
-class QWaylandShmBuffer;
class QWaylandDisplay;
class QWaylandScreen;
-struct wl_surface;
+struct wl_cursor_theme;
class QWaylandCursor : public QPlatformCursor
{
@@ -60,15 +59,10 @@ public:
QPoint pos() const;
void setPos(const QPoint &pos);
- void setupPixmapCursor(QCursor *cursor);
-
- QWaylandShmBuffer *mBuffer;
- QWaylandDisplay *mDisplay;
- wl_surface *mSurface;
-
private:
- void ensureSurface(const QSize &size);
-
+ QWaylandDisplay *mDisplay;
+ struct wl_cursor_theme *mCursorTheme;
+ struct wl_cursor **mCursors;
QPoint mLastPos;
};
diff --git a/src/plugins/platforms/wayland/qwaylanddecoration.cpp b/src/plugins/platforms/wayland/qwaylanddecoration.cpp
index f8c374a6c..9fcc6a8bc 100644
--- a/src/plugins/platforms/wayland/qwaylanddecoration.cpp
+++ b/src/plugins/platforms/wayland/qwaylanddecoration.cpp
@@ -229,6 +229,7 @@ bool QWaylandDecoration::handleMouse(QWaylandInputDevice *inputDevice, const QPo
void QWaylandDecoration::restoreMouseCursor()
{
if (m_hasSetCursor) {
+ overrideCursor(Qt::ArrowCursor);
QGuiApplication::restoreOverrideCursor();
m_hasSetCursor = false;
}
@@ -261,9 +262,11 @@ void QWaylandDecoration::processMouseTop(QWaylandInputDevice *inputDevice, const
if (local.y() <= m_margins.bottom()) {
if (local.x() <= margins().left()) {
//top left bit
+ overrideCursor(Qt::SizeFDiagCursor);
startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_LEFT,b);
} else if (local.x() > m_window->width() - margins().right()) {
//top right bit
+ overrideCursor(Qt::SizeBDiagCursor);
startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_RIGHT,b);
} else {
//top reszie bit
@@ -282,10 +285,12 @@ void QWaylandDecoration::processMouseBottom(QWaylandInputDevice *inputDevice, co
Q_UNUSED(mods);
if (local.x() <= margins().left()) {
//bottom left bit
+ overrideCursor(Qt::SizeBDiagCursor);
startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT,b);
} else if (local.x() > m_window->width() - margins().right()) {
//bottom right bit
- startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT,b);
+ overrideCursor(Qt::SizeFDiagCursor);
+ startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT,b);
} else {
//bottom bit
overrideCursor(Qt::SplitVCursor);
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.h b/src/plugins/platforms/wayland/qwaylanddisplay.h
index 84558dbff..0e5511821 100644
--- a/src/plugins/platforms/wayland/qwaylanddisplay.h
+++ b/src/plugins/platforms/wayland/qwaylanddisplay.h
@@ -93,7 +93,7 @@ public:
QWaylandWindowManagerIntegration *windowManagerIntegration();
#endif
- void setCursor(wl_surface *surface, int32_t x, int32_t y);
+ void setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image);
struct wl_display *wl_display() const { return mDisplay; }
struct wl_registry *wl_registry() const { return mRegistry; }
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
index e7ffc6234..a3a31e3d7 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp
@@ -54,6 +54,8 @@
#include <unistd.h>
#include <fcntl.h>
+#include <wayland-cursor.h>
+
#include <QtGui/QGuiApplication>
#ifndef QT_NO_WAYLAND_XKB
@@ -158,6 +160,7 @@ void QWaylandInputDevice::seat_capabilities(void *data, struct wl_seat *seat, ui
if (caps & WL_SEAT_CAPABILITY_POINTER) {
self->mDeviceInterfaces.pointer = wl_seat_get_pointer(seat);
+ self->mDeviceInterfaces.pointerSurface = self->mQDisplay->createSurface(self);
wl_pointer_add_listener(self->mDeviceInterfaces.pointer, &pointerListener, self);
}
@@ -198,10 +201,15 @@ void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button)
mButtons = mButtons & !button;
}
-void QWaylandInputDevice::setCursor(wl_surface *surface, int x, int y)
+void QWaylandInputDevice::setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image)
{
- if (mCaps & WL_SEAT_CAPABILITY_POINTER)
- wl_pointer_set_cursor(mDeviceInterfaces.pointer, mTime, surface, x, y);
+ if (mCaps & WL_SEAT_CAPABILITY_POINTER) {
+ wl_pointer_set_cursor(mDeviceInterfaces.pointer, mEnterSerial, mDeviceInterfaces.pointerSurface,
+ image->hotspot_x, image->hotspot_y);
+ wl_surface_attach(mDeviceInterfaces.pointerSurface, buffer, 0, 0);
+ wl_surface_damage(mDeviceInterfaces.pointerSurface, 0, 0, image->width, image->height);
+ wl_surface_commit(mDeviceInterfaces.pointerSurface);
+ }
}
void QWaylandInputDevice::pointer_enter(void *data,
@@ -217,12 +225,21 @@ void QWaylandInputDevice::pointer_enter(void *data,
if (!surface)
return;
+ QGuiApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
+
QWaylandWindow *window = (QWaylandWindow *) wl_surface_get_user_data(surface);
window->handleMouseEnter();
+ window->handleMouse(inputDevice,
+ inputDevice->mTime,
+ inputDevice->mSurfacePos,
+ inputDevice->mGlobalPos,
+ inputDevice->mButtons,
+ Qt::NoModifier);
inputDevice->mPointerFocus = window;
inputDevice->mTime = QWaylandDisplay::currentTimeMillisec();
inputDevice->mSerial = serial;
+ inputDevice->mEnterSerial = serial;
}
void QWaylandInputDevice::pointer_leave(void *data,
@@ -237,6 +254,8 @@ void QWaylandInputDevice::pointer_leave(void *data,
if (!surface)
return;
+ QGuiApplication::restoreOverrideCursor();
+
QWaylandWindow *window = (QWaylandWindow *) wl_surface_get_user_data(surface);
window->handleMouseLeave();
inputDevice->mPointerFocus = 0;
@@ -290,7 +309,6 @@ void QWaylandInputDevice::pointer_button(void *data,
QWaylandWindow *window = inputDevice->mPointerFocus;
Qt::MouseButton qt_button;
-
// translate from kernel (input.h) 'button' to corresponding Qt:MouseButton.
// The range of mouse values is 0x110 <= mouse_button < 0x120, the first Joystick button.
switch (button) {
diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.h b/src/plugins/platforms/wayland/qwaylandinputdevice.h
index 6678c25a3..716343822 100644
--- a/src/plugins/platforms/wayland/qwaylandinputdevice.h
+++ b/src/plugins/platforms/wayland/qwaylandinputdevice.h
@@ -72,7 +72,7 @@ public:
struct wl_seat *wl_seat() const { return mSeat; }
- void setCursor(wl_surface *surface, int x, int y);
+ void setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image);
void handleWindowDestroyed(QWaylandWindow *window);
void setTransferDevice(struct wl_data_device *device);
@@ -91,6 +91,7 @@ private:
struct {
struct wl_pointer *pointer;
+ struct wl_surface *pointerSurface;
struct wl_keyboard *keyboard;
struct wl_touch *touch;
} mDeviceInterfaces;
@@ -105,6 +106,7 @@ private:
QPointF mGlobalPos;
uint32_t mTime;
uint32_t mSerial;
+ uint32_t mEnterSerial;
static const struct wl_seat_listener seatListener;
diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro
index 4b5287536..ef4520f02 100644
--- a/src/plugins/platforms/wayland/wayland.pro
+++ b/src/plugins/platforms/wayland/wayland.pro
@@ -83,9 +83,9 @@ OTHER_FILES += wayland.json
INCLUDEPATH += $$PWD/../../../shared
!contains(QT_CONFIG, no-pkg-config) {
- PKGCONFIG += wayland-client
+ PKGCONFIG += wayland-client wayland-cursor
} else {
- LIBS += -lwayland-client
+ LIBS += -lwayland-client -lwayland-cursor
}
include ($$PWD/gl_integration/gl_integration.pri)