using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Runtime.InteropServices; using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Native.Interop; using Avalonia.Platform.Interop; namespace Avalonia.Native { class ClipboardImpl : IClipboard, IDisposable { private IAvnClipboard _native; private const string NSPasteboardTypeString = "public.utf8-plain-text"; private const string NSFilenamesPboardType = "NSFilenamesPboardType"; private const string NSPasteboardTypeFileUrl = "public.file-url"; public ClipboardImpl(IAvnClipboard native) { _native = native; } public Task ClearAsync() { _native.Clear(); return Task.CompletedTask; } public Task GetTextAsync() { using (var text = _native.GetText(NSPasteboardTypeString)) return Task.FromResult(text.String); } public unsafe Task SetTextAsync(string text) { _native.Clear(); if (text != null) _native.SetText(NSPasteboardTypeString, text); return Task.CompletedTask; } public IEnumerable GetFormats() { var rv = new List(); using (var formats = _native.ObtainFormats()) { var cnt = formats.Count; for (uint c = 0; c < cnt; c++) { using (var fmt = formats.Get(c)) { if(fmt.String == NSPasteboardTypeString) rv.Add(DataFormats.Text); if(fmt.String == NSFilenamesPboardType) rv.Add(DataFormats.FileNames); } } } return rv; } public void Dispose() { _native?.Dispose(); _native = null; } public IEnumerable GetFileNames() { using (var strings = _native.GetStrings(NSFilenamesPboardType)) return strings.ToStringArray(); } public unsafe Task SetDataObjectAsync(IDataObject data) { _native.Clear(); foreach (var fmt in data.GetDataFormats()) { var o = data.Get(fmt); if(o is string s) _native.SetText(fmt, s); else if(o is byte[] bytes) fixed (byte* pbytes = bytes) _native.SetBytes(fmt, pbytes, bytes.Length); } return Task.CompletedTask; } public Task GetFormatsAsync() { using (var n = _native.ObtainFormats()) return Task.FromResult(n.ToStringArray()); } public async Task GetDataAsync(string format) { if (format == DataFormats.Text) return await GetTextAsync(); if (format == DataFormats.FileNames) return GetFileNames(); using (var n = _native.GetBytes(format)) return n.Bytes; } } class ClipboardDataObject : IDataObject, IDisposable { private ClipboardImpl _clipboard; private List _formats; public ClipboardDataObject(IAvnClipboard clipboard) { _clipboard = new ClipboardImpl(clipboard); } public void Dispose() { _clipboard?.Dispose(); _clipboard = null; } List Formats => _formats ??= _clipboard.GetFormats().ToList(); public IEnumerable GetDataFormats() => Formats; public bool Contains(string dataFormat) => Formats.Contains(dataFormat); public string GetText() { // bad idea in general, but API is synchronous anyway return _clipboard.GetTextAsync().Result; } public IEnumerable GetFileNames() => _clipboard.GetFileNames(); public object Get(string dataFormat) { if (dataFormat == DataFormats.Text) return GetText(); if (dataFormat == DataFormats.FileNames) return GetFileNames(); return null; } } }