Fixed bug 4877 - Add support for loading menus from a nib/xib instead of building a hardcoded minimum set
authorSam Lantinga <slouken@libsdl.org>
Tue, 03 Dec 2019 07:12:55 -0800
changeset 13309a72231930f12
parent 13308 fb600198ec12
child 13310 f9a9707ff56d
Fixed bug 4877 - Add support for loading menus from a nib/xib instead of building a hardcoded minimum set

Eric Shepherd

Currently, SDL on Cocoa macOS creates a rudimentary menu bar programmatically if none is already present when the app is registered during setup.

SDL could be much more easily and flexibly used on macOS if upon finding that no menus are currently in place, it first looked for the application's main menu nib or xib file and, if found, loaded that instead of programmatically building the menus.

This would then let developers simply drop in a nib file with a menu bar defined in it and it would be installed and used automatically.

Attached is a patch that does just this. It changes the SDL_cocoaevents.m file to:

* In Cocoa_RegisterApp(), before calling CreateApplicationMenus(), it calls a new function, LoadMainMenuNibIfAvailable(), which attempts to load and install the main menu nib file, using the nib name fetched from the Info.plist file. If that succeeds, LoadMainMenuNibIfAvailable() returns true; otherwise false.
* If LMMNIA() returns false, CreateApplicationMenus() is called to programmatically build the menus as before.
* Otherwise, we're done, and using the menus from the nib/xib file!

I made these changes to support a project I'm working on, and felt they were useful enough to be worth offering them for uplift. They should have zero impact on existing projects' behavior, but make Cocoa SDL development miles easier.
src/video/cocoa/SDL_cocoaevents.m
     1.1 --- a/src/video/cocoa/SDL_cocoaevents.m	Tue Dec 03 03:53:06 2019 -0500
     1.2 +++ b/src/video/cocoa/SDL_cocoaevents.m	Tue Dec 03 07:12:55 2019 -0800
     1.3 @@ -267,6 +267,25 @@
     1.4      return appName;
     1.5  }
     1.6  
     1.7 +static bool
     1.8 +LoadMainMenuNibIfAvailable(void)
     1.9 +{
    1.10 +    NSDictionary *infoDict;
    1.11 +    NSString *mainNibFileName;
    1.12 +    bool success = false;
    1.13 +    
    1.14 +    infoDict = [[NSBundle mainBundle] infoDictionary];
    1.15 +    if (infoDict) {
    1.16 +        mainNibFileName = [infoDict valueForKey:@"NSMainNibFile"];
    1.17 +        
    1.18 +        if (mainNibFileName) {
    1.19 +            success = [[NSBundle mainBundle] loadNibNamed:mainNibFileName owner:[NSApplication sharedApplication] topLevelObjects:nil];
    1.20 +        }
    1.21 +    }
    1.22 +    
    1.23 +    return success;
    1.24 +}
    1.25 +
    1.26  static void
    1.27  CreateApplicationMenus(void)
    1.28  {
    1.29 @@ -281,7 +300,7 @@
    1.30      if (NSApp == nil) {
    1.31          return;
    1.32      }
    1.33 -
    1.34 +    
    1.35      mainMenu = [[NSMenu alloc] init];
    1.36  
    1.37      /* Create the main menu bar */
    1.38 @@ -385,8 +404,17 @@
    1.39              [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
    1.40          }
    1.41  
    1.42 +        /* If there aren't already menus in place, look to see if there's
    1.43 +         * a nib we should use. If not, then manually create the basic
    1.44 +         * menus we meed.
    1.45 +         */
    1.46          if ([NSApp mainMenu] == nil) {
    1.47 -            CreateApplicationMenus();
    1.48 +            bool nibLoaded;
    1.49 +            
    1.50 +            nibLoaded = LoadMainMenuNibIfAvailable();
    1.51 +            if (!nibLoaded) {
    1.52 +                CreateApplicationMenus();
    1.53 +            }
    1.54          }
    1.55          [NSApp finishLaunching];
    1.56          if ([NSApp delegate]) {