8

I'm building a menu bar in my cocoa application with the following code in the @implementation of my custom application CustomApplication:

+(void) setUpMenuBar
{
  [CustomApplication sharedApplication];

  // Main menu
  NSMenu* mainMenu = [NSApp mainMenu];
  if (mainMenu != nil) return; // We set it already
  mainMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
  [NSApp setMainMenu:mainMenu];

  // Application menu
  NSMenuItem* appleItem = [mainMenu addItemWithTitle:@""
                                              action:nil
                                       keyEquivalent:@""];

  NSString* appName = @"MyApp";

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

  // Apple menu
  [appleMenu addItemWithTitle:[@"About " stringByAppendingString:appName]
                       action:@selector(orderFrontStandardAboutPanel:)
                keyEquivalent:@""];

  // Quit
  [appleMenu addItemWithTitle:[@"Quit " stringByAppendingString:appName]
                                        action:@selector(terminate:)
                                        keyEquivalent:@"q"];

  [appleItem setSubmenu:[appleMenu autorelease]];
}

At launch, my application gets the focus, but the menu bar is not clikable. However, if I click out the window and in again (giving the focus back to the application), it becomes clickable and working correctly.

Did I miss something?


UPDATE

This method is called when I'm creating the application as follows. [UPDATE] This is what I'm starting my application with. It is actually called first thing from an ocaml binding outside any @implementation of a class.

CustomApplicationDelegate* delegate = [CustomApplicationDelegate new];

[CustomApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];

[[NSApplication sharedApplication] setDelegate:delegate];

[CustomApplication setUpMenuBar];

[[CustomApplication sharedApplication] finishLaunching];
Théo Winterhalter
  • 4,908
  • 2
  • 18
  • 34
  • You haven't said how/when this +setUpMenuBar method is called. I would also suggest moving the [NSApp setMainMenu:mainMenu] call to the end of the function, so that you give the menu to NSApp after it is all set up; I can imagine that NSApp parses the menu structure it is given and caches information about it, which might explain why it is initially non-functional. Overall, my reaction is: "Gah, why are you doing this instead of using a nib??" But I am trying to suppress my gag reflex... – bhaller Oct 26 '15 at 13:55
  • Alright, I edited my message to give more information. As for why I decided not to use a nib, I'm actually working on a cross-platform library. – Théo Winterhalter Oct 26 '15 at 15:16
  • Oh and your solution doesn't work unfortunately, thanks anyway. – Théo Winterhalter Oct 26 '15 at 15:22
  • Even for a cross-platform library, I would suggest making a basic menu bar in a nib and adding things to it in code as needed. – bhaller Oct 26 '15 at 19:12
  • The information you added to the question still does not say when you are making these calls. Is this in applicationWillFinishLaunching? applicationDidFinishLaunching? Some other time? Please supply proper context. From what you have posted thus far, I would say that it seems odd to ask NSApp to activateIgnoringOtherApps: before you have even given it a menu bar; what exactly do you expect it to display when it activates? I would reorder that, as another guess at what the problem might be. – bhaller Oct 26 '15 at 19:15
  • I tried to explain it better, is it still lacking? I tried reorganizing the methods call and even putting it inside `applicationWillFinishLaunching` of the delegate (obviously I didn't put the `setDelegate` inside). – Théo Winterhalter Oct 26 '15 at 20:09

3 Answers3

7

Okay, thanks to the remarks of @bhaller I was able to solve my problem.

I actually transferred my calls to the delegate as follows.

-(void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
  [CustomApplication sharedApplication];
  [CustomApplication setUpMenuBar];
  [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
}

-(void)applicationDidFinishLaunching:(NSNotification *)notification
{
  [CustomApplication sharedApplication];

  [NSApp activateIgnoringOtherApps:YES];
}
Théo Winterhalter
  • 4,908
  • 2
  • 18
  • 34
  • OK, good. I guess I should have posted all that as an answer so I got the credit. :-> So, for posterity, what exactly turned out to be the problem? Was it that the activateIgnoringOtherApps: call was too early? – bhaller Oct 27 '15 at 00:06
  • You still can if you want. But reorganizing the method calls wasn't enough. This order in the same function doesn't work, for instance, if I put `setActivationPolicy` in the second one, before `activate` the same problem occurs. – Théo Winterhalter Oct 27 '15 at 11:15
  • Hmm, very strange. Well, this is, in a nutshell, why it would be a good idea to use a minimal nib rather than building the menu bar from scratch. Because nobody ever builds UI from scratch this way, it is a basically untested case, and may expose all kinds of weird bugs and order-dependencies in Cocoa. Not only those, those weird bugs and order-dependencies are likely to vary from release to release of OS X. You will prevent many bizarre OS-X-version-dependent issues by starting with a nib instead, I predict. – bhaller Oct 27 '15 at 13:46
  • I see, but this sound like a lot of overhead for something I'm developing in ocaml and not using Xcode, this means I cannot hand over control of this to the user of the library. – Théo Winterhalter Oct 27 '15 at 14:38
  • Hmm. Well, I have no idea what ocaml is, so perhaps you are right, I don't know. Good luck with it! – bhaller Oct 27 '15 at 17:30
  • 1
    For me adding `[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];` as the last line of `applicationWillFinishLaunching` worked. – IndrekV Jan 07 '16 at 15:23
  • 1
    I needed to move `[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];` to `applicationDidFinishLaunching` for the menu to work. It seems that generally speaking this activation policy needs to be set after the menu is all set. – Strom May 28 '20 at 13:39
4

I had this issue and the reason was because my call to [NSApp activateIgnoringOtherApps:YES] was in applicationWillFinishLaunching: instead of applicationDidFinishLaunching:.

As soon as I moved it, the menubar worked on first-launch.

EpaL
  • 51
  • 3
1

I fixed by removing LSUIElement in Info.plist if the app has a Window and Menu Bar.

The old solution is that we override this config with [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];, but in Catalina, it doesn't work anymore.

Nghia Tran
  • 2,600
  • 2
  • 16
  • 25