Search code examples
objective-cmacosselectornsmenufindersync

No callback when clicking menu item


I'm trying to implement a simple context menu in my FinderSync extension.

I built the following using some examples, and my problem is that the callback is never called when I click the menu item.

Source code:

ContextMenuHelper.h

#import <Foundation/Foundation.h>
#include "FinderSync.h"

@interface ContextMenuHelper : NSObject

+ (NSMenu *)buildMenu;

@end

ContextMenuHelper.m

#import "ContextMenuHelper.h"

#define SharedContextMenuTarget  [ContextMenuTarget sharedInstance]

@interface ContextMenuTarget : NSObject
+ (ContextMenuTarget *) sharedInstance;
@end

@implementation ContextMenuTarget

- (void) callback              : (id)sender {
    NSLog(@"Called back!!!");
}

+ (ContextMenuTarget *) sharedInstance
{
    static ContextMenuTarget *sharedContextMenuTarget = nil;
    @synchronized(self)
    {
        if (!sharedContextMenuTarget)
            sharedContextMenuTarget = [[ContextMenuTarget alloc] init];
        return sharedContextMenuTarget;
    }
}

@end

@implementation ContextMenuHelper

+ (NSMenu *)buildMenu
{
    ContextMenuTarget *contextMenuTarget = SharedContextMenuTarget;

    NSMenu *mySubmenu = [[NSMenu alloc] initWithTitle:@""];

    NSMenuItem *newMenu = [[NSMenuItem alloc] initWithTitle:@"hello"
                                                     action:@selector(callback:)
                                              keyEquivalent:@""];
    [newMenu setTarget:contextMenuTarget];
    [mySubmenu addItem:newMenu];

    return mySubmenu;
}

@end

MyFinderSync.m

...
- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu {

    NSMenu *myContextMenu = [[NSMenu alloc] initWithTitle:@""];

    @try
    {
        if(whichMenu != FIMenuKindContextualMenuForItems) {
            return myContextMenu;
        }

        myContextMenu = [ContextMenuHelper buildMenu];
    }
    @catch (NSException *ex)
    {
    }

    return myContextMenu;
}
...

Solution

  • Apparently, callbacks will only work if the target is the instance of FinderSync. Could not find any documentation to support this theory, but the only thing that fixed the problem was moving the context menu code into MyFinderSync.m:

    ...
    - (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu {
    
        NSMenu *myContextMenu = [[NSMenu alloc] initWithTitle:@""];
    
        @try
        {
            if(whichMenu != FIMenuKindContextualMenuForItems) {
                return myContextMenu;
            }
    
            myContextMenu = [self buildMenu];
        }
        @catch (NSException *ex)
        {
        }
    
        return myContextMenu;
    }
    
    - (NSMenu *)buildMenu
    {
        NSMenu *mySubmenu = [[NSMenu alloc] initWithTitle:@""];
    
        NSMenuItem *newMenu = [[NSMenuItem alloc] initWithTitle:@"hello"
                                                         action:@selector(callback:)
                                                  keyEquivalent:@""];
        [newMenu setTarget:self];
        [mySubmenu addItem:newMenu];
    
        return mySubmenu;
    }
    
    - (void) callback              : (id)sender {
        NSLog(@"Called back!!!");
    }
    ...