Skip to content

Implement XDND: drag-and-drop support for Linux - #20926

Merged
MrJul merged 38 commits into
AvaloniaUI:masterfrom
MrJul:feature/xdnd
Jul 2, 2026
Merged

Implement XDND: drag-and-drop support for Linux#20926
MrJul merged 38 commits into
AvaloniaUI:masterfrom
MrJul:feature/xdnd

Conversation

@MrJul

@MrJul MrJul commented Mar 17, 2026

Copy link
Copy Markdown
Member

What does the pull request do?

This PR implements XDND for Avalonia's X11 platform, allowing windows to act as drag sources and drop targets.
In short, drag-and-drop now works across processes on Linux.

How was the solution implemented (if it's not obvious)?

This PR supersedes #19232, which had several identified core problems: threading issues and re-implementations of existing algorithms already provided by the clipboard.

Instead, this PR tries to share most of its code with the clipboard implementation, since the underlying concepts are similar.

Key points:

  • Most of the clipboard logic has been moved to base Selection[...] classes, with Clipboard and DragDrop inheritors.
  • Threading is straightforward: no dispatcher calls, no arbitrary timers (except for timeouts), no non-awaited tasks.
  • Since drag-and-drop is synchronous, but X11 isn't, the SynchronousXEventWaiter type waits for specific matching events synchronously while reading from a selection, and puts back unused events onto the standard queue.
  • All atoms used by Avalonia are now interned on startup, even if they don't exist.

Fixed issues

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.0.999-cibuild0063557-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.0.999-cibuild0063878-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.0.999-cibuild0063886-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.0.999-cibuild0063962-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.0.999-cibuild0064001-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.0.999-cibuild0064019-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul
MrJul force-pushed the feature/xdnd branch 2 times, most recently from dced1ad to 0337db6 Compare March 25, 2026 16:04
@MrJul
MrJul marked this pull request as ready for review March 25, 2026 16:07
@MrJul MrJul mentioned this pull request Mar 25, 2026
3 tasks
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.0.999-cibuild0064041-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

// TODO: make the render window invisible from input using XShape.
XUngrabPointer(platform.Display, 0);

var grabResult = XGrabPointer(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to introduce backend-wide event filter instead of dealing with explicit pointer grabs. This will cause user frustration when they will inevitably have a breakpoint to be hit during DnD operation

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. No more explicit grab, I've added a global hook.
XInput2 events are now handled since we don't have a grab preventing them anymore.

Retested with mouse and touch.

/// <summary>
/// An object used to read values, converted to the correct format, from the X11 clipboard.
/// </summary>
internal sealed class ClipboardDataReader(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming both ClipboardDataReader and X11ClipboardImpl.cs don't have heavy changes and it's just git losing rename information. Please, correct me if I'm wrong

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the core logic for these files hasn't changed.

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0066620-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@Dattel

Dattel commented Jun 24, 2026

Copy link
Copy Markdown

Is there anything i need to know to test the implementation on x11 except adding event handlers (AddDropHandler, AddDragEnterHandler, AddLeaveHandler, AddDragOverHandler)

I'm asking because i can't get in working using the alpha-build :-(

@Gillibald

Gillibald commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0066860-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul MrJul closed this Jul 1, 2026
@MrJul
MrJul deleted the feature/xdnd branch July 1, 2026 13:41
@MrJul
MrJul restored the feature/xdnd branch July 1, 2026 13:42
@MrJul MrJul reopened this Jul 1, 2026
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0067033-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0067049-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0067053-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul

MrJul commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

Re-tested again.
Note that on KDE Plasma 6 + Xwayland there's a known bug where the cursor might stay in the "forbidden" mode (but drag-drop actually works correctly). This is out of Avalonia's control, see https://bugs.kde.org/show_bug.cgi?id=496243

@MrJul
MrJul merged commit fd26b29 into AvaloniaUI:master Jul 2, 2026
10 checks passed
ModifAmorphic added a commit to ModifAmorphic/darktide-modificus-curator that referenced this pull request Jul 4, 2026
…#29)

Fills the shell content area (Track A's empty placeholder) with the
mod-list for the active profile, plus the mod source/version model that
backs it.

## Backend model
- `ModSource` (None / Nexus / GitHub) recorded on the shared entry;
versions are raw strings everywhere (GitHub release tags and Nexus file
versions are not SemVer).
- Allocation is plain string equality, which removes the `//
TODO(phase4)` version-equality wart.
- `IModImportService` (folder or `.zip` import into the shared store).
- `IModOrderResolver` + identity stub (the auto-sort seam; real
dependency algorithm deferred).

## Mod-list UI
- View / enable-disable / remove (confirmed) / reorder (up-down) /
per-mod policy (Latest or Pinned to a version string), with a read-only
source badge per row.
- Auto-sort toggle (identity stub, no-op).

## Import flow
- Split-button "Add Mod" (zip default, folder via the flyout) plus
drag-and-drop; both feed a sequential per-mod modal collecting Source +
Version + URL.
- Drag-and-drop is wired but messaged as Windows-only (Avalonia 12.0.x
lacks Linux XDND, wont-backport; PR AvaloniaUI/Avalonia#20926 lands it
in 12.1). Folder import is reachable via the picker on all platforms.

## Tests + docs
- 426 tests (backend model + services + VM logic against hand-rolled
fakes; view mechanics are live-verified).
- Reference, architecture, and AGENTS.md docs updated in place.
KyongSik-Yoon pushed a commit to KyongSik-Yoon/OtterZip that referenced this pull request Aug 11, 2026
Investigating why file-manager drops still did nothing on KDE/Dolphin
turned up the real cause, which is not a handler bug: Avalonia 11's X11
backend has no XDND drop target at all. Binary inspection confirms the
X11 backend exports only BeginMoveDrag/BeginResizeDrag, while the Win32
backend has a full IDropTarget; receiving external drops on Linux landed
only in Avalonia 12.1 (AvaloniaUI/Avalonia#20926), explicitly not
backported to 11.x. No drag event is ever delivered to the app here, so
no handler change could have fixed it.

Correct the record rather than leave a wrong explanation in the tree:
- Replace the "handledEventsToo is why it didn't work" comments with the
  actual reason, and keep the handlers as forward-compatible wiring that
  already works on Windows/macOS and lights up on a future Avalonia 12+.
- Stop the docs promising drag-to-add on Linux; point users at the Add
  buttons, "Open With", and the context-menu actions, and state the
  limitation plainly under Differences.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJonUFTLyWKeg9Ut5TrUWK
KyongSik-Yoon pushed a commit to KyongSik-Yoon/OtterZip that referenced this pull request Aug 11, 2026
Avalonia 11's X11 backend has no XDND drop target, so a file dragged from
Dolphin/Nautilus/Thunar never reached the window. Receiving external
drops on X11 landed in Avalonia 12.1 (AvaloniaUI/Avalonia#20926), not
backported to 11.x — so the toolkit has to move to 12.1 for this to work
at all.

- Directory.Packages.props: Avalonia 11.2.* → 12.1.* (all four packages).
- Migrate the drag-and-drop code to Avalonia 12's data-transfer model,
  which removed IDataObject: DragEventArgs.Data → DataTransfer,
  Contains(DataFormats.Files) → Contains(DataFormat.File), and
  IDataObject.GetFiles() → IDataTransfer.TryGetFiles(). Both the archive
  contents window and the main drop window.
- Restore the docs and code comments to say drag-to-add works on Linux
  (via 12.1), reverting the "unsupported on X11" wording.

Builds clean; the app launches and a self-contained linux-x64 publish
runs (both windows, native lib bundled) under xvfb. Interactive drag from
a file manager can't be exercised headlessly here — that needs a real
desktop test before this merges to master.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJonUFTLyWKeg9Ut5TrUWK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Known][Waiting] Drag and Drop files doesn't work on Linux

8 participants