2
votes

I'm trying to kick off a drag in my Mac app. I want the drag to offer both a native UTI, and also a file promise, so that the user can drag a clipping to the desktop.

According to Apple's obsolete documentation, the way to achieve this is:

  1. Kick off the "promise" drag with dragPromisedFilesOfTypes:fromRect:source:slideBack:event:

  2. Add additional pasteboard types by overriding dragImage:at:offset:event:pasteboard:source:slideBack:

The problem with this is that Apple has since replaced AppKit's dragImage: method with beginDraggingSession: ...and dragPromisedFilesOfTypes: does not appear to call it.

What's the best way to go about this now?

1

1 Answers

1
votes

So it looks like you have to set up the promise yourself. For example:

    let writer = NSPasteboardItem()

    // We can provide "MP3" data, and/or a "File promise"
    writer.setDataProvider(
        data_source,
        forTypes: [ kUTTypeMP3, kPasteboardTypeFileURLPromise]
    )

    // If the receiver wants the "File promise", we'll 
    // be writing a "CAF file" for them
    writer.setString( AVFileTypeCoreAudioFormat, forType: kPasteboardTypeFilePromiseContent ) 

    let drag_item = NSDraggingItem( pasteboardWriter: writer )

    let drag_session = self.beginDraggingSession( with: [drag_item], event: event, source: self )

In this example, I set up a normal drag that can provide an MP3 immediately, or a promise for a CAF file.

By kicking off the drag in such a manner, "namesOfPromisedFilesDropped:" gets called, just as it would with "dragPromisedFilesOfTypes:" but we also have the ability to set non-promise content.


Edit: Thanks to jnadeau for pointing out that macOS 10.12 adds "NSFilePromiseProvider" which is probably simpler. I need to support 10.10 and 10.11, but I mention this in case someone else finds it useful.