Jelajahi Sumber

[OSX] Move Drag and Drop logic to TopLevelImpl (#19731)

* Move Drag and Drop logic to TopLevelImpl

* Update src/Avalonia.Native/TopLevelImpl.cs

Co-authored-by: Max Katz <[email protected]>

---------

Co-authored-by: Max Katz <[email protected]>
Co-authored-by: Benedikt Stebner <[email protected]>
Tim Miller 2 minggu lalu
induk
melakukan
650aeb20c6

+ 3 - 0
native/Avalonia.Native/src/OSX/TopLevelImpl.h

@@ -60,6 +60,9 @@ public:
     virtual HRESULT SetTransparencyMode(AvnWindowTransparencyMode mode) override;
 
     virtual HRESULT GetCurrentDisplayId (CGDirectDisplayID* ret) override;
+
+    virtual HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point,
+                                             IAvnClipboard* clipboard, IAvnDndResultCallback* cb, void* sourceHandle) override;
 protected:
     NSCursor *cursor;
     virtual void UpdateAppearance();

+ 49 - 0
native/Avalonia.Native/src/OSX/TopLevelImpl.mm

@@ -6,6 +6,7 @@
 #include "TopLevelImpl.h"
 #include "AvnTextInputMethod.h"
 #include "AvnView.h"
+#include "common.h"
 
 TopLevelImpl::~TopLevelImpl() {
     View = nullptr;
@@ -271,6 +272,54 @@ void TopLevelImpl::UpdateAppearance() {
     
 }
 
+HRESULT TopLevelImpl::BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point, IAvnClipboard *clipboard, IAvnDndResultCallback *cb, void *sourceHandle) {
+    START_COM_CALL;
+
+    auto item = TryGetPasteboardItem(clipboard);
+    [item setString:@"" forType:GetAvnCustomDataType()];
+    if (item == nil)
+        return E_INVALIDARG;
+    if (View == NULL)
+        return E_FAIL;
+
+    auto nsevent = [NSApp currentEvent];
+    auto nseventType = [nsevent type];
+
+    // If current event isn't a mouse one (probably due to malfunctioning user app)
+    // attempt to forge a new one
+    if (!((nseventType >= NSEventTypeLeftMouseDown && nseventType <= NSEventTypeMouseExited)
+            || (nseventType >= NSEventTypeOtherMouseDown && nseventType <= NSEventTypeOtherMouseDragged))) {
+        // For TopLevelImpl, we don't have a Window so we use the View's window
+        auto window = [View window];
+        if (window != nil) {
+            NSRect convertRect = [window convertRectToScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)];
+            auto nspoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y);
+            CGPoint cgpoint = NSPointToCGPoint(nspoint);
+            auto cgevent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, cgpoint, kCGMouseButtonLeft);
+            nsevent = [NSEvent eventWithCGEvent:cgevent];
+            CFRelease(cgevent);
+        }
+    }
+
+    auto dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:item];
+
+    auto dragItemImage = [NSImage imageNamed:NSImageNameMultipleDocuments];
+    NSRect dragItemRect = {(float) point.X, (float) point.Y, [dragItemImage size].width, [dragItemImage size].height};
+    [dragItem setDraggingFrame:dragItemRect contents:dragItemImage];
+
+    int op = 0;
+    int ieffects = (int) effects;
+    if ((ieffects & (int) AvnDragDropEffects::Copy) != 0)
+        op |= NSDragOperationCopy;
+    if ((ieffects & (int) AvnDragDropEffects::Link) != 0)
+        op |= NSDragOperationLink;
+    if ((ieffects & (int) AvnDragDropEffects::Move) != 0)
+        op |= NSDragOperationMove;
+    [View beginDraggingSessionWithItems:@[dragItem] event:nsevent
+                                 source:CreateDraggingSource((NSDragOperation) op, cb, sourceHandle)];
+    return S_OK;
+}
+
 void TopLevelImpl::SetClientSize(NSSize size){
     [View setFrameSize:size];
 }

+ 0 - 4
native/Avalonia.Native/src/OSX/WindowBaseImpl.h

