How to implement a Cocoa-based Adobe Photoshop plugin

cocoa, objective-c, photoshop

Solution

You have to create a new Loadable Bundle target that contains your nibs and your Cocoa code. Add the bundle product to the Copy Bundle Resources phase of your plugin. Then the code for a filter plugin that loads a Cocoa window with some controls would be:

Boolean DoUI (void) {

    // Create the CF Cocoa bundle
    CFBundleRef pluginBundle;
    CFURLRef cocoaBundleURL;
    pluginBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.example.plugin"));
    cocoaBundleURL = CFBundleCopyResourceURL(pluginBundle, 
                                             CFSTR("Cocoa_bundle"), 
                                             CFSTR("bundle"), 
                                             NULL);
    CFBundleRef cocoaBundleRef;
    cocoaBundleRef = CFBundleCreate(kCFAllocatorDefault, cocoaBundleURL);
    CFRelease(cocoaBundleURL);

    // start Cocoa (for CS3)
    NSApplicationLoad(); 

    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    // load the cocoa bundle by identifier
    NSBundle* cocoaBundle;
    cocoaBundle = [NSBundle bundleWithIdentifier:@"com.example.plugin.cocoa"];

    // load the window controller from the bundle
    Class testControllerClass;
    testControllerClass = [cocoaBundle classNamed:@"MyWindowController"];

    MyWindowController* winController = [[testControllerClass alloc] init];
    [NSApp runModalForWindow:[winController window]];
    [[winController window] performClose:nil];
    [winController release];

    // release the bundle
    CFRelease(cocoaBundleRef);

    [pool release];

    return 1;
}

This is based on the Craig Hockenberry bundle trick. I'm still testing it but it should work both on CS3 and CS4.

Problem

Cocoa used to work on CS3 with the trick of putting a Cocoa bundle inside the main Carbon plugin bundle, loading it from Carbon and issuing a NSApplicationLoad(). That's because Photoshop CS3 was Carbon-only and used to unload the plugin bundles. Photoshop CS4 uses Cocoa and has its own NSAutorelease pool in place on the main thread. On Photoshop CS4 very simple window-based xibs/nibs loaded by a NSWindowController work out of the box. But just add a binding to a control on the window and you'll get funny crashes, optionally when you close the window, or the second time you use the plugin, or even when closing Photoshop itself. Why everything seem to work well until I use some advanced Cocoa features? I'm stuck. EDIT: I've really found myself the solution to the broader problem "How to use Cocoa in a Photoshop CS3/CS4 plugin?". See below.

Original source