diff options
author | Giulio Camuffo <giuliocamuffo@gmail.com> | 2012-11-05 21:19:39 +0100 |
---|---|---|
committer | Andy Nichols <andy.nichols@digia.com> | 2013-01-18 14:09:24 +0100 |
commit | 7bd2d367a3eafc403a6c2d3264c5812119768f60 (patch) | |
tree | 6355be3b118d78c3443e403472d9fe8655938843 | |
parent | 1dffceac360e07542902c0877332c7ad47f4f17d (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.cpp | 271 | ||||
-rw-r--r-- | src/plugins/platforms/wayland/qwaylandcursor.h | 14 | ||||
-rw-r--r-- | src/plugins/platforms/wayland/qwaylanddecoration.cpp | 7 | ||||
-rw-r--r-- | src/plugins/platforms/wayland/qwaylanddisplay.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/wayland/qwaylandinputdevice.cpp | 26 | ||||
-rw-r--r-- | src/plugins/platforms/wayland/qwaylandinputdevice.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/wayland/wayland.pro | 4 |
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) |