@@ -69,10 +69,6 @@ public:
 
     virtual HRESULT SetFrameThemeVariant(AvnPlatformThemeVariant variant) override;
 
-    virtual HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point,
-            IAvnClipboard *clipboard, IAvnDndResultCallback *cb,
-            void *sourceHandle) override;
-
     virtual HRESULT SetTransparencyMode(AvnWindowTransparencyMode mode) override;
                            
     virtual bool IsModal();

+ 0 - 44
native/Avalonia.Native/src/OSX/WindowBaseImpl.mm

@@ -411,50 +411,6 @@ HRESULT WindowBaseImpl::SetFrameThemeVariant(AvnPlatformThemeVariant variant) {
     return S_OK;
 }
 
-HRESULT WindowBaseImpl::BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point, IAvnClipboard *clipboard, IAvnDndResultCallback *cb, void *sourceHandle) {
-    START_COM_CALL;
-
-    auto item = TryGetPasteboardItem(clipboard);
-    [item setString:@"" forType:GetAvnCustomDataType()];
-    if (item == nil)
-        return E_INVALIDARG;
-    if (View == NULL)
-        return E_FAIL;
-
-    auto nsevent = [NSApp currentEvent];
-    auto nseventType = [nsevent type];
-
-    // If current event isn't a mouse one (probably due to malfunctioning user app)
-    // attempt to forge a new one
-    if (!((nseventType >= NSEventTypeLeftMouseDown && nseventType <= NSEventTypeMouseExited)
-            || (nseventType >= NSEventTypeOtherMouseDown && nseventType <= NSEventTypeOtherMouseDragged))) {
-        NSRect convertRect = [Window convertRectToScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)];
-        auto nspoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y);
-        CGPoint cgpoint = NSPointToCGPoint(nspoint);
-        auto cgevent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, cgpoint, kCGMouseButtonLeft);
-        nsevent = [NSEvent eventWithCGEvent:cgevent];
-        CFRelease(cgevent);
-    }
-
-    auto dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:item];
-
-    auto dragItemImage = [NSImage imageNamed:NSImageNameMultipleDocuments];
-    NSRect dragItemRect = {(float) point.X, (float) point.Y, [dragItemImage size].width, [dragItemImage size].height};
-    [dragItem setDraggingFrame:dragItemRect contents:dragItemImage];
-
-    int op = 0;
-    int ieffects = (int) effects;
-    if ((ieffects & (int) AvnDragDropEffects::Copy) != 0)
-        op |= NSDragOperationCopy;
-    if ((ieffects & (int) AvnDragDropEffects::Link) != 0)
-        op |= NSDragOperationLink;
-    if ((ieffects & (int) AvnDragDropEffects::Move) != 0)
-        op |= NSDragOperationMove;
-    [View beginDraggingSessionWithItems:@[dragItem] event:nsevent
-                                 source:CreateDraggingSource((NSDragOperation) op, cb, sourceHandle)];
-    return S_OK;
-}
-
 bool WindowBaseImpl::IsModal() {
     return false;
 }

+ 1 - 1
src/Avalonia.Native/AvaloniaNativeDragSource.cs

