diff --git a/src/Avalonia.X11/Selections/DragDrop/DragDropDataTransfer.cs b/src/Avalonia.X11/Selections/DragDrop/DragDropDataTransfer.cs index aa626643ff..cdbdcee510 100644 --- a/src/Avalonia.X11/Selections/DragDrop/DragDropDataTransfer.cs +++ b/src/Avalonia.X11/Selections/DragDrop/DragDropDataTransfer.cs @@ -15,7 +15,8 @@ internal sealed class DragDropDataTransfer( IntPtr display, IntPtr sourceWindow, IntPtr targetWindow, - IInputRoot inputRoot) + IInputRoot inputRoot, + byte xdndVersion) : PlatformDataTransfer { public IntPtr SourceWindow { get; } = sourceWindow; @@ -32,10 +33,8 @@ internal sealed class DragDropDataTransfer( protected override PlatformDataTransferItem[] ProvideItems() => reader.CreateItems(); - public override void Dispose() + private void SendXdndFinished() { - reader.Dispose(); - var evt = new XEvent { ClientMessageEvent = new XClientMessageEvent @@ -56,4 +55,12 @@ internal sealed class DragDropDataTransfer( XSendEvent(display, SourceWindow, false, (IntPtr)EventMask.NoEventMask, ref evt); XFlush(display); } + + public override void Dispose() + { + reader.Dispose(); + + if (xdndVersion >= 5) + SendXdndFinished(); + } } diff --git a/src/Avalonia.X11/Selections/DragDrop/XdndHandler.cs b/src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs similarity index 94% rename from src/Avalonia.X11/Selections/DragDrop/XdndHandler.cs rename to src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs index d657b23894..d9882c0503 100644 --- a/src/Avalonia.X11/Selections/DragDrop/XdndHandler.cs +++ b/src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs @@ -11,8 +11,10 @@ namespace Avalonia.X11.Selections.DragDrop; /// Manages XDND (drag and drop) for a given X11 window. /// Specs: https://www.freedesktop.org/wiki/Specifications/XDND/ /// -internal sealed class XdndHandler +internal sealed class X11DropTarget { + // Spec: every application that supports XDND version N must also support all previous versions (3 to N-1). + private const byte MinXdndVersion = 3; private const byte XdndVersion = 5; private readonly IDragDropDevice _dragDropDevice; @@ -21,7 +23,7 @@ internal sealed class XdndHandler private readonly X11Atoms _atoms; private DragDropDataTransfer? _currentDrag; - public XdndHandler(IDragDropDevice dragDropDevice, IXdndWindow window, IntPtr _display, X11Atoms atoms) + public X11DropTarget(IDragDropDevice dragDropDevice, IXdndWindow window, IntPtr _display, X11Atoms atoms) { _dragDropDevice = dragDropDevice; _window = window; @@ -40,7 +42,7 @@ internal sealed class XdndHandler // Spec: If the version number in the XdndEnter message is higher than what the target can support, // the target should ignore the source. var version = (byte)((message.ptr2 >> 24) & 0xFF); - if (version > XdndVersion) + if (version is < MinXdndVersion or > XdndVersion) return; // If we ever receive a new XdndEnter message while a drag is in progress, it means something went wrong. @@ -82,7 +84,8 @@ internal sealed class XdndHandler _display, sourceWindow, _window.Handle, - inputRoot); + inputRoot, + version); } public void HandleXdndPosition(in XClientMessageEvent message) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 97f2cf9bb0..d64113a37b 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -71,7 +71,7 @@ namespace Avalonia.X11 private bool _usePositioningFlags = false; private X11WindowMode _mode; private IWindowIconImpl? _iconImpl; - private readonly XdndHandler? _xdndHandler; + private readonly X11DropTarget? _dropTarget; private enum XSyncState { @@ -280,7 +280,7 @@ namespace Avalonia.X11 }); if (AvaloniaLocator.Current.GetService() is { } dragDropDevice) - _xdndHandler = new XdndHandler(dragDropDevice, this, _x11.Display, _x11.Atoms); + _dropTarget = new X11DropTarget(dragDropDevice, this, _x11.Display, _x11.Atoms); platform.X11Screens.Changed += OnScreensChanged; } @@ -700,13 +700,13 @@ namespace Avalonia.X11 } } else if (messageType == _x11.Atoms.XdndEnter) - _xdndHandler?.HandleXdndEnter(ev.ClientMessageEvent); + _dropTarget?.HandleXdndEnter(ev.ClientMessageEvent); else if (messageType == _x11.Atoms.XdndPosition) - _xdndHandler?.HandleXdndPosition(ev.ClientMessageEvent); + _dropTarget?.HandleXdndPosition(ev.ClientMessageEvent); else if (messageType == _x11.Atoms.XdndLeave) - _xdndHandler?.HandleXdndLeave(ev.ClientMessageEvent); + _dropTarget?.HandleXdndLeave(ev.ClientMessageEvent); else if (messageType == _x11.Atoms.XdndDrop) - _xdndHandler?.HandleXdndDrop(ev.ClientMessageEvent); + _dropTarget?.HandleXdndDrop(ev.ClientMessageEvent); } else if (ev.type == XEventName.KeyPress || ev.type == XEventName.KeyRelease) {