From 1afb52b27d08ac10412f4945b09196f4a399c25a Mon Sep 17 00:00:00 2001 From: boombuler Date: Sun, 11 Mar 2018 16:18:39 +0100 Subject: [PATCH] OSX drag cleanup --- src/OSX/Avalonia.MonoMac/DragSource.cs | 96 ++++++++++++++++---------- 1 file changed, 61 insertions(+), 35 deletions(-) diff --git a/src/OSX/Avalonia.MonoMac/DragSource.cs b/src/OSX/Avalonia.MonoMac/DragSource.cs index ea1739e33a..77bbee86f1 100644 --- a/src/OSX/Avalonia.MonoMac/DragSource.cs +++ b/src/OSX/Avalonia.MonoMac/DragSource.cs @@ -1,13 +1,19 @@ -using System.Data; +using System; +using System.Data; +using System.IO; +using System.Linq; using System.Linq.Expressions; using System.Reactive.Linq; using System.Reactive.Subjects; +using System.Runtime.InteropServices; +using System.Runtime.Serialization.Formatters.Binary; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.DragDrop; using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Input.Raw; +using MonoMac; using MonoMac.AppKit; using MonoMac.CoreGraphics; using MonoMac.Foundation; @@ -17,46 +23,54 @@ namespace Avalonia.MonoMac { public class DragSource : NSDraggingSource, IPlatformDragSource { - class DS : NSDraggingSource - { - private readonly DragDropEffects _allowedEffects; - public ReplaySubject Result { get; } = new ReplaySubject(); - - public DS(DragDropEffects allowedEffects) - { - _allowedEffects = allowedEffects; - } - - public override bool IgnoreModifierKeysWhileDragging => false; - - public override NSDragOperation DraggingSourceOperationMaskForLocal(bool flag) - { - return DraggingInfo.ConvertDragOperation(_allowedEffects); - } - - public override void DraggedImageEndedAtOperation(NSImage image, CGPoint screenPoint, NSDragOperation operation) - { - Result.OnNext(DraggingInfo.ConvertDragOperation(operation)); - Result.OnCompleted(); - } - } - - + private const string NSPasteboardTypeString = "public.utf8-plain-text"; + private readonly Subject _result = new Subject(); private readonly IInputManager _inputManager; + private DragDropEffects _allowedEffects; - + public override bool IgnoreModifierKeysWhileDragging => false; + public DragSource() { _inputManager = AvaloniaLocator.Current.GetService(); } - private NSDraggingItem[] ConvertDraggedItems(IDataObject data) + private string DataFormatToUTI(string s) + { + if (s == DataFormats.FileNames) + throw new NotImplementedException(); + if (s == DataFormats.Text) + return NSPasteboardTypeString; + return s; + } + + private NSDraggingItem CreateDraggingItem(string format, object data) { - NSString s = new NSString("FOOBAR"); - NSPasteboardWriting w = new NSPasteboardWriting(s.Handle); - var text = new NSDraggingItem(w); - return new[] {text}; + + var pasteboardItem = new NSPasteboardItem(); + NSData nsData; + if(data is string s) + nsData = NSData.FromString(s); + else if (data is Stream strm) + nsData = NSData.FromStream(strm); + else if (data is byte[] bytes) + nsData = NSData.FromArray(bytes); + else + { + BinaryFormatter bf = new BinaryFormatter(); + using (var ms = new MemoryStream()) + { + bf.Serialize(ms, data); + ms.Position = 0; + nsData = NSData.FromStream(ms); + } + } + pasteboardItem.SetDataForType(nsData, DataFormatToUTI(format)); + + NSPasteboardWriting writing = new NSPasteboardWriting(pasteboardItem.Handle); + + return new NSDraggingItem(writing); } @@ -72,10 +86,22 @@ namespace Avalonia.MonoMac var pt = view.TranslateLocalPoint(mouseEv.Position).ToMonoMacPoint(); var ev = NSEvent.MouseEvent(NSEventType.LeftMouseDown, pt, 0, 0, 0, null, 0, 0, 0); - var ds = new DS(allowedEffects); - view.BeginDraggingSession(ConvertDraggedItems(data) ,ev, ds); + _allowedEffects = allowedEffects; + var items = data.GetDataFormats().Select(fmt => CreateDraggingItem(fmt, data.Get(fmt))).ToArray(); + view.BeginDraggingSession(items ,ev, this); - return await ds.Result; + return await _result; + } + + public override NSDragOperation DraggingSourceOperationMaskForLocal(bool flag) + { + return DraggingInfo.ConvertDragOperation(_allowedEffects); + } + + public override void DraggedImageEndedAtOperation(NSImage image, CGPoint screenPoint, NSDragOperation operation) + { + _result.OnNext(DraggingInfo.ConvertDragOperation(operation)); + _result.OnCompleted(); } } } \ No newline at end of file