I'm trying a minimalistic Cocoa app as described in this page using code:
#import <Cocoa/Cocoa.h>;
int main ()
{
[NSAutoreleasePool new];
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
id menubar = [[NSMenu new] autorelease];
id appMenuItem = [[NSMenuItem new] autorelease];
[menubar addItem:appMenuItem];
[NSApp setMainMenu:menubar];
id appMenu = [[NSMenu new] autorelease];
id appName = [[NSProcessInfo processInfo] processName];
id quitTitle = [@"Quit " stringByAppendingString:appName];
id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle
action:@selector(terminate:) keyEquivalent:@"q"] autorelease];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
id window = [[[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200)
styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]
autorelease];
[window cascadeTopLeftFromPoint:NSMakePoint(20,20)];
[window setTitle:appName];
[window makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
[NSApp run];
return 0;
}
My issue is, that the application menu is not responding until I reactivate its window (activating another app and then clicking back to my app window).
Any idea why and how to resolve it?
CodePudding user response:
Ok... I found the solution... I must replace
[NSApp activateIgnoringOtherApps:YES];
with:
dispatch_async(dispatch_get_main_queue(), ^{
[NSApp activateIgnoringOtherApps:YES];
});
I don't know why, but it works.
CodePudding user response:
The AppKit is still in your app's startup phase when you're attempting to call [NSApp activateIgnoringOtherApps:YES];
.
The correct way to do it is to handle it through NSApplicationDelegate
:
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (strong, nonatomic, class, readonly) AppDelegate* sharedInstance;
@end
@implementation AppDelegate
(instancetype)sharedInstance {
static AppDelegate *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [AppDelegate new];
});
return sharedInstance;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSApp activateIgnoringOtherApps:YES];
}
@end
int main ()
{
[NSAutoreleasePool new];
[NSApplication sharedApplication];
NSApplication.sharedApplication.delegate = [AppDelegate sharedInstance];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
id menubar = [[NSMenu new] autorelease];
id appMenuItem = [[NSMenuItem new] autorelease];
[menubar addItem:appMenuItem];
[NSApp setMainMenu:menubar];
id appMenu = [[NSMenu new] autorelease];
id appName = [[NSProcessInfo processInfo] processName];
id quitTitle = [@"Quit " stringByAppendingString:appName];
id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle
action:@selector(terminate:) keyEquivalent:@"q"] autorelease];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
id window = [[[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200)
styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]
autorelease];
[window cascadeTopLeftFromPoint:NSMakePoint(20,20)];
[window setTitle:appName];
[window makeKeyAndOrderFront:nil];
[NSApp run];
return 0;
}
As a bonus the delegate's - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
will get invoked before your:
dispatch_async(dispatch_get_main_queue(), ^{
[NSApp activateIgnoringOtherApps:YES];
});
hinting it's the correct way to do it.