From eb440387490abbaca03dbee9b5fada248146dcfd Mon Sep 17 00:00:00 2001 From: StarHack Date: Sat, 25 Feb 2023 12:44:16 +0100 Subject: [PATCH] darwin-external-dragndrop: implement external drag n' drop for darwin --- app/os_macos.go | 21 +++++++++++++++++++++ app/os_macos.m | 15 +++++++++++++++ io/router/pointer.go | 4 ++-- io/router/router.go | 13 +++++++++++++ io/transfer/transfer.go | 2 +- 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/app/os_macos.go b/app/os_macos.go index 516157aaa..51f0bc2ba 100644 --- a/app/os_macos.go +++ b/app/os_macos.go @@ -8,6 +8,10 @@ package app import ( "errors" "image" + "io" + "mime" + "os" + "path/filepath" "runtime" "time" "unicode" @@ -18,6 +22,7 @@ import ( "gioui.org/io/key" "gioui.org/io/pointer" "gioui.org/io/system" + "gioui.org/io/transfer" "gioui.org/unit" _ "gioui.org/internal/cocoainit" @@ -557,6 +562,22 @@ func gio_onMouse(view, evt C.CFTypeRef, cdir C.int, cbtn C.NSInteger, x, y, dx, }) } +//export gio_onExternalDrop +func gio_onExternalDrop(view C.CFTypeRef, path *C.char) { + fileUrl := C.GoString(path) + w := mustView(view) + + fileExtension := filepath.Ext(fileUrl) + mime := mime.TypeByExtension(fileExtension) + + w.w.Event(transfer.DataEvent{ + Type: mime, + Open: func() (io.ReadCloser, error) { + return os.Open(fileUrl) + }, + }) +} + //export gio_onDraw func gio_onDraw(view C.CFTypeRef) { w := mustView(view) diff --git a/app/os_macos.m b/app/os_macos.m index 49964fbf1..dc62b5eaf 100644 --- a/app/os_macos.m +++ b/app/os_macos.m @@ -110,6 +110,20 @@ - (void)mouseMoved:(NSEvent *)event { - (void)mouseDragged:(NSEvent *)event { handleMouse(self, event, MOUSE_MOVE, 0, 0); } +-(NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender +{ + return NSDragOperationCopy; +} +- (void)draggingEnded:(id )sender +{ + NSPasteboard* pbrd = [sender draggingPasteboard]; + NSArray* droppedFiles = [pbrd propertyListForType:NSFilenamesPboardType]; + + for (NSString* filePath in droppedFiles) { + NSURL* url = [NSURL fileURLWithPath:filePath]; + gio_onExternalDrop((__bridge CFTypeRef)self, (char*)[[url path] UTF8String]); + } +} - (void)scrollWheel:(NSEvent *)event { CGFloat dx = -event.scrollingDeltaX; CGFloat dy = -event.scrollingDeltaY; @@ -366,6 +380,7 @@ CFTypeRef gio_createView(void) { @autoreleasepool { NSRect frame = NSMakeRect(0, 0, 0, 0); GioView* view = [[GioView alloc] initWithFrame:frame]; + [view registerForDraggedTypes: [NSArray arrayWithObjects:NSTIFFPboardType, NSFilenamesPboardType, nil]]; view.wantsLayer = YES; view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize; return CFBridgingRetain(view); diff --git a/io/router/pointer.go b/io/router/pointer.go index e95bc6e7a..4e8e8c294 100644 --- a/io/router/pointer.go +++ b/io/router/pointer.go @@ -858,9 +858,9 @@ func (q *pointerQueue) deliverTransferDataEvent(p *pointerInfo, events *handlerE transferIdx := len(q.transfers) events.Add(p.dataTarget, transfer.DataEvent{ Type: src.offeredMime, - Open: func() io.ReadCloser { + Open: func() (io.ReadCloser, error) { q.transfers[transferIdx] = nil - return src.data + return src.data, nil }, }) q.transfers = append(q.transfers, src.data) diff --git a/io/router/router.go b/io/router/router.go index e3b3be8d9..bc69aea95 100644 --- a/io/router/router.go +++ b/io/router/router.go @@ -182,6 +182,19 @@ func (q *Router) Queue(events ...event.Event) bool { } case clipboard.Event: q.cqueue.Push(e, &q.handlers) + case transfer.DataEvent: + pq := &q.pointer.queue + for _, h := range pq.hitTree { + if h.tag != nil { + targetMimes := pq.handlers[h.tag].targetMimes + for _, mimeType := range targetMimes { + if mimeType == e.Type { + q.handlers.Add(h.tag, e) + break + } + } + } + } } } return q.handlers.HadEvents() diff --git a/io/transfer/transfer.go b/io/transfer/transfer.go index 78e2b9005..2ec700c7c 100644 --- a/io/transfer/transfer.go +++ b/io/transfer/transfer.go @@ -103,7 +103,7 @@ type DataEvent struct { Type string // Open returns the transfer data. It is only valid to call Open in the frame // the DataEvent is received. The caller must close the return value after use. - Open func() io.ReadCloser + Open func() (io.ReadCloser, error) } func (DataEvent) ImplementsEvent() {}