diff --git a/src/Avalonia.X11/Selections/DragDrop/DragDropDataTransfer.cs b/src/Avalonia.X11/Selections/DragDrop/DragDropDataTransfer.cs index a142eea6b5..b1dc030800 100644 --- a/src/Avalonia.X11/Selections/DragDrop/DragDropDataTransfer.cs +++ b/src/Avalonia.X11/Selections/DragDrop/DragDropDataTransfer.cs @@ -1,7 +1,6 @@ using System; using Avalonia.Input; using Avalonia.Input.Platform; -using static Avalonia.X11.XLib; namespace Avalonia.X11.Selections.DragDrop; @@ -10,9 +9,7 @@ namespace Avalonia.X11.Selections.DragDrop; /// internal sealed class DragDropDataTransfer( DragDropDataReader reader, - X11Atoms atoms, DataFormat[] dataFormats, - IntPtr display, IntPtr sourceWindow, IntPtr targetWindow, IInputRoot inputRoot) @@ -20,44 +17,24 @@ internal sealed class DragDropDataTransfer( { public IntPtr SourceWindow { get; } = sourceWindow; + public IntPtr TargetWindow { get; } = targetWindow; + public IInputRoot InputRoot { get; } = inputRoot; public Point? LastPosition { get; set; } public IntPtr LastTimestamp { get; set; } + public DragDropEffects ResultEffects { get; set; } = DragDropEffects.None; + + public bool Dropped { get; set; } + protected override DataFormat[] ProvideFormats() => dataFormats; protected override PlatformDataTransferItem[] ProvideItems() => reader.CreateItems(); - private void SendXdndFinished() - { - var evt = new XEvent - { - ClientMessageEvent = new XClientMessageEvent - { - type = XEventName.ClientMessage, - display = display, - window = SourceWindow, - message_type = atoms.XdndFinished, - format = 32, - ptr1 = targetWindow, - ptr2 = 0, - ptr3 = 0, - ptr4 = 0, - ptr5 = 0 - } - }; - - XSendEvent(display, SourceWindow, false, (IntPtr)EventMask.NoEventMask, ref evt); - XFlush(display); - } - public override void Dispose() - { - reader.Dispose(); - SendXdndFinished(); - } + => reader.Dispose(); } diff --git a/src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs b/src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs index 65b2be5c72..3fa5928d51 100644 --- a/src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs +++ b/src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs @@ -19,7 +19,6 @@ internal sealed class X11DropTarget private readonly IntPtr _display; private readonly X11Atoms _atoms; private DragDropDataTransfer? _currentDrag; - private DragDropEffects _resultEffects; public X11DropTarget(IDragDropDevice dragDropDevice, IXdndWindow window, IntPtr _display, X11Atoms atoms) { @@ -72,89 +71,52 @@ internal sealed class X11DropTarget } var (dataFormats, textFormats) = DataFormatHelper.ToDataFormats(formats.ToArray(), _atoms); - var reader = new DragDropDataReader(_atoms, textFormats, dataFormats, _display, _window.Handle); - - _currentDrag = new DragDropDataTransfer( - reader, - _atoms, - dataFormats, - _display, - sourceWindow, - _window.Handle, - inputRoot); + _currentDrag = new DragDropDataTransfer(reader, dataFormats, sourceWindow, _window.Handle, inputRoot); } public void OnXdndPosition(in XClientMessageEvent message) { - if (_currentDrag is null) - return; - - var sourceWindow = message.ptr1; - if (sourceWindow != _currentDrag.SourceWindow) + if (_currentDrag is not { } drag || message.ptr1 != drag.SourceWindow) return; var screenX = (ushort)((message.ptr3 >> 16) & 0xFFFF); var screenY = (ushort)(message.ptr3 & 0xFFFF); var position = _window.PointToClient(new PixelPoint(screenX, screenY)); var requestedEffects = XdndActionHelper.ActionToEffects(message.ptr5, _atoms); - var eventType = _currentDrag.LastPosition is null ? RawDragEventType.DragEnter : RawDragEventType.DragOver; + var eventType = drag.LastPosition is null ? RawDragEventType.DragEnter : RawDragEventType.DragOver; - _currentDrag.LastPosition = position; - _currentDrag.LastTimestamp = message.ptr4; + drag.LastPosition = position; + drag.LastTimestamp = message.ptr4; var dragEvent = new RawDragEvent( _dragDropDevice, eventType, - _currentDrag.InputRoot, + drag.InputRoot, position, - _currentDrag, + drag, requestedEffects, RawInputModifiers.None); _dragDropDevice.ProcessRawEvent(dragEvent); - _resultEffects = dragEvent.Effects; - var resultAction = XdndActionHelper.EffectsToAction(_resultEffects, _atoms); - - var evt = new XEvent - { - ClientMessageEvent = - { - type = XEventName.ClientMessage, - send_event = 1, - window = sourceWindow, - message_type = _atoms.XdndStatus, - format = 32, - ptr1 = _window.Handle, - ptr2 = resultAction == 0 ? 0 : 1, - ptr3 = 0, - ptr4 = 0, - ptr5 = resultAction - } - }; + drag.ResultEffects = dragEvent.Effects; - XSendEvent(_display, sourceWindow, false, (IntPtr)EventMask.NoEventMask, ref evt); - XFlush(_display); + var resultAction = XdndActionHelper.EffectsToAction(dragEvent.Effects, _atoms); + SendXdndMessage(_atoms.XdndStatus, drag, resultAction == 0 ? 0 : 1, 0, 0, resultAction); } public void OnXdndLeave(in XClientMessageEvent message) { - if (_currentDrag is null) - return; - - var sourceWindow = message.ptr1; - if (sourceWindow != _currentDrag.SourceWindow) + if (_currentDrag is not { } drag || message.ptr1 != drag.SourceWindow) return; - _resultEffects = DragDropEffects.None; - var dragLeave = new RawDragEvent( _dragDropDevice, RawDragEventType.DragLeave, - _currentDrag.InputRoot, + drag.InputRoot, default, - _currentDrag, + drag, DragDropEffects.None, RawInputModifiers.None); @@ -165,30 +127,68 @@ internal sealed class X11DropTarget public void OnXdndDrop(in XClientMessageEvent message) { - if (_currentDrag is null) - return; - - var sourceWindow = message.ptr1; - if (sourceWindow != _currentDrag.SourceWindow) + if (_currentDrag is not { } drag || message.ptr1 != drag.SourceWindow) return; var drop = new RawDragEvent( _dragDropDevice, RawDragEventType.Drop, - _currentDrag.InputRoot, - _currentDrag.LastPosition ?? default, - _currentDrag, - _resultEffects, + drag.InputRoot, + drag.LastPosition ?? default, + drag, + drag.ResultEffects, RawInputModifiers.None); _dragDropDevice.ProcessRawEvent(drop); + drag.ResultEffects = drop.Effects; + drag.Dropped = true; + DisposeCurrentDrag(); } + private void SendXdndMessage( + IntPtr messageType, + DragDropDataTransfer drag, + IntPtr ptr2, + IntPtr ptr3, + IntPtr ptr4, + IntPtr ptr5) + { + var evt = new XEvent + { + ClientMessageEvent = new XClientMessageEvent + { + type = XEventName.ClientMessage, + display = _display, + window = drag.SourceWindow, + message_type = messageType, + format = 32, + ptr1 = drag.TargetWindow, + ptr2 = ptr2, + ptr3 = ptr3, + ptr4 = ptr4, + ptr5 = ptr5 + } + }; + + XSendEvent(_display, drag.SourceWindow, false, (IntPtr)EventMask.NoEventMask, ref evt); + XFlush(_display); + } + private void DisposeCurrentDrag() { - _currentDrag?.Dispose(); + if (_currentDrag is not { } drag) + return; + _currentDrag = null; + + if (drag.Dropped) + { + var resultAction = XdndActionHelper.EffectsToAction(drag.ResultEffects, _atoms); + SendXdndMessage(_atoms.XdndFinished, drag, resultAction == 0 ? 0 : 1, resultAction, 0, 0); + } + + drag.Dispose(); } }