Browse Source

Xdnd: send XdndFinished with correct args

pull/20926/head
Julien Lebosquain 15 hours ago
parent
commit
efb2589add
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 37
      src/Avalonia.X11/Selections/DragDrop/DragDropDataTransfer.cs
  2. 122
      src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs

37
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;
/// </summary>
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();
}

122
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();
}
}

Loading…
Cancel
Save