Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

macos - Dropping promised files on to application icon in Dock

Is it possible to open promised files NSFilesPromisePboardType in sandboxed application when dropping on to application icon in Dock? The Dock icon is accepting the drop, but -application:openFile: is never called.

The only reference I found are pre sandbox: Accepting iCal events dropped on my application's icon

rdar://47917787

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Let's break this down: NSApplication and NSDocumentController in NSDocument based apps gives you -application:openFile: or -openDocumentWithContentsOfURL:display:completionHandler: for free in case of NSFilenamesPboardType and NSURLPboardType drops.

Note: I think under the hood this is implement with the NSAppleEventManager event handlers for kCoreEventClass/kAEOpenDocuments and kInternetEventClass/kAEGetURL.

Unfortunately they don't handle NSFilesPromisePboardType.

Lets refresh our pasteboard knowledge: The pasteboard is shared amongst all application. There are default pasteboards for tasks like copy, find, and drag.

When the drag starts the application writes into the shared drag pasteboard. So all we need now is notification about the drop onto Dock icon.

This is where NSService comes into play:

<key>NSServices</key>
<array>
    <dict>
        <key>NSMessage</key>
        <string>openService</string>
        <key>NSSendTypes</key>
        <array>
            <string>public.data</string>
        </array>
        <key>NSMenuItem</key>
        <dict>
            <key>default</key>
            <string>Open</string>
        </dict>
    </dict>
</array>

And set it up in code:

- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
    [NSApp setServicesProvider:self];
}

- (void)openService:(NSPasteboard *)serviceBoard
           userData:(NSString *)userData
              error:(NSString **)error
{
}

One caveat is that the NSService pasteboard is not the NSDragPboard pasteboard.

But they are all shared, so we can just access the one we want:

NSPasteboard *dragPboard = [NSPasteboard pasteboardWithName:NSDragPboard];

if ([[dragPboard types] containsObject:NSFilesPromisePboardType])
{
}

The next problem is that we don't have -[NSDraggingInfo namesOfPromisedFilesDroppedAtDestination:].

#import <ApplicationServices/ApplicationServices.h>

Good old Carbon got us covered.

    PasteboardRef pboardRef = NULL;
    PasteboardCreate((__bridge CFStringRef)NSDragPboard, &pboardRef);
    PasteboardSetPasteLocation(pboardRef, (__bridge CFURLRef)temporaryDirectory);

    NSString *urlString = [dragPboard stringForType:(NSString *)kPasteboardTypeFileURLPromise];

    CFRelease(pboardRef);

Handle like any other promise file from here on.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...