diff --git a/src/pointer_input.cpp b/src/pointer_input.cpp index 2fc931be69..7f5350ef39 100644 --- a/src/pointer_input.cpp +++ b/src/pointer_input.cpp @@ -22,6 +22,7 @@ #include "mousebuttons.h" #include "osd.h" #include "screenedge.h" +#include "wayland/abstract_data_source.h" #include "wayland/display.h" #include "wayland/pointer.h" #include "wayland/pointerconstraints_v1.h" @@ -964,6 +965,7 @@ CursorImage::CursorImage(PointerInputRedirection *parent) m_decoration.cursor = std::make_unique(); m_serverCursor.surface = std::make_unique(); m_serverCursor.shape = std::make_unique(); + m_dragCursor = std::make_unique(); #if KWIN_BUILD_SCREENLOCKER if (kwinApp()->supportsLockScreen()) { @@ -988,6 +990,7 @@ CursorImage::CursorImage(PointerInputRedirection *parent) m_windowSelectionCursor->setTheme(m_waylandImage.theme()); m_decoration.cursor->setTheme(m_waylandImage.theme()); m_serverCursor.shape->setTheme(m_waylandImage.theme()); + m_dragCursor->setTheme(m_waylandImage.theme()); connect(&m_waylandImage, &WaylandCursorImage::themeChanged, this, [this] { m_effectsCursor->setTheme(m_waylandImage.theme()); @@ -996,6 +999,14 @@ CursorImage::CursorImage(PointerInputRedirection *parent) m_windowSelectionCursor->setTheme(m_waylandImage.theme()); m_decoration.cursor->setTheme(m_waylandImage.theme()); m_serverCursor.shape->setTheme(m_waylandImage.theme()); + m_dragCursor->setTheme(m_waylandImage.theme()); + }); + + connect(waylandServer()->seat(), &SeatInterface::dragStarted, this, [this]() { + m_dragCursor->setShape(Qt::ForbiddenCursor); + connect(waylandServer()->seat()->dragSource(), &AbstractDataSource::dndActionChanged, this, &CursorImage::updateDragCursor); + connect(waylandServer()->seat()->dragSource(), &AbstractDataSource::acceptedChanged, this, &CursorImage::updateDragCursor); + reevaluteSource(); }); PointerInterface *pointer = waylandServer()->seat()->pointer(); @@ -1064,6 +1075,32 @@ void CursorImage::updateMoveResize() reevaluteSource(); } +void CursorImage::updateDragCursor() +{ + AbstractDataSource *dragSource = waylandServer()->seat()->dragSource(); + if (dragSource && dragSource->isAccepted()) { + switch (dragSource->selectedDndAction()) { + case DataDeviceManagerInterface::DnDAction::None: + m_dragCursor->setShape(Qt::ClosedHandCursor); + break; + case DataDeviceManagerInterface::DnDAction::Copy: + m_dragCursor->setShape(Qt::DragCopyCursor); + break; + case DataDeviceManagerInterface::DnDAction::Move: + m_dragCursor->setShape(Qt::DragMoveCursor); + break; + case DataDeviceManagerInterface::DnDAction::Ask: + // Cursor themes don't have anything better in the themes yet + // a dnd-drag-ask is proposed + m_dragCursor->setShape(Qt::ClosedHandCursor); + break; + } + } else { + m_dragCursor->setShape(Qt::ForbiddenCursor); + } + reevaluteSource(); +} + void CursorImage::updateServerCursor(const PointerCursor &cursor) { if (auto surfaceCursor = std::get_if(&cursor)) { @@ -1153,6 +1190,10 @@ void CursorImage::reevaluteSource() setSource(m_serverCursor.cursor); return; } + if (waylandServer()->seat()->isDrag()) { + setSource(m_dragCursor.get()); + return; + } if (input()->isSelectingWindow()) { setSource(m_windowSelectionCursor.get()); return; diff --git a/src/pointer_input.h b/src/pointer_input.h index dbbc633010..9d7d698d99 100644 --- a/src/pointer_input.h +++ b/src/pointer_input.h @@ -244,6 +244,7 @@ private: void updateDecoration(); void updateDecorationCursor(); void updateMoveResize(); + void updateDragCursor(); void handleFocusedSurfaceChanged(); @@ -255,6 +256,7 @@ private: std::unique_ptr m_fallbackCursor; std::unique_ptr m_moveResizeCursor; std::unique_ptr m_windowSelectionCursor; + std::unique_ptr m_dragCursor; struct { diff --git a/src/wayland/abstract_data_source.h b/src/wayland/abstract_data_source.h index 1962c44f2d..6fd7c6e170 100644 --- a/src/wayland/abstract_data_source.h +++ b/src/wayland/abstract_data_source.h @@ -110,6 +110,8 @@ Q_SIGNALS: void mimeTypeOffered(const QString &); void supportedDragAndDropActionsChanged(); void keyboardModifiersChanged(); + void dndActionChanged(); + void acceptedChanged(); protected: explicit AbstractDataSource(QObject *parent = nullptr); diff --git a/src/wayland/datasource.cpp b/src/wayland/datasource.cpp index 1713c135c3..72278836fc 100644 --- a/src/wayland/datasource.cpp +++ b/src/wayland/datasource.cpp @@ -91,6 +91,7 @@ void DataSourceInterface::accept(const QString &mimeType) { d->send_target(mimeType); d->isAccepted = !mimeType.isNull(); + Q_EMIT acceptedChanged(); } void DataSourceInterface::requestData(const QString &mimeType, qint32 fd) @@ -148,6 +149,7 @@ void DataSourceInterface::dndFinished() void DataSourceInterface::dndAction(DataDeviceManagerInterface::DnDAction action) { d->selectedDndAction = action; + Q_EMIT dndActionChanged(); if (d->resource()->version() < WL_DATA_SOURCE_ACTION_SINCE_VERSION) { return; @@ -188,11 +190,6 @@ bool DataSourceInterface::isAccepted() const return d->isAccepted; } -void DataSourceInterface::setAccepted(bool accepted) -{ - d->isAccepted = accepted; -} - XdgToplevelDragV1Interface *DataSourceInterface::xdgToplevelDrag() const { return d->xdgToplevelDrag; diff --git a/src/wayland/datasource.h b/src/wayland/datasource.h index e19d3cf4cd..de9214ff18 100644 --- a/src/wayland/datasource.h +++ b/src/wayland/datasource.h @@ -48,7 +48,6 @@ public: wl_client *client() const override; bool isAccepted() const override; - void setAccepted(bool accepted); XdgToplevelDragV1Interface *xdgToplevelDrag() const; diff --git a/src/xwayland/datasource.cpp b/src/xwayland/datasource.cpp index ce907fe1c9..11b8415a44 100644 --- a/src/xwayland/datasource.cpp +++ b/src/xwayland/datasource.cpp @@ -35,6 +35,7 @@ void XwlDataSource::setMimeTypes(const QStringList &mimeTypes) void XwlDataSource::accept(const QString &mimeType) { m_accepted = !mimeType.isEmpty(); + Q_EMIT acceptedChanged(); } DataDeviceManagerInterface::DnDActions XwlDataSource::supportedDragAndDropActions() const @@ -56,6 +57,7 @@ DataDeviceManagerInterface::DnDAction XwlDataSource::selectedDndAction() const void XwlDataSource::dndAction(DataDeviceManagerInterface::DnDAction action) { m_dndAction = action; + Q_EMIT dndActionChanged(); } bool XwlDataSource::isAccepted() const