@@ -36,7 +36,7 @@ namespace Avalonia.Native
         {
             // Sanity check
             var tl = TopLevel.GetTopLevel(triggerEvent.Source as Visual);
-            var view = tl?.PlatformImpl as WindowBaseImpl;
+            var view = tl?.PlatformImpl as TopLevelImpl;
             if (view == null)
                 throw new ArgumentException();
 

+ 12 - 7
src/Avalonia.Native/TopLevelImpl.cs

@@ -52,7 +52,7 @@ internal class MacOSTopLevelHandle : IPlatformHandle, IMacOSTopLevelPlatformHand
     {
         return Native.ObtainNSViewHandleRetained();
     }
-    
+
     public IntPtr NSWindow => (Native as IAvnWindowBase)?.ObtainNSWindowHandle() ?? IntPtr.Zero;
 
     public IntPtr GetNSWindowRetained()
@@ -98,13 +98,18 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
     {
         _handle = handle;
         _savedLogicalSize = ClientSize;
-        _savedScaling = Native?.Scaling ?? 1;;
+        _savedScaling = Native?.Scaling ?? 1;
         _nativeControlHost = new NativeControlHostImpl(Native!.CreateNativeControlHost());
         _platformBehaviorInhibition = new PlatformBehaviorInhibition(Factory.CreatePlatformBehaviorInhibition());
         _surfaces = new object[] { new GlPlatformSurface(Native), new MetalPlatformSurface(Native), this };
         InputMethod = new AvaloniaNativeTextInputMethod(Native);
     }
 
+    internal void BeginDraggingSession(AvnDragDropEffects effects, AvnPoint point, IAvnClipboard clipboard, IAvnDndResultCallback callback, IntPtr sourceHandle)
+    {
+        Native?.BeginDragAndDropOperation(effects, point, clipboard, callback, sourceHandle);
+    }
+
     public double DesktopScaling => 1;
 
     public IAvnTopLevel? Native => _handle?.Native;
@@ -118,7 +123,7 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
             {
                 return default;
             }
-            
+
             var s = Native.ClientSize;
             return new Size(s.Width, s.Height);
 
@@ -135,7 +140,7 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
     public Compositor Compositor => AvaloniaNativePlatform.Compositor;
     public Action? Closed { get; set; }
     public Action? LostFocus { get; set; }
-    
+
     public WindowTransparencyLevel TransparencyLevel
     {
         get => _transparencyLevel;
@@ -397,7 +402,7 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
         {
             throw new RenderTargetNotReadyException();
         }
-        
+
         return new FramebufferRenderTarget(this, nativeRenderTarget);
     }
 
@@ -439,7 +444,7 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
             {
                 return;
             }
-            
+
             var s = new Size(size->Width, size->Height);
             _parent._savedLogicalSize = s;
             _parent.Resized?.Invoke(s, (WindowResizeReason)reason);
@@ -492,7 +497,7 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
             {
                 return AvnDragDropEffects.None;
             }
-            
+
             IDataObject? dataObject = null;
             if (dataObjectHandle != IntPtr.Zero)
                 dataObject = GCHandle.FromIntPtr(dataObjectHandle).Target as IDataObject;

+ 0 - 6
src/Avalonia.Native/WindowImplBase.cs

@@ -116,12 +116,6 @@ namespace Avalonia.Native
             Native?.SetMinMaxSize(minSize.ToAvnSize(), maxSize.ToAvnSize());
         }
 
-        internal void BeginDraggingSession(AvnDragDropEffects effects, AvnPoint point, IAvnClipboard clipboard,
-            IAvnDndResultCallback callback, IntPtr sourceHandle)
-        {
-            Native?.BeginDragAndDropOperation(effects, point, clipboard, callback, sourceHandle);
-        }
-
         protected class WindowBaseEvents : TopLevelEvents, IAvnWindowBaseEvents
         {
             private readonly WindowBaseImpl _parent;

+ 3 - 2
src/Avalonia.Native/avn.idl

@@ -735,6 +735,9 @@ interface IAvnTopLevel : IUnknown
      HRESULT SetTransparencyMode(AvnWindowTransparencyMode mode);
      
      HRESULT GetCurrentDisplayId(uint* ret);
+
+     HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point,
+                                              IAvnClipboard* clipboard, IAvnDndResultCallback* cb, [intptr]void* sourceHandle);
 }
 
 [uuid(e5aca675-02b7-4129-aa79-d6e417210bda), cpp-virtual-inherits]
@@ -757,8 +760,6 @@ interface IAvnWindowBase : IAvnTopLevel
      HRESULT SetMainMenu(IAvnMenu* menu);
      HRESULT ObtainNSWindowHandle([intptr]void** retOut);
      HRESULT ObtainNSWindowHandleRetained([intptr]void** retOut);
-     HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point,
-                                              IAvnClipboard* clipboard, IAvnDndResultCallback* cb, [intptr]void* sourceHandle);
 }
 
 [uuid(83e588f3-6981-4e48-9ea0-e1e569f79a91), cpp-virtual-inherits]