Browse Source

Xdnd: send messages

pull/20926/head
Julien Lebosquain 7 months ago
parent
commit
17563ac0ea
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 3
      src/Avalonia.Base/Input/AsyncDataTransferExtensions.cs
  2. 43
      src/Avalonia.Base/Input/SyncToAsyncDataTransfer.cs
  3. 21
      src/Avalonia.Base/Input/SyncToAsyncDataTransferItem.cs
  4. 12
      src/Avalonia.X11/Selections/Clipboard/X11ClipboardImpl.cs
  5. 15
      src/Avalonia.X11/Selections/DragDrop/DragDropDataProvider.cs
  6. 294
      src/Avalonia.X11/Selections/DragDrop/X11DragSource.cs
  7. 26
      src/Avalonia.X11/Selections/DragDrop/X11DropTarget.cs
  8. 29
      src/Avalonia.X11/Selections/DragDrop/XdndActionHelper.cs
  9. 16
      src/Avalonia.X11/Selections/SelectionDataProvider.cs

3
src/Avalonia.Base/Input/AsyncDataTransferExtensions.cs

@ -27,6 +27,9 @@ public static class AsyncDataTransferExtensions
return new AsyncToSyncDataTransfer(asyncDataTransfer); return new AsyncToSyncDataTransfer(asyncDataTransfer);
} }
internal static IAsyncDataTransfer ToAsynchronous(this IDataTransfer dataTransfer)
=> dataTransfer as IAsyncDataTransfer ?? new SyncToAsyncDataTransfer(dataTransfer);
/// <summary> /// <summary>
/// Gets whether a <see cref="IAsyncDataTransfer"/> supports a specific format. /// Gets whether a <see cref="IAsyncDataTransfer"/> supports a specific format.
/// </summary> /// </summary>

43
src/Avalonia.Base/Input/SyncToAsyncDataTransfer.cs

@ -0,0 +1,43 @@
using System.Collections.Generic;
namespace Avalonia.Input;
/// <summary>
/// Wraps a <see cref="IDataTransfer"/> into a <see cref="IAsyncDataTransfer"/>.
/// </summary>
/// <param name="dataTransfer">The sync object to wrap.</param>
internal sealed class SyncToAsyncDataTransfer(IDataTransfer dataTransfer)
: IDataTransfer, IAsyncDataTransfer
{
private SyncToAsyncDataTransferItem[]? _items;
public IReadOnlyList<DataFormat> Formats
=> dataTransfer.Formats;
public IReadOnlyList<SyncToAsyncDataTransferItem> Items
=> _items ??= ProvideItems();
IReadOnlyList<IDataTransferItem> IDataTransfer.Items
=> dataTransfer.Items;
IReadOnlyList<IAsyncDataTransferItem> IAsyncDataTransfer.Items
=> Items;
private SyncToAsyncDataTransferItem[] ProvideItems()
{
var asyncItems = dataTransfer.Items;
var count = asyncItems.Count;
var syncItems = new SyncToAsyncDataTransferItem[count];
for (var i = 0; i < count; ++i)
{
var asyncItem = asyncItems[i];
syncItems[i] = new SyncToAsyncDataTransferItem(asyncItem);
}
return syncItems;
}
public void Dispose()
=> dataTransfer.Dispose();
}

21
src/Avalonia.Base/Input/SyncToAsyncDataTransferItem.cs

@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Avalonia.Input;
/// <summary>
/// Wraps a <see cref="IDataTransferItem"/> into a <see cref="IAsyncDataTransferItem"/>.
/// </summary>
/// <param name="dataTransferItem">The sync item to wrap.</param>
internal sealed class SyncToAsyncDataTransferItem(IDataTransferItem dataTransferItem)
: IDataTransferItem, IAsyncDataTransferItem
{
public IReadOnlyList<DataFormat> Formats
=> dataTransferItem.Formats;
public object? TryGetRaw(DataFormat format)
=> dataTransferItem.TryGetRaw(format);
public Task<object?> TryGetRawAsync(DataFormat format)
=> Task.FromResult(dataTransferItem.TryGetRaw(format));
}

12
src/Avalonia.X11/Selections/Clipboard/X11ClipboardImpl.cs

@ -17,7 +17,7 @@ internal sealed class X11ClipboardImpl(AvaloniaX11Platform platform)
if (ev.type == XEventName.SelectionClear) if (ev.type == XEventName.SelectionClear)
{ {
// We night have already regained the clipboard ownership by the time a SelectionClear message arrives. // We night have already regained the clipboard ownership by the time a SelectionClear message arrives.
if (GetOwner() != Handle) if (GetOwner() != Window)
DataTransfer = null; DataTransfer = null;
_storeAtomTcs?.TrySetResult(); _storeAtomTcs?.TrySetResult();
@ -67,11 +67,11 @@ internal sealed class X11ClipboardImpl(AvaloniaX11Platform platform)
var atomValues = ConvertDataTransfer(dataTransfer); var atomValues = ConvertDataTransfer(dataTransfer);
XChangeProperty(Platform.Display, Handle, atoms.AVALONIA_SAVE_TARGETS_PROPERTY_ATOM, atoms.ATOM, 32, XChangeProperty(Platform.Display, Window, atoms.AVALONIA_SAVE_TARGETS_PROPERTY_ATOM, atoms.ATOM, 32,
PropertyMode.Replace, atomValues, atomValues.Length); PropertyMode.Replace, atomValues, atomValues.Length);
XConvertSelection(Platform.Display, atoms.CLIPBOARD_MANAGER, atoms.SAVE_TARGETS, XConvertSelection(Platform.Display, atoms.CLIPBOARD_MANAGER, atoms.SAVE_TARGETS,
atoms.AVALONIA_SAVE_TARGETS_PROPERTY_ATOM, Handle, 0); atoms.AVALONIA_SAVE_TARGETS_PROPERTY_ATOM, Window, 0);
await _storeAtomTcs.Task; await _storeAtomTcs.Task;
} }
@ -90,7 +90,7 @@ internal sealed class X11ClipboardImpl(AvaloniaX11Platform platform)
if (owner == 0) if (owner == 0)
return null; return null;
if (owner == Handle && DataTransfer is { } storedDataTransfer) if (owner == Window && DataTransfer is { } storedDataTransfer)
return storedDataTransfer; return storedDataTransfer;
// Get the formats while we're in an async method, since IAsyncDataTransfer.GetFormats() is synchronous. // Get the formats while we're in an async method, since IAsyncDataTransfer.GetFormats() is synchronous.
@ -115,10 +115,10 @@ internal sealed class X11ClipboardImpl(AvaloniaX11Platform platform)
public Task SetDataAsync(IAsyncDataTransfer dataTransfer) public Task SetDataAsync(IAsyncDataTransfer dataTransfer)
{ {
DataTransfer = dataTransfer; DataTransfer = dataTransfer;
SetOwner(Handle); SetOwner(Window);
return StoreAtomsInClipboardManager(dataTransfer); return StoreAtomsInClipboardManager(dataTransfer);
} }
public Task<bool> IsCurrentOwnerAsync() public Task<bool> IsCurrentOwnerAsync()
=> Task.FromResult(GetOwner() == Handle); => Task.FromResult(GetOwner() == Window);
} }

15
src/Avalonia.X11/Selections/DragDrop/DragDropDataProvider.cs

@ -0,0 +1,15 @@
using Avalonia.Input;
namespace Avalonia.X11.Selections.DragDrop;
internal sealed class DragDropDataProvider : SelectionDataProvider
{
public DragDropDataProvider(AvaloniaX11Platform platform, IAsyncDataTransfer dataTransfer)
: base(platform, platform.Info.Atoms.XdndSelection)
{
DataTransfer = dataTransfer;
}
public void SetAsOwner()
=> SetOwner(Window);
}

294
src/Avalonia.X11/Selections/DragDrop/X11DragSource.cs

