csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
3.3 KiB
108 lines
3.3 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Avalonia.Input;
|
|
using Avalonia.Input.Platform;
|
|
using Avalonia.Media.Imaging;
|
|
using Avalonia.Platform.Storage;
|
|
|
|
namespace Avalonia.X11.Selections;
|
|
|
|
/// <summary>
|
|
/// An object used to read values, converted to the correct format, from an X11 selection (clipboard/drag-and-drop).
|
|
/// </summary>
|
|
internal abstract class SelectionDataReader<TItem>(
|
|
X11Atoms atoms,
|
|
IntPtr[] textFormatAtoms,
|
|
DataFormat[] dataFormats)
|
|
: IDisposable
|
|
where TItem : class
|
|
{
|
|
protected X11Atoms Atoms { get; } = atoms;
|
|
|
|
public async Task<TItem[]> CreateItemsAsync()
|
|
{
|
|
List<DataFormat>? nonFileFormats = null;
|
|
var items = new List<TItem>();
|
|
var hasFiles = false;
|
|
|
|
foreach (var format in dataFormats)
|
|
{
|
|
if (DataFormat.File.Equals(format))
|
|
{
|
|
if (hasFiles)
|
|
continue;
|
|
|
|
if (await TryGetAsync(format) is IEnumerable<IStorageItem> storageItems)
|
|
{
|
|
hasFiles = true;
|
|
|
|
foreach (var storageItem in storageItems)
|
|
items.Add((TItem)(object)PlatformDataTransferItem.Create(DataFormat.File, storageItem));
|
|
}
|
|
}
|
|
else
|
|
(nonFileFormats ??= []).Add(format);
|
|
}
|
|
|
|
// Single item containing all formats except for DataFormat.File.
|
|
if (nonFileFormats is not null)
|
|
items.Add(CreateSingleItem(nonFileFormats.ToArray()));
|
|
|
|
return items.ToArray();
|
|
}
|
|
|
|
public virtual async Task<object?> TryGetAsync(DataFormat format)
|
|
{
|
|
var formatAtom = DataFormatHelper.ToAtom(format, textFormatAtoms, Atoms, dataFormats);
|
|
if (formatAtom == IntPtr.Zero)
|
|
return null;
|
|
|
|
using var session = CreateReadSession();
|
|
var result = await session.SendDataRequest(formatAtom, 0).ConfigureAwait(false);
|
|
return ConvertDataResult(result, format, formatAtom);
|
|
}
|
|
|
|
protected abstract TItem CreateSingleItem(DataFormat[] nonFileFormats);
|
|
|
|
protected abstract SelectionReadSession CreateReadSession();
|
|
|
|
private object? ConvertDataResult(SelectionReadSession.GetDataResult? result, DataFormat format, IntPtr formatAtom)
|
|
{
|
|
if (result is null)
|
|
return null;
|
|
|
|
if (DataFormat.Text.Equals(format))
|
|
{
|
|
return DataFormatHelper.TryGetStringEncoding(result.TypeAtom, Atoms) is { } textEncoding ?
|
|
textEncoding.GetString(result.AsBytes()) :
|
|
null;
|
|
}
|
|
|
|
if (DataFormat.Bitmap.Equals(format))
|
|
{
|
|
using var data = result.AsStream();
|
|
|
|
return new Bitmap(data);
|
|
}
|
|
|
|
if (DataFormat.File.Equals(format))
|
|
{
|
|
// text/uri-list might not be supported
|
|
return formatAtom != IntPtr.Zero && result.TypeAtom == formatAtom ?
|
|
UriListHelper.Utf8BytesToFileUriList(result.AsBytes()) :
|
|
null;
|
|
}
|
|
|
|
if (format is DataFormat<string>)
|
|
return Encoding.UTF8.GetString(result.AsBytes());
|
|
|
|
if (format is DataFormat<byte[]>)
|
|
return result.AsBytes();
|
|
|
|
return null;
|
|
}
|
|
|
|
public abstract void Dispose();
|
|
}
|
|
|