diff --git a/abstract_client.h b/abstract_client.h --- a/abstract_client.h +++ b/abstract_client.h @@ -24,6 +24,7 @@ #include "options.h" #include "rules.h" #include "tabgroup.h" +#include "cursor.h" #include @@ -602,7 +603,7 @@ /** * Cursor shape for move/resize mode. **/ - Qt::CursorShape cursor() const { + CursorShape cursor() const { return m_moveResize.cursor; } @@ -747,7 +748,7 @@ void modalChanged(); void quickTileModeChanged(); void moveResizedChanged(); - void moveResizeCursorChanged(Qt::CursorShape); + void moveResizeCursorChanged(CursorShape); void clientStartUserMovedResized(KWin::AbstractClient*); void clientStepUserMovedResized(KWin::AbstractClient *, const QRect&); void clientFinishUserMovedResized(KWin::AbstractClient*); @@ -1122,7 +1123,7 @@ QRect geometry; Position pointer = PositionCenter; bool buttonDown = false; - Qt::CursorShape cursor = Qt::ArrowCursor; + CursorShape cursor = Qt::ArrowCursor; int startScreen = 0; QTimer *delayedTimer = nullptr; } m_moveResize; diff --git a/abstract_client.cpp b/abstract_client.cpp --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -1291,23 +1291,31 @@ Position m = moveResizePointerMode(); if (!isResizable() || isShade()) m = PositionCenter; - Qt::CursorShape c = Qt::ArrowCursor; + CursorShape c = Qt::ArrowCursor; switch(m) { case PositionTopLeft: + c = KWin::ExtendedCursor::SizeNorthWest; + break; case PositionBottomRight: - c = Qt::SizeFDiagCursor; + c = KWin::ExtendedCursor::SizeSouthEast; break; case PositionBottomLeft: + c = KWin::ExtendedCursor::SizeSouthWest; + break; case PositionTopRight: - c = Qt::SizeBDiagCursor; + c = KWin::ExtendedCursor::SizeNorthEast; break; case PositionTop: + c = KWin::ExtendedCursor::SizeNorth; + break; case PositionBottom: - c = Qt::SizeVerCursor; + c = KWin::ExtendedCursor::SizeSouth; break; case PositionLeft: + c = KWin::ExtendedCursor::SizeWest; + break; case PositionRight: - c = Qt::SizeHorCursor; + c = KWin::ExtendedCursor::SizeEast; break; default: if (isMoveResize()) diff --git a/autotests/integration/decoration_input_test.cpp b/autotests/integration/decoration_input_test.cpp --- a/autotests/integration/decoration_input_test.cpp +++ b/autotests/integration/decoration_input_test.cpp @@ -365,28 +365,28 @@ quint32 timestamp = 1; MOTION(QPoint(c->geometry().center().x(), c->clientPos().y() / 2)); - QCOMPARE(c->cursor(), Qt::ArrowCursor); + QCOMPARE(c->cursor(), CursorShape(Qt::ArrowCursor)); - MOTION(QPoint(20, 0)); - QCOMPARE(c->cursor(), Qt::SizeFDiagCursor); + MOTION(QPoint(c->geometry().x(), 0)); + QCOMPARE(c->cursor(), CursorShape(KWin::ExtendedCursor::SizeNorthWest)); MOTION(QPoint(c->geometry().x() + c->geometry().width() / 2, 0)); - QCOMPARE(c->cursor(), Qt::SizeVerCursor); + QCOMPARE(c->cursor(), CursorShape(KWin::ExtendedCursor::SizeNorth)); MOTION(QPoint(c->geometry().x() + c->geometry().width() - 1, 0)); - QCOMPARE(c->cursor(), Qt::SizeBDiagCursor); + QCOMPARE(c->cursor(), CursorShape(KWin::ExtendedCursor::SizeNorthEast)); MOTION(QPoint(c->geometry().x() + c->geometry().width() - 1, c->height() / 2)); - QCOMPARE(c->cursor(), Qt::SizeHorCursor); + QCOMPARE(c->cursor(), CursorShape(KWin::ExtendedCursor::SizeEast)); MOTION(QPoint(c->geometry().x() + c->geometry().width() - 1, c->height() - 1)); - QCOMPARE(c->cursor(), Qt::SizeFDiagCursor); + QCOMPARE(c->cursor(), CursorShape(KWin::ExtendedCursor::SizeSouthEast)); MOTION(QPoint(c->geometry().x() + c->geometry().width() / 2, c->height() - 1)); - QCOMPARE(c->cursor(), Qt::SizeVerCursor); + QCOMPARE(c->cursor(), CursorShape(KWin::ExtendedCursor::SizeSouth)); MOTION(QPoint(c->geometry().x(), c->height() - 1)); - QCOMPARE(c->cursor(), Qt::SizeBDiagCursor); + QCOMPARE(c->cursor(), CursorShape(KWin::ExtendedCursor::SizeSouthWest)); MOTION(QPoint(c->geometry().x(), c->height() / 2)); - QCOMPARE(c->cursor(), Qt::SizeHorCursor); + QCOMPARE(c->cursor(), CursorShape(KWin::ExtendedCursor::SizeWest)); MOTION(c->geometry().center()); QEXPECT_FAIL("", "Cursor not set back on leave", Continue); - QCOMPARE(c->cursor(), Qt::ArrowCursor); + QCOMPARE(c->cursor(), CursorShape(Qt::ArrowCursor)); } void DecorationInputTest::testPressToMove_data() @@ -425,7 +425,7 @@ quint32 timestamp = 1; MOTION(QPoint(c->geometry().center().x(), c->y() + c->clientPos().y() / 2)); - QCOMPARE(c->cursor(), Qt::ArrowCursor); + QCOMPARE(c->cursor(), CursorShape(Qt::ArrowCursor)); PRESS; QVERIFY(!c->isMove()); diff --git a/client.cpp b/client.cpp --- a/client.cpp +++ b/client.cpp @@ -154,7 +154,7 @@ connect(clientMachine(), &ClientMachine::localhostChanged, this, &Client::updateCaption); connect(options, &Options::condensedTitleChanged, this, &Client::updateCaption); - connect(this, &Client::moveResizeCursorChanged, this, [this] (Qt::CursorShape cursor) { + connect(this, &Client::moveResizeCursorChanged, this, [this] (CursorShape cursor) { xcb_cursor_t nativeCursor = Cursor::x11Cursor(cursor); m_frame.defineCursor(nativeCursor); if (m_decoInputExtent.isValid()) diff --git a/cursor.h b/cursor.h --- a/cursor.h +++ b/cursor.h @@ -33,6 +33,48 @@ namespace KWin { +namespace ExtendedCursor { +enum Shape { + SizeNorthWest = 0x100 + 0, + SizeNorth = 0x100 + 1, + SizeNorthEast = 0x100 + 2, + SizeEast = 0x100 + 3, + SizeWest = 0x100 + 4, + SizeSouthEast = 0x100 + 5, + SizeSouth = 0x100 + 6, + SizeSouthWest = 0x100 + 7 +}; +} +/** + * Extension of Qt::CursorShape with values not currently present there + */ + + +/** + * @brief Wrapper round Qt::CursorShape with extensions enums into a single entity + */ +class KWIN_EXPORT CursorShape { +public: + CursorShape(Qt::CursorShape qtShape) { + m_shape = qtShape; + } + CursorShape(KWin::ExtendedCursor::Shape kwinShape) { + m_shape = kwinShape; + } + bool operator==(const CursorShape &o) const { + return m_shape == o.m_shape; + } + operator int() const { + return m_shape; + } + /** + * @brief The name of a cursor shape in the theme. + */ + QByteArray name() const; +private: + int m_shape = Qt::ArrowCursor; +}; + /** * @short Replacement for QCursor. * @@ -93,13 +135,6 @@ * @return int */ int themeSize() const; - /** - * @brief The name of a cursor shape in the theme. - * - * @param shape The cursor for which the name needs to be known. - * @return QByteArray - */ - QByteArray cursorName(Qt::CursorShape shape) const; /** * @return list of alternative names for the cursor with @p name **/ @@ -118,9 +153,9 @@ **/ static void setPos(const QPoint &pos); static void setPos(int x, int y); - static xcb_cursor_t x11Cursor(Qt::CursorShape shape); + static xcb_cursor_t x11Cursor(CursorShape shape); /** - * Notice: if available always use the Qt::CursorShape variant to avoid cache duplicates for + * Notice: if available always use the CursorShape variant to avoid cache duplicates for * ambiguous cursor names in the non existing cursor name spcification **/ static xcb_cursor_t x11Cursor(const QByteArray &name); @@ -147,7 +182,7 @@ * a null cursor, an implementing subclass should implement this method if it can provide X11 * mouse cursors. **/ - virtual xcb_cursor_t getX11Cursor(Qt::CursorShape shape); + virtual xcb_cursor_t getX11Cursor(CursorShape shape); /** * Called from @link x11Cursor to actually retrieve the X11 cursor. Base implementation returns * a null cursor, an implementing subclass should implement this method if it can provide X11 diff --git a/cursor.cpp b/cursor.cpp --- a/cursor.cpp +++ b/cursor.cpp @@ -125,7 +125,7 @@ Cursor::setPos(QPoint(x, y)); } -xcb_cursor_t Cursor::getX11Cursor(Qt::CursorShape shape) +xcb_cursor_t Cursor::getX11Cursor(CursorShape shape) { Q_UNUSED(shape) return XCB_CURSOR_NONE; @@ -137,7 +137,7 @@ return XCB_CURSOR_NONE; } -xcb_cursor_t Cursor::x11Cursor(Qt::CursorShape shape) +xcb_cursor_t Cursor::x11Cursor(CursorShape shape) { return s_self->getX11Cursor(shape); } @@ -299,60 +299,115 @@ QByteArrayLiteral("1081e37283d90000800003c07f3ef6bf"), QByteArrayLiteral("6407b0e94181790501fd1e167b474872"), QByteArrayLiteral("b66166c04f8c3109214a4fbd64a50fc8")}}, - {QByteArrayLiteral("dnd-move"), {QByteArrayLiteral("move")}} + {QByteArrayLiteral("dnd-move"), {QByteArrayLiteral("move")}}, + {QByteArrayLiteral("sw-resize"), {QByteArrayLiteral("size_bdiag"), + QByteArrayLiteral("fcf1c3c7cd4491d801f1e1c78f100000"), + QByteArrayLiteral("fd_double_arrow"), + QByteArrayLiteral("bottom_left_corner")}}, + {QByteArrayLiteral("se-resize"), {QByteArrayLiteral("size_fdiag"), + QByteArrayLiteral("c7088f0f3e6c8088236ef8e1e3e70000"), + QByteArrayLiteral("bd_double_arrow"), + QByteArrayLiteral("bottom_right_corner")}}, + {QByteArrayLiteral("ne-resize"), {QByteArrayLiteral("size_bdiag"), + QByteArrayLiteral("fcf1c3c7cd4491d801f1e1c78f100000"), + QByteArrayLiteral("fd_double_arrow"), + QByteArrayLiteral("top_right_corner")}}, + {QByteArrayLiteral("nw-resize"), {QByteArrayLiteral("size_fdiag"), + QByteArrayLiteral("c7088f0f3e6c8088236ef8e1e3e70000"), + QByteArrayLiteral("bd_double_arrow"), + QByteArrayLiteral("top_left_corner")}}, + {QByteArrayLiteral("n-resize"), {QByteArrayLiteral("size_ver"), + QByteArrayLiteral("00008160000006810000408080010102"), + QByteArrayLiteral("sb_v_double_arrow"), + QByteArrayLiteral("v_double_arrow"), + QByteArrayLiteral("col-resize"), + QByteArrayLiteral("top_side")}}, + {QByteArrayLiteral("e-resize"), {QByteArrayLiteral("size_hor"), + QByteArrayLiteral("028006030e0e7ebffc7f7070c0600140"), + QByteArrayLiteral("sb_h_double_arrow"), + QByteArrayLiteral("h_double_arrow"), + QByteArrayLiteral("row-resize"), + QByteArrayLiteral("left_side")}}, + {QByteArrayLiteral("s-resize"), {QByteArrayLiteral("size_ver"), + QByteArrayLiteral("00008160000006810000408080010102"), + QByteArrayLiteral("sb_v_double_arrow"), + QByteArrayLiteral("v_double_arrow"), + QByteArrayLiteral("col-resize"), + QByteArrayLiteral("bottom_side")}}, + {QByteArrayLiteral("w-resize"), {QByteArrayLiteral("size_hor"), + QByteArrayLiteral("028006030e0e7ebffc7f7070c0600140"), + QByteArrayLiteral("sb_h_double_arrow"), + QByteArrayLiteral("h_double_arrow"), + QByteArrayLiteral("right_side")}} }; auto it = alternatives.find(name); if (it != alternatives.end()) { return it.value(); } return QVector(); } -QByteArray Cursor::cursorName(Qt::CursorShape shape) const +QByteArray CursorShape::name() const { - switch (shape) { + switch (m_shape) { case Qt::ArrowCursor: - return QByteArray("left_ptr"); + return QByteArrayLiteral("left_ptr"); case Qt::UpArrowCursor: - return QByteArray("up_arrow"); + return QByteArrayLiteral("up_arrow"); case Qt::CrossCursor: - return QByteArray("cross"); + return QByteArrayLiteral("cross"); case Qt::WaitCursor: - return QByteArray("wait"); + return QByteArrayLiteral("wait"); case Qt::IBeamCursor: - return QByteArray("ibeam"); + return QByteArrayLiteral("ibeam"); case Qt::SizeVerCursor: - return QByteArray("size_ver"); + return QByteArrayLiteral("size_ver"); case Qt::SizeHorCursor: - return QByteArray("size_hor"); + return QByteArrayLiteral("size_hor"); case Qt::SizeBDiagCursor: - return QByteArray("size_bdiag"); + return QByteArrayLiteral("size_bdiag"); case Qt::SizeFDiagCursor: - return QByteArray("size_fdiag"); + return QByteArrayLiteral("size_fdiag"); case Qt::SizeAllCursor: - return QByteArray("size_all"); + return QByteArrayLiteral("size_all"); case Qt::SplitVCursor: - return QByteArray("split_v"); + return QByteArrayLiteral("split_v"); case Qt::SplitHCursor: - return QByteArray("split_h"); + return QByteArrayLiteral("split_h"); case Qt::PointingHandCursor: - return QByteArray("pointing_hand"); + return QByteArrayLiteral("pointing_hand"); case Qt::ForbiddenCursor: - return QByteArray("forbidden"); + return QByteArrayLiteral("forbidden"); case Qt::OpenHandCursor: - return QByteArray("openhand"); + return QByteArrayLiteral("openhand"); case Qt::ClosedHandCursor: - return QByteArray("closedhand"); + return QByteArrayLiteral("closedhand"); case Qt::WhatsThisCursor: - return QByteArray("whats_this"); + return QByteArrayLiteral("whats_this"); case Qt::BusyCursor: - return QByteArray("left_ptr_watch"); + return QByteArrayLiteral("left_ptr_watch"); case Qt::DragMoveCursor: - return QByteArray("dnd-move"); + return QByteArrayLiteral("dnd-move"); case Qt::DragCopyCursor: - return QByteArray("dnd-copy"); + return QByteArrayLiteral("dnd-copy"); case Qt::DragLinkCursor: - return QByteArray("dnd-link"); + return QByteArrayLiteral("dnd-link"); + case KWin::ExtendedCursor::SizeNorthEast: + return QByteArrayLiteral("ne-resize"); + case KWin::ExtendedCursor::SizeNorth: + return QByteArrayLiteral("n-resize"); + case KWin::ExtendedCursor::SizeNorthWest: + return QByteArrayLiteral("nw-resize"); + case KWin::ExtendedCursor::SizeEast: + return QByteArrayLiteral("e-resize"); + case KWin::ExtendedCursor::SizeWest: + return QByteArrayLiteral("w-resize"); + case KWin::ExtendedCursor::SizeSouthEast: + return QByteArrayLiteral("se-resize"); + case KWin::ExtendedCursor::SizeSouth: + return QByteArrayLiteral("s-resize"); + case KWin::ExtendedCursor::SizeSouthWest: + return QByteArrayLiteral("sw-resize"); default: return QByteArray(); } diff --git a/plugins/platforms/x11/standalone/x11cursor.h b/plugins/platforms/x11/standalone/x11cursor.h --- a/plugins/platforms/x11/standalone/x11cursor.h +++ b/plugins/platforms/x11/standalone/x11cursor.h @@ -46,7 +46,7 @@ void notifyCursorChanged(); protected: - virtual xcb_cursor_t getX11Cursor(Qt::CursorShape shape); + virtual xcb_cursor_t getX11Cursor(CursorShape shape); xcb_cursor_t getX11Cursor(const QByteArray &name) override; virtual void doSetPos(); virtual void doGetPos(); diff --git a/plugins/platforms/x11/standalone/x11cursor.cpp b/plugins/platforms/x11/standalone/x11cursor.cpp --- a/plugins/platforms/x11/standalone/x11cursor.cpp +++ b/plugins/platforms/x11/standalone/x11cursor.cpp @@ -144,9 +144,9 @@ } } -xcb_cursor_t X11Cursor::getX11Cursor(Qt::CursorShape shape) +xcb_cursor_t X11Cursor::getX11Cursor(CursorShape shape) { - return getX11Cursor(cursorName(shape)); + return getX11Cursor(shape.name()); } xcb_cursor_t X11Cursor::getX11Cursor(const QByteArray &name) diff --git a/pointer_input.h b/pointer_input.h --- a/pointer_input.h +++ b/pointer_input.h @@ -39,11 +39,11 @@ namespace KWin { - class CursorImage; class InputRedirection; class Toplevel; class WaylandCursorTheme; +class CursorShape; namespace Decoration { @@ -203,7 +203,7 @@ QImage image; QPoint hotSpot; }; - void loadThemeCursor(Qt::CursorShape shape, Image *image); + void loadThemeCursor(CursorShape shape, Image *image); void loadThemeCursor(const QByteArray &shape, Image *image); template void loadThemeCursor(const T &shape, QHash &cursors, Image *image); @@ -235,7 +235,7 @@ Image m_fallbackCursor; Image m_moveResizeCursor; Image m_windowSelectionCursor; - QHash m_cursors; + QHash m_cursors; QHash m_cursorsByName; QElapsedTimer m_surfaceRenderedTimer; struct { diff --git a/pointer_input.cpp b/pointer_input.cpp --- a/pointer_input.cpp +++ b/pointer_input.cpp @@ -1178,7 +1178,7 @@ // TODO: add the cursor image } -void CursorImage::loadThemeCursor(Qt::CursorShape shape, Image *image) +void CursorImage::loadThemeCursor(CursorShape shape, Image *image) { loadThemeCursor(shape, m_cursors, image); } diff --git a/wayland_cursor_theme.h b/wayland_cursor_theme.h --- a/wayland_cursor_theme.h +++ b/wayland_cursor_theme.h @@ -23,6 +23,7 @@ #include #include +#include "cursor.h" struct wl_cursor_image; struct wl_cursor_theme; @@ -45,7 +46,7 @@ explicit WaylandCursorTheme(KWayland::Client::ShmPool *shm, QObject *parent = nullptr); virtual ~WaylandCursorTheme(); - wl_cursor_image *get(Qt::CursorShape shape); + wl_cursor_image *get(CursorShape shape); wl_cursor_image *get(const QByteArray &name); Q_SIGNALS: diff --git a/wayland_cursor_theme.cpp b/wayland_cursor_theme.cpp --- a/wayland_cursor_theme.cpp +++ b/wayland_cursor_theme.cpp @@ -90,9 +90,9 @@ m_theme = nullptr; } -wl_cursor_image *WaylandCursorTheme::get(Qt::CursorShape shape) +wl_cursor_image *WaylandCursorTheme::get(CursorShape shape) { - return get(Cursor::self()->cursorName(shape)); + return get(shape.name()); } wl_cursor_image *WaylandCursorTheme::get(const QByteArray &name)