Browse Source

Xdnd: send XdndFinished with correct args

pull/20926/head
Julien Lebosquain 7 months ago
parent
commit
2ac5df86f8
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 System;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Platform; using Avalonia.Input.Platform;
using static Avalonia.X11.XLib;
namespace Avalonia.X11.Selections.DragDrop; namespace Avalonia.X11.Selections.DragDrop;
@ -10,9 +9,7 @@ namespace Avalonia.X11.Selections.DragDrop;
/// </summary> /// </summary>
internal sealed class DragDropDataTransfer( internal sealed class DragDropDataTransfer(
DragDropDataReader reader, DragDropDataReader reader,
X11Atoms atoms,
DataFormat[] dataFormats, DataFormat[] dataFormats,
IntPtr display,
IntPtr sourceWindow, IntPtr sourceWindow,
IntPtr targetWindow, IntPtr targetWindow,
IInputRoot inputRoot) IInputRoot inputRoot)
@ -20,44 +17,24 @@ internal sealed class DragDropDataTransfer(
{ {
public IntPtr SourceWindow { get; } = sourceWindow; public IntPtr SourceWindow { get; } = sourceWindow;
public IntPtr TargetWindow { get; } = targetWindow;
public IInputRoot InputRoot { get; } = inputRoot; public IInputRoot InputRoot { get; } = inputRoot;
public Point? LastPosition { get; set; } public Point? LastPosition { get; set; }
public IntPtr LastTimestamp { get; set; } public IntPtr LastTimestamp { get; set; }
public DragDropEffects ResultEffects { get; set; } = DragDropEffects.None;
public bool Dropped { get; set; }
protected override DataFormat[] ProvideFormats() protected override DataFormat[] ProvideFormats()
=> dataFormats; => dataFormats;
protected override PlatformDataTransferItem[] ProvideItems() protected override PlatformDataTransferItem[] ProvideItems()
=> reader.CreateItems(); => 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() public override void Dispose()
{ => reader.Dispose();
reader.Dispose();
SendXdndFinished();
}
} }

122
src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs

@ -19,7 +19,6 @@ internal sealed class X11DropTarget
private readonly IntPtr _display; private readonly IntPtr _display;
private readonly X11Atoms _atoms; private readonly X11Atoms _atoms;
private DragDropDataTransfer? _currentDrag; private DragDropDataTransfer? _currentDrag;
private DragDropEffects _resultEffects;
public X11DropTarget(IDragDropDevice dragDropDevice, IXdndWindow window, IntPtr _display, X11Atoms atoms) 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 (dataFormats, textFormats) = DataFormatHelper.ToDataFormats(formats.ToArray(), _atoms);
var reader = new DragDropDataReader(_atoms, textFormats, dataFormats, _display, _window.Handle); var reader = new DragDropDataReader(_atoms, textFormats, dataFormats, _display, _window.Handle);
_currentDrag = new DragDropDataTransfer(reader, dataFormats, sourceWindow, _window.Handle, inputRoot);
_currentDrag = new DragDropDataTransfer(
reader,
_atoms,
dataFormats,
_display,
sourceWindow,
_window.Handle,
inputRoot);
} }
public void OnXdndPosition(in XClientMessageEvent message) public void OnXdndPosition(in XClientMessageEvent message)
{ {
if (_currentDrag is null) if (_currentDrag is not { } drag || message.ptr1 != drag.SourceWindow)
return;
var sourceWindow = message.ptr1;
if (sourceWindow != _currentDrag.SourceWindow)
return; return;
var screenX = (ushort)((message.ptr3 >> 16) & 0xFFFF); var screenX = (ushort)((message.ptr3 >> 16) & 0xFFFF);
var screenY = (ushort)(message.ptr3 & 0xFFFF); var screenY = (ushort)(message.ptr3 & 0xFFFF);
var position = _window.PointToClient(new PixelPoint(screenX, screenY)); var position = _window.PointToClient(new PixelPoint(screenX, screenY));
var requestedEffects = XdndActionHelper.ActionToEffects(message.ptr5, _atoms); 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; drag.LastPosition = position;
_currentDrag.LastTimestamp = message.ptr4; drag.LastTimestamp = message.ptr4;
var dragEvent = new RawDragEvent( var dragEvent = new RawDragEvent(
_dragDropDevice, _dragDropDevice,
eventType, eventType,
_currentDrag.InputRoot, drag.InputRoot,
position, position,
_currentDrag, drag,
requestedEffects, requestedEffects,
RawInputModifiers.None); RawInputModifiers.None);
_dragDropDevice.ProcessRawEvent(dragEvent); _dragDropDevice.ProcessRawEvent(dragEvent);
_resultEffects = dragEvent.Effects; drag.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
}
};
XSendEvent(_display, sourceWindow, false, (IntPtr)EventMask.NoEventMask, ref evt); var resultAction = XdndActionHelper.EffectsToAction(dragEvent.Effects, _atoms);
XFlush(_display); SendXdndMessage(_atoms.XdndStatus, drag, resultAction == 0 ? 0 : 1, 0, 0, resultAction);
} }
public void OnXdndLeave(in XClientMessageEvent message) public void OnXdndLeave(in XClientMessageEvent message)
{ {
if (_currentDrag is null) if (_currentDrag is not { } drag || message.ptr1 != drag.SourceWindow)
return;
var sourceWindow = message.ptr1;
if (sourceWindow != _currentDrag.SourceWindow)
return; return;
_resultEffects = DragDropEffects.None;
var dragLeave = new RawDragEvent( var dragLeave = new RawDragEvent(
_dragDropDevice, _dragDropDevice,
RawDragEventType.DragLeave, RawDragEventType.DragLeave,
_currentDrag.InputRoot, drag.InputRoot,
default, default,
_currentDrag, drag,
DragDropEffects.None, DragDropEffects.None,
RawInputModifiers.None); RawInputModifiers.None);
@ -165,30 +127,68 @@ internal sealed class X11DropTarget
public void OnXdndDrop(in XClientMessageEvent message) public void OnXdndDrop(in XClientMessageEvent message)
{ {
if (_currentDrag is null) if (_currentDrag is not { } drag || message.ptr1 != drag.SourceWindow)
return;
var sourceWindow = message.ptr1;
if (sourceWindow != _currentDrag.SourceWindow)
return; return;
var drop = new RawDragEvent( var drop = new RawDragEvent(
_dragDropDevice, _dragDropDevice,
RawDragEventType.Drop, RawDragEventType.Drop,
_currentDrag.InputRoot, drag.InputRoot,
_currentDrag.LastPosition ?? default, drag.LastPosition ?? default,
_currentDrag, drag,
_resultEffects, drag.ResultEffects,
RawInputModifiers.None); RawInputModifiers.None);
_dragDropDevice.ProcessRawEvent(drop); _dragDropDevice.ProcessRawEvent(drop);
drag.ResultEffects = drop.Effects;
drag.Dropped = true;
DisposeCurrentDrag(); 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() private void DisposeCurrentDrag()
{ {
_currentDrag?.Dispose(); if (_currentDrag is not { } drag)
return;
_currentDrag = null; _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