Skip to content

Wayland: implement DnD file drop via SCTK DataDeviceManager#4504

Open
joeleaver wants to merge 1 commit intorust-windowing:masterfrom
joeleaver:wayland-dnd
Open

Wayland: implement DnD file drop via SCTK DataDeviceManager#4504
joeleaver wants to merge 1 commit intorust-windowing:masterfrom
joeleaver:wayland-dnd

Conversation

@joeleaver
Copy link

@joeleaver joeleaver commented Mar 6, 2026

Summary

Implements Wayland drag-and-drop (file drop) by integrating SCTK's DataDeviceManagerState into winit-wayland. Emits DragEntered, DragMoved, DragDropped, and DragLeft window events with file paths parsed from text/uri-list.

Closes #1881.

Relationship to #2429 and #4009

There are two existing open PRs for this feature. I built a new one because:

This PR is written from scratch against the current winit-wayland crate, but incorporates the same core approach (SCTK DataDeviceManager + text/uri-list pipe read) and the lessons from debugging those earlier PRs.

Design decisions

set_actions() only in enter(), never on motion. Calling set_actions on every motion event restarts the DnD negotiation. If the user drops during re-negotiation, the compositor sends leave instead of drop_performed. This was the primary reliability issue we hit — a fast drop would race the buffered protocol messages.

conn.flush() after every protocol response. Without explicit flushes after accept_mime_type / set_actions, a fast drop can arrive at the compositor before it has processed our acceptance. The accept/set_actions sit in the client-side buffer while the user releases the mouse.

Pipe read on a background thread with safe OwnedFd. The compositor won't write to the pipe until it processes our receive request, which requires the Wayland event loop to dispatch — but we're inside a handler on that thread. Reading directly would deadlock. We dup the fd via try_clone_to_owned() (no unsafe), drop the original ReadPipe, flush the connection, then thread::spawn + join to read.

Data devices keyed by seat ObjectId. Stored in HashMap<ObjectId, DataDevice> so they're properly cleaned up in remove_seat. A Vec would leak devices when seats are removed.

Re-accept MIME on motion and selected_action. Some compositors (KDE) need the MIME acceptance refreshed on motion or after action negotiation. We re-accept text/uri-list on every motion event and in the selected_action callback, but without calling set_actions again.

Testing

Tested on GNOME (Mutter), KDE (KWin), and wlroots (Sway). File drops from Nautilus, Dolphin, and Thunar all work reliably including fast drops. Clipboard access via external crates (e.g. smithay-clipboard) continues to work — per @kchibisov's note on #2429, the GNOME bug that caused conflicts has been fixed and backported.

Changes

  • New file: winit-wayland/src/seat/data_device.rsDataDeviceHandler, DataOfferHandler, DataSourceHandler impls, URI parsing with unit tests

  • winit-wayland/src/state.rs — adds DataDeviceManagerState, per-seat data devices, DnD tracking state

  • winit-wayland/src/seat/mod.rs — registers module, creates/removes data devices on seat add/remove

  • Tested on all platforms changed

  • Added an entry to CHANGELOG.md if knowledge of this change could be valuable to users

  • Updated documentation to reflect any user-facing changes

  • Created or updated an example program

  • Updated feature matrix

Implements Wayland drag-and-drop file dropping by integrating SCTK's
DataDeviceManagerState. Emits DragEntered, DragMoved, DragDropped, and
DragLeft window events with file paths parsed from text/uri-list MIME.

Key design decisions:
- set_actions() called only once in enter() — repeated calls restart
  negotiation and race with fast drops
- conn.flush() after every protocol response so the compositor receives
  acceptance before the user releases the mouse
- Pipe read on a background thread with safe OwnedFd (no unsafe) to
  avoid deadlocking the Wayland event loop
- Data devices stored in AHashMap<ObjectId, DataDevice> keyed by seat
  for proper cleanup when seats are removed
- Re-accept MIME type on every motion event and in selected_action
  callback for broad compositor compatibility (GNOME, KDE, wlroots)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Support drag and drop on wayland

1 participant