Search code examples
macoscocoansapplescript

How can an app send a (basic) Apple Event to itself in Cocoa?


I thought I was so slick in rewriting my handler for the "Open" menu command in the application delegate:

- (IBAction)openDocument:(id)sender {
    NSOpenPanel * const  panel = [NSOpenPanel openPanel];

    panel.allowsMultipleSelection = YES;
    panel.delegate = self;
    [panel beginWithCompletionHandler:^(NSInteger result) {
        if (result == NSFileHandlingPanelOKButton) {
            NSMutableArray * const  paths = [NSMutableArray arrayWithCapacity:panel.URLs.count];

            for (NSURL *file in panel.URLs) {
                [paths addObject:file.path];
            }
            [self application:NSApp openFiles:paths];
        }
    }];
}

In the old code, looping through each file URL, I used to call my window creation code directly. Then I swapped out implementing the single-file -application:openFile: for its multi-file variant, and decided to reuse that code within -openDocument:.

I thought it was fine.

The single-file version return a BOOL indicating its success. For the multi-file version, you're supposed to call a special function of the application object.

I guess when you start up your app with some files, Cocoa's handler looks at them with the open-file AppleEvent, calls -application:openFiles:, waits for the response global to be set, then sends back and AppleEvent reply. When I reuse -application:openFiles: in -openDocument, I post to that global when the application object isn't expecting it.... Oh, crap.

Oh, I could submit the files for processing by putting them in an open-file AppleEvent and sending to self. I look around the docs, and I see everything except what I need: how to send an AppleEvent and the list of possible AppleEvents and their parameters.

Could someone here demostrate how to create and send an open-file AppleEvent? Or at least tell us where the table of event IDs and parameters are? (The various Cocoa guides on scripting refer to the event ID reference, but it's a dead link, leading to Apple's developer portal general/search page.)


Solution

  • I just guessed:

    - (IBAction)openDocument:(id)sender {
        NSOpenPanel * const  panel = [NSOpenPanel openPanel];
    
        panel.allowsMultipleSelection = YES;
        panel.delegate = self.openPanelDelegate;
        [panel beginWithCompletionHandler:^(NSInteger result) {
            if (result == NSFileHandlingPanelOKButton) {
                NSAppleEventDescriptor * const   fileList = [NSAppleEventDescriptor listDescriptor];
                NSAppleEventDescriptor * const  openEvent = [NSAppleEventDescriptor appleEventWithEventClass:kCoreEventClass eventID:kAEOpenDocuments targetDescriptor:nil returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
    
                for (NSURL *file in panel.URLs) {
                    [fileList insertDescriptor:[NSAppleEventDescriptor descriptorWithDescriptorType:typeFileURL data:[[file absoluteString] dataUsingEncoding:NSUTF8StringEncoding]] atIndex:0];
                }
                [openEvent setParamDescriptor:fileList forKeyword:keyDirectObject];
                [[NSAppleEventManager sharedAppleEventManager] dispatchRawAppleEvent:[openEvent aeDesc] withRawReply:(AppleEvent *)[[NSAppleEventDescriptor nullDescriptor] aeDesc] handlerRefCon:(SRefCon)0];
            }
        }];
    }
    

    looking at the docs for "NSAppleEventManager.h" and "NSAppleEventDescriptor.h" and half-remembering Mac programming materials I read in the 1990s.

    I also poked around the Legacy/Retired Documents section of Apple's Developer Portal / Xcode.