@ -1,10 +1,12 @@
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Platform; using Avalonia.Input.Platform;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Threading; using Avalonia.Threading;
using static Avalonia.X11.Selections.DragDrop.XdndConstants;
using static Avalonia.X11.XLib; using static Avalonia.X11.XLib;
namespace Avalonia.X11.Selections.DragDrop; namespace Avalonia.X11.Selections.DragDrop;
@ -29,7 +31,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
var cursorFactory = AvaloniaLocator.Current.GetService<ICursorFactory>(); var cursorFactory = AvaloniaLocator.Current.GetService<ICursorFactory>();
using var handler = new Handler(platform, window.Handle, cursorFactory); using var handler = new Handler(platform, window.Handle, dataTransfer.ToAsynchronous(), allowedEffects, cursorFactory);
await handler.Completion; await handler.Completion;
return DragDropEffects.None; return DragDropEffects.None;
@ -39,21 +41,30 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
{ {
private readonly AvaloniaX11Platform _platform; private readonly AvaloniaX11Platform _platform;
private readonly IntPtr _sourceWindow; private readonly IntPtr _sourceWindow;
private readonly TaskCompletionSource _completionSource = new(); private readonly IAsyncDataTransfer _dataTransfer;
private readonly X11EventDispatcher.EventHandler? _originalEventHandler; private readonly DragDropEffects _allowedEffects;
private readonly TaskCompletionSource<DragDropEffects> _completionSource = new();
private X11EventDispatcher.EventHandler? _originalEventHandler;
private bool _pointerGrabbed;
private XdndTargetInfo? _lastTarget; private XdndTargetInfo? _lastTarget;
private DragDropDataProvider? _dataProvider;
public Task Completion private IntPtr _lastStatusAction;
=> _completionSource.Task;
public Handler(
public Handler(AvaloniaX11Platform platform, IntPtr sourceWindow, ICursorFactory? cursorFactory) AvaloniaX11Platform platform,
IntPtr sourceWindow,
IAsyncDataTransfer dataTransfer,
DragDropEffects allowedEffects,
ICursorFactory? cursorFactory)
{ {
_platform = platform; _platform = platform;
_sourceWindow = sourceWindow; _sourceWindow = sourceWindow;
_dataTransfer = dataTransfer;
_allowedEffects = allowedEffects;
if (!platform.Windows.TryGetValue(sourceWindow, out _originalEventHandler)) if (!platform.Windows.TryGetValue(sourceWindow, out _originalEventHandler))
{ {
_completionSource.TrySetResult(); _completionSource.TrySetResult(DragDropEffects.None);
return; return;
} }
@ -80,37 +91,167 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
{ {
Console.WriteLine($"Could not grab: {grabResult}"); Console.WriteLine($"Could not grab: {grabResult}");
_completionSource.TrySetResult(); _completionSource.TrySetResult(DragDropEffects.None);
return; return;
} }
Console.WriteLine("Grabbed!"); Console.WriteLine("Grabbed!");
_pointerGrabbed = true;
_platform.Windows[_sourceWindow] = OnEvent; _platform.Windows[_sourceWindow] = OnEvent;
} }
public Task<DragDropEffects> Completion
=> _completionSource.Task;
private IntPtr[] DataFormatAtoms
{
get
{
return field ??= CalcDataFormatAtoms();
IntPtr[] CalcDataFormatAtoms()
{
var atomValues = new List<IntPtr>(_dataTransfer.Formats.Count);
foreach (var format in _dataTransfer.Formats)
{
foreach (var atom in DataFormatHelper.ToAtoms(format, _platform.Info.Atoms))
atomValues.Add(atom);
}
return atomValues.ToArray();
}
}
}
private DragDropDataProvider DataProvider
{
get
{
return _dataProvider ??= CreateDataProvider();
DragDropDataProvider CreateDataProvider()
{
var dataProvider = new DragDropDataProvider(_platform, _dataTransfer);
var formats = DataFormatAtoms;
XChangeProperty(
_platform.Display,
dataProvider.Window,
_platform.Info.Atoms.XdndTypeList,
_platform.Info.Atoms.ATOM,
32,
PropertyMode.Replace,
formats,
formats.Length);
return dataProvider;
}
}
}
private void OnEvent(ref XEvent xev) private void OnEvent(ref XEvent xev)
{ {
Console.WriteLine($"Event on drag window: {xev.type}"); if (xev.type == XEventName.MotionNotify && _pointerGrabbed)
OnMotionNotify(in xev.MotionEvent);
else if (xev.type == XEventName.ButtonRelease && _pointerGrabbed)
OnButtonRelease(in xev.ButtonEvent);
else if (xev.type == XEventName.ClientMessage)
{
ref var message = ref xev.ClientMessageEvent;
var atoms = _platform.Info.Atoms;
if (message.message_type == atoms.XdndStatus)
OnXdndStatus(in message);
else if (message.message_type == atoms.XdndFinished)
OnXdndFinished(in message);
else
_originalEventHandler?.Invoke(ref xev);
}
else
_originalEventHandler?.Invoke(ref xev);
}
private void OnMotionNotify(in XMotionEvent motion)
{
var target = FindXdndTarget(motion.x_root, motion.y_root);
if (xev.type == XEventName.MotionNotify) if (_lastTarget != target)
{ {
var m = xev.MotionEvent; if (_lastTarget is { } lastTarget)
var target = FindXdndTarget(m.x_root, m.y_root); SendXdndLeave(lastTarget);
_lastTarget = target;
Console.WriteLine($"Motion on 0x{m.subwindow:x} at {m.x},{m.y} (root={m.x_root},{m.y_root}); XDND: win=0x{target?.MessageWindow:x}; version={target?.Version}"); if (target is { } newTarget)
SendXdndEnter(newTarget);
} }
else if (xev.type == XEventName.ButtonRelease) if (target is { } currentTarget)
{ {
Console.WriteLine("Completing"); var action = XdndActionHelper.EffectsToAction(_allowedEffects, _platform.Info.Atoms);
_completionSource.TrySetResult(); SendXdndPosition(currentTarget, motion.x_root, motion.y_root, motion.time, action);
}
Console.WriteLine($"Motion on 0x{motion.subwindow:x} at {motion.x},{motion.y} (root={motion.x_root},{motion.y_root}); XDND: win=0x{target?.MessageWindow:x}; version={target?.Version}");
}
private void OnButtonRelease(in XButtonEvent button)
{
UngrabPointer();
if (_lastTarget is { } lastTarget)
SendXdndDrop(lastTarget, button.time);
}
private void OnXdndStatus(in XClientMessageEvent message)
{
Console.WriteLine("Received XdndStatus");
if (_lastTarget is null)
return;
var targetWindow = message.ptr1;
if (targetWindow == 0 || targetWindow != _dataProvider?.Window)
return;
var accepted = (message.ptr2 & 1) == 1;
_lastStatusAction = accepted ? message.ptr5 : 0;
Console.WriteLine($"Status updated: {XdndActionHelper.ActionToEffects(_lastStatusAction, _platform.Info.Atoms)}");
}
private void OnXdndFinished(in XClientMessageEvent message)
{
Console.WriteLine("Received XdndFinished");
if (_lastTarget is not { } lastTarget)
return;
var targetWindow = message.ptr1;
if (targetWindow == 0 || targetWindow != _dataProvider?.Window)
return;
_lastTarget = null;
IntPtr action;
if (lastTarget.Version >= 5)
{
var accepted = (message.ptr2 & 1) == 1;
action = accepted ? message.ptr3 : 0;
} }
else else
_originalEventHandler!(ref xev); action = _lastStatusAction;
var effects = XdndActionHelper.ActionToEffects(action, _platform.Info.Atoms);
_completionSource.TrySetResult(effects);
} }
private XdndTargetInfo? FindXdndTarget(int rootX, int rootY) private XdndTargetInfo? FindXdndTarget(int x, int y)
{ {
var display = _platform.Display; var display = _platform.Display;
var rootWindow = _platform.Info.RootWindow; var rootWindow = _platform.Info.RootWindow;
@ -121,7 +262,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
if (TryGetXdndTargetInfo(currentWindow) is { } info) if (TryGetXdndTargetInfo(currentWindow) is { } info)
return info; return info;
if (!XTranslateCoordinates(display, rootWindow, currentWindow, rootX, rootY, out _, out _, out var childWindow)) if (!XTranslateCoordinates(display, rootWindow, currentWindow, x, y, out _, out _, out var childWindow))
return null; return null;
currentWindow = childWindow; currentWindow = childWindow;
@ -162,13 +303,80 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
var atoms = _platform.Info.Atoms; var atoms = _platform.Info.Atoms;
var version = XGetWindowPropertyAsIntPtr(_platform.Display, window, atoms.XdndAware, atoms.ATOM) ?? 0; var version = XGetWindowPropertyAsIntPtr(_platform.Display, window, atoms.XdndAware, atoms.ATOM) ?? 0;
if (version is < XdndConstants.MinXdndVersion or > byte.MaxValue) if (version is < MinXdndVersion or > byte.MaxValue)
version = 0; version = 0;
return (byte)version; return (byte)version;
} }
private void SendXdndEnter(XdndTargetInfo target) private void SendXdndEnter(XdndTargetInfo target)
{
Console.WriteLine("Sending XdndEnter");
var version = Math.Min(target.Version, XdndVersion);
var formats = DataFormatAtoms;
var hasMoreFormats = formats.Length > 3;
SendXdndMessage(
_platform.Info.Atoms.XdndEnter,
target,
DataProvider.Window,
(version << 24) | (hasMoreFormats ? 1 : 0),
formats.Length >= 1 ? formats[0] : 0,
formats.Length >= 2 ? formats[1] : 0,
formats.Length >= 3 ? formats[2] : 0);
}
private void SendXdndPosition(XdndTargetInfo target, int x, int y, IntPtr timestamp, IntPtr action)
{
Console.WriteLine("Sending XdndPosition");
SendXdndMessage(
_platform.Info.Atoms.XdndPosition,
target,
DataProvider.Window,
0,
(x << 16) | y,
timestamp,
action);
}
private void SendXdndLeave(XdndTargetInfo target)
{
Console.WriteLine("Sending XdndLeave");
SendXdndMessage(
_platform.Info.Atoms.XdndLeave,
target,
DataProvider.Window,
0,
0,
0,
0);
}
private void SendXdndDrop(XdndTargetInfo target, IntPtr timestamp)
{
Console.WriteLine("Sending XdndDrop");
SendXdndMessage(
_platform.Info.Atoms.XdndDrop,
target,
DataProvider.Window,
0,
timestamp,
0,
0);
}
private void SendXdndMessage(
IntPtr messageType,
XdndTargetInfo target,
IntPtr sourceWindow,
IntPtr ptr2,
IntPtr ptr3,
IntPtr ptr4,
IntPtr ptr5)
{ {
var evt = new XEvent var evt = new XEvent
{ {
@ -177,13 +385,13 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
type = XEventName.ClientMessage, type = XEventName.ClientMessage,
display = _platform.Display, display = _platform.Display,
window = target.MessageWindow, window = target.MessageWindow,
message_type = _platform.Info.Atoms.XdndEnter, message_type = messageType,
format = 32, format = 32,
ptr1 = target.TargetWindow, ptr1 = sourceWindow,
ptr2 = 0, ptr2 = ptr2,
ptr3 = 0, ptr3 = ptr3,
ptr4 = 0, ptr4 = ptr4,
ptr5 = 0 ptr5 = ptr5
} }
}; };
@ -191,19 +399,35 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
XFlush(_platform.Display); XFlush(_platform.Display);
} }
public void Dispose() private void UngrabPointer()
{ {
_pointerGrabbed = false;
XUngrabPointer(_platform.Display, 0); XUngrabPointer(_platform.Display, 0);
XFlush(_platform.Display);
}
public void Dispose()
{
if (_pointerGrabbed)
UngrabPointer();
if (_originalEventHandler is not null && _platform.Windows.ContainsKey(_sourceWindow)) if (_originalEventHandler is not null && _platform.Windows.ContainsKey(_sourceWindow))
{
_platform.Windows[_sourceWindow] = _originalEventHandler; _platform.Windows[_sourceWindow] = _originalEventHandler;
} _originalEventHandler = null;
}
private readonly struct XdndTargetInfo(byte version, IntPtr targetWindow, IntPtr messageWindow) _lastTarget = null;
{ _lastStatusAction = 0;
public readonly byte Version = version;
public readonly IntPtr TargetWindow = targetWindow; _dataProvider?.Dispose();
public readonly IntPtr MessageWindow = messageWindow; _dataProvider = null;
} }
private readonly record struct XdndTargetInfo(
byte Version,
IntPtr TargetWindow,
IntPtr MessageWindow);
} }
} }

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

