diff --git a/src/Avalonia.X11/X11Clipboard.cs b/src/Avalonia.X11/X11Clipboard.cs index 6e18151fae..637d44d617 100644 --- a/src/Avalonia.X11/X11Clipboard.cs +++ b/src/Avalonia.X11/X11Clipboard.cs @@ -14,6 +14,7 @@ namespace Avalonia.X11 private readonly X11Info _x11; private IDataObject _storedDataObject; private IntPtr _handle; + private TaskCompletionSource _storeAtomTcs; private TaskCompletionSource _requestedFormatsTcs; private TaskCompletionSource _requestedDataTcs; private readonly IntPtr[] _textAtoms; @@ -52,6 +53,12 @@ namespace Avalonia.X11 private unsafe void OnEvent(ref XEvent ev) { + if (ev.type == XEventName.SelectionClear) + { + _storeAtomTcs?.TrySetResult(true); + return; + } + if (ev.type == XEventName.SelectionRequest) { var sel = ev.SelectionRequestEvent; @@ -82,18 +89,9 @@ namespace Avalonia.X11 Encoding textEnc; if (target == _x11.Atoms.TARGETS) { - var atoms = new HashSet { _x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE }; - foreach (var fmt in _storedDataObject.GetDataFormats()) - { - if (fmt == DataFormats.Text) - foreach (var ta in _textAtoms) - atoms.Add(ta); - else - atoms.Add(_x11.Atoms.GetAtom(fmt)); - } - + var atoms = ConvertDataObject(_storedDataObject); XChangeProperty(_x11.Display, window, property, - _x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms.ToArray(), atoms.Count); + _x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms, atoms.Length); return property; } else if(target == _x11.Atoms.SAVE_TARGETS && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero) @@ -252,20 +250,41 @@ namespace Avalonia.X11 return (string)await SendDataRequest(target); } - private void StoreAtomsInClipboardManager(IntPtr[] atoms) + + private IntPtr[] ConvertDataObject(IDataObject data) + { + var atoms = new HashSet { _x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE }; + foreach (var fmt in data.GetDataFormats()) + { + if (fmt == DataFormats.Text) + foreach (var ta in _textAtoms) + atoms.Add(ta); + else + atoms.Add(_x11.Atoms.GetAtom(fmt)); + } + return atoms.ToArray(); + } + + private Task StoreAtomsInClipboardManager(IDataObject data) { if (_x11.Atoms.CLIPBOARD_MANAGER != IntPtr.Zero && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero) { var clipboardManager = XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER); if (clipboardManager != IntPtr.Zero) - { + { + if (_storeAtomTcs == null || _storeAtomTcs.Task.IsCompleted) + _storeAtomTcs = new TaskCompletionSource(); + + var atoms = ConvertDataObject(data); XChangeProperty(_x11.Display, _handle, _avaloniaSaveTargetsAtom, _x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms, atoms.Length); XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD_MANAGER, _x11.Atoms.SAVE_TARGETS, _avaloniaSaveTargetsAtom, _handle, IntPtr.Zero); + return _storeAtomTcs.Task; } } + return Task.CompletedTask; } public Task SetTextAsync(string text) @@ -283,9 +302,8 @@ namespace Avalonia.X11 public Task SetDataObjectAsync(IDataObject data) { _storedDataObject = data; - XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero); - StoreAtomsInClipboardManager(_textAtoms); - return Task.CompletedTask; + XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero); + return StoreAtomsInClipboardManager(data); } public async Task GetFormatsAsync()