@ -96,7 +96,7 @@ internal sealed class X11DropTarget
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 = ActionToEffects(message.ptr5); var requestedEffects = XdndActionHelper.ActionToEffects(message.ptr5, _atoms);
var eventType = _currentDrag.LastPosition is null ? RawDragEventType.DragEnter : RawDragEventType.DragOver; var eventType = _currentDrag.LastPosition is null ? RawDragEventType.DragEnter : RawDragEventType.DragOver;
_currentDrag.LastPosition = position; _currentDrag.LastPosition = position;
@ -113,7 +113,7 @@ internal sealed class X11DropTarget
_dragDropDevice.ProcessRawEvent(dragEnter); _dragDropDevice.ProcessRawEvent(dragEnter);
var resultAction = EffectsToAction(dragEnter.Effects); var resultAction = XdndActionHelper.EffectsToAction(dragEnter.Effects, _atoms);
var evt = new XEvent var evt = new XEvent
{ {
@ -182,28 +182,6 @@ internal sealed class X11DropTarget
DisposeCurrentDrag(); DisposeCurrentDrag();
} }
private DragDropEffects ActionToEffects(IntPtr action)
{
if (action == _atoms.XdndActionCopy)
return DragDropEffects.Copy;
if (action == _atoms.XdndActionMove)
return DragDropEffects.Move;
if (action == _atoms.XdndActionLink)
return DragDropEffects.Link;
return DragDropEffects.None;
}
private IntPtr EffectsToAction(DragDropEffects effects)
{
if ((effects & DragDropEffects.Copy) != 0)
return _atoms.XdndActionCopy;
if ((effects & DragDropEffects.Move) != 0)
return _atoms.XdndActionMove;
if ((effects & DragDropEffects.Link) != 0)
return _atoms.XdndActionLink;
return 0;
}
private void DisposeCurrentDrag() private void DisposeCurrentDrag()
{ {
_currentDrag?.Dispose(); _currentDrag?.Dispose();

29
src/Avalonia.X11/Selections/DragDrop/XdndActionHelper.cs

@ -0,0 +1,29 @@
using System;
using Avalonia.Input;
namespace Avalonia.X11.Selections.DragDrop;
internal static class XdndActionHelper
{
public static DragDropEffects ActionToEffects(IntPtr action, X11Atoms atoms)
{
if (action == atoms.XdndActionCopy)
return DragDropEffects.Copy;
if (action == atoms.XdndActionMove)
return DragDropEffects.Move;
if (action == atoms.XdndActionLink)
return DragDropEffects.Link;
return DragDropEffects.None;
}
public static IntPtr EffectsToAction(DragDropEffects effects, X11Atoms atoms)
{
if ((effects & DragDropEffects.Copy) != 0)
return atoms.XdndActionCopy;
if ((effects & DragDropEffects.Move) != 0)
return atoms.XdndActionMove;
if ((effects & DragDropEffects.Link) != 0)
return atoms.XdndActionLink;
return 0;
}
}

16
src/Avalonia.X11/Selections/SelectionDataProvider.cs

@ -18,13 +18,13 @@ internal abstract class SelectionDataProvider : IDisposable
{ {
private readonly int _maximumPropertySize; private readonly int _maximumPropertySize;
protected AvaloniaX11Platform Platform { get; } public AvaloniaX11Platform Platform { get; }
protected IntPtr Selection { get; } public IntPtr Selection { get; }
protected IntPtr Handle { get; private set; } public IntPtr Window { get; private set; }
public IAsyncDataTransfer? DataTransfer { get; set; } public IAsyncDataTransfer? DataTransfer { get; protected set; }
protected SelectionDataProvider(AvaloniaX11Platform platform, IntPtr selection) protected SelectionDataProvider(AvaloniaX11Platform platform, IntPtr selection)
{ {
@ -37,7 +37,7 @@ internal abstract class SelectionDataProvider : IDisposable
_maximumPropertySize = (int)Math.Min(0x100000, maxRequestSize - 0x100); _maximumPropertySize = (int)Math.Min(0x100000, maxRequestSize - 0x100);
Handle = CreateEventWindow(platform, OnEvent); Window = CreateEventWindow(platform, OnEvent);
} }
protected IntPtr GetOwner() protected IntPtr GetOwner()
@ -269,10 +269,10 @@ internal abstract class SelectionDataProvider : IDisposable
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (Handle == 0) if (Window == 0)
return; return;
XDestroyWindow(Platform.Display, Handle); XDestroyWindow(Platform.Display, Window);
Handle = 0; Window = 0;
} }
} }

Loading…
Cancel
Save