Initializing the menubar without Interface Builder

  • Hi all,

    How do I setup the menu bar if I'm not using Interface Builder?
    Here's some sample code that pops up a window, but there are no menus.

    I could answer this myself if I could see the source code for
    NSApplicationMain, but that's not available, correct?

    thank you,
    Rob

    #import <Cocoa/Cocoa.h>

    int main()
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSApplication *app = [NSApplication sharedApplication];

        id window = [[NSWindow alloc] initWithContentRect: NSMakeRect
    (10,10,100,100)
                                      styleMask: NSTitledWindowMask |
    NSResizableWindowMask | NSClosableWindowMask |
    NSMiniaturizableWindowMask
                                      backing: NSBackingStoreBuffered
                                      defer: NO];
        [window makeKeyAndOrderFront: window];

        id m = [[NSMenu alloc] initWithTitle: @"Test Menu"];
        id mi = [[NSMenuItem alloc] initWithTitle: @"Test Menu Item"
                                    action: nil
                                    keyEquivalent: @""];
        [m addItem: mi];
        printf ("mainMenu: %p\n", [app mainMenu]);
        [app setMainMenu: m];
        [NSMenu setMenuBarVisible: YES];

        [app run];
        [pool release];
    }
  • Rob,

    I wrote a series of short articles about this a few months ago.  The
    latest is at <http://lapcatsoftware.com/blog/2007/07/10/working-
    without-a-nib-part-5-open-recent-menu/
    >.  The technique should still
    work on Leopard, though it's using a deprecated method.  I'll write a
    new article soon about a non-deprecated technique that works on Leopard.

    -Jeff

    On Nov 3, 2007, at 12:12 PM, Robert Nikander wrote:

    > Hi all,
    >
    > How do I setup the menu bar if I'm not using Interface Builder?
    > Here's some sample code that pops up a window, but there are no menus.
    >
    > I could answer this myself if I could see the source code for
    > NSApplicationMain, but that's not available, correct?
    >
    > thank you,
    > Rob
    >
    >
    > #import <Cocoa/Cocoa.h>
    >
    > int main()
    > {
    > NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    > NSApplication *app = [NSApplication sharedApplication];
    >
    > id window = [[NSWindow alloc] initWithContentRect: NSMakeRect
    > (10,10,100,100)
    > styleMask: NSTitledWindowMask |
    > NSResizableWindowMask | NSClosableWindowMask |
    > NSMiniaturizableWindowMask
    > backing: NSBackingStoreBuffered
    > defer: NO];
    > [window makeKeyAndOrderFront: window];
    >
    > id m = [[NSMenu alloc] initWithTitle: @"Test Menu"];
    > id mi = [[NSMenuItem alloc] initWithTitle: @"Test Menu Item"
    > action: nil
    > keyEquivalent: @""];
    > [m addItem: mi];
    > printf ("mainMenu: %p\n", [app mainMenu]);
    > [app setMainMenu: m];
    > [NSMenu setMenuBarVisible: YES];
    >
    > [app run];
    > [pool release];
    > }
  • On Nov 3, 2007, at 12:12 PM, Robert Nikander wrote:

    > I could answer this myself if I could see the source code for
    > NSApplicationMain, but that's not available, correct?

    I would kill for this.  Well, maybe not kill, but seriously maim.
  • On Nov 3, 2007, at 10:12 AM, Robert Nikander wrote:

    > I could answer this myself if I could see the source code for
    > NSApplicationMain, but that's not available, correct?
    >
    <http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Cla
    sses/NSApplication_Class/Reference/Reference.html
    >

    "The main() function Xcode creates begins by calling a function named
    NSApplicationMain(), which is functionally similar to the following:"...

    void NSApplicationMain(int argc, char *argv[]) {
        [NSApplication sharedApplication];
        [NSBundle loadNibNamed:@"myMain" owner:NSApp];
        [NSApp run];
    }

    See also <http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Mis
    cellaneous/AppKit_Functions/Reference/reference.html#//apple_ref/c/func/NSA
    pplicationMain
    >.
    "Creates the application, loads the main nib file from the
    application’s main bundle, and runs the application. You typically
    only call this function once, from your application’s main function,
    which is usually generated automatically by Xcode."

    So, particularly with reference to <http://developer.apple.com/DOCUMENTATION/MacOSX/Conceptual/BPRuntimeConfig/
    Articles/PListKeys.html
    > you can fill in a little more detail:

    void NSApplicationMain(int argc, char *argv[])
    {
        NSDictionary * infoDictionary = [[NSBundle mainBundle]
    infoDictionary];

        NSString *principalClassName = [infoDictionary
    objectForKey:@"NSPrincipalClass"];
        Class principalClass = NSClassFromString(principalClassName);
        [principalClass sharedApplication];

        NSString *mainNibFile = [infoDictionary
    objectForKey:@"NSMainNibFile"];
        [NSBundle loadNibNamed:@"mainNibFile" owner:NSApp];

        [NSApp run];
    }

    mmalc
  • On Nov 3, 2007, at 2:29 PM, mmalc crawford wrote:
    > On Nov 3, 2007, at 10:12 AM, Robert Nikander wrote:
    >
    >> I could answer this myself if I could see the source code for
    >> NSApplicationMain, but that's not available, correct?
    >>
    >
    >
    > void NSApplicationMain(int argc, char *argv[]) {
    > [NSApplication sharedApplication];
    > [NSBundle loadNibNamed:@"myMain" owner:NSApp];
    > [NSApp run];
    > }

    I'm trying to set up the menus programmatically, without loading
    nibs, so I would need to the see source for other functions called by
    NSApplicationMain as well.

    Rob
  • On Nov 3, 2007, at 1:37 PM, Jeff Johnson wrote:
    > I wrote a series of short articles about this a few months ago.
    > The latest is at <http://lapcatsoftware.com/blog/2007/07/10/working-
    > without-a-nib-part-5-open-recent-menu/>.  The technique should
    > still work on Leopard, though it's using a deprecated method.  I'll
    > write a new article soon about a non-deprecated technique that
    > works on Leopard.

    Thanks.  I downloaded your sample and am messing around with it -- I
    also want to get rid of the Info.plist and the package directory
    structure.

    Rob
  • On Nov 3, 2007, at 11:54 AM, Robert Nikander wrote:

    > I'm trying to set up the menus programmatically, without loading
    > nibs, so I would need to the see source for other functions called
    > by NSApplicationMain as well.
    >
    No, you wouldn't.

    If all NSApplication is doing is loading a nib file using the same
    NSBundle method used by the rest of the system, the sensible next step
    is to look at the contents of a typical MainMenu nib file and see what
    properties the main menu itself has...

    mmalc
  • Okay... I've got a menu to show up, but the behavior seems to depend
    on the location of the executable file, which I don't understand.

    If I put the code below in a file called "cocoa.m" and compile it
    from the command line with:

        gcc -o cocoa cocoa.m -framework Cocoa

    and I run it like this:

        ./cocoa

    then no menu shows up.  But if I copy the binary into a bundle
    directory, like this:

        cp cocoa CocoaTest.app/Contents/MacOS/CocoaTest

    and run that same binary, at the different location:

        ./CocoaTest.app/Contents/MacOS/CocoaTest

    then the menu bar shows up.

    Why the difference?  Does a cocoa binary have to run from within a
    bundle directory?

    thanks,
    Rob

    ---

    #import <Cocoa/Cocoa.h>

    int main()
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSApplication *app = [NSApplication sharedApplication];

        id window = [[NSWindow alloc] initWithContentRect: NSMakeRect
    (10,10,100,100)
                                      styleMask: NSTitledWindowMask |
    NSResizableWindowMask | NSClosableWindowMask |
    NSMiniaturizableWindowMask
                                      backing: NSBackingStoreBuffered
                                      defer: NO];

        NSMenu *mainMenu = [[NSMenu alloc] initWithTitle: @"MainMenu"];
        NSMenuItem *mi;
        NSMenu *m;
        mi = [mainMenu addItemWithTitle:@"Apple" action:NULL
    keyEquivalent:@""];
        m = [[NSMenu alloc] initWithTitle:@"Apple"];
        // strange hack
        [NSApp performSelector:@selector(setAppleMenu:) withObject: m];
        [mainMenu setSubmenu:m forItem:mi];
        mi = [m addItemWithTitle: @"Test Item"
                action: nil
                keyEquivalent: @""];

        [app setMainMenu: mainMenu];

        [window makeKeyAndOrderFront: window];

        [app run];
        [pool release];
    }
  • On Nov 3, 2007, at 5:15 PM, Robert Nikander wrote:

    > Okay... I've got a menu to show up, but the behavior seems to depend
    > on the location of the executable file, which I don't understand.
    >
    > If I put the code below in a file called "cocoa.m" and compile it
    > from the command line with:
    >
    > gcc -o cocoa cocoa.m -framework Cocoa
    >
    > and I run it like this:
    >
    > ./cocoa
    >
    > then no menu shows up.  But if I copy the binary into a bundle
    > directory, like this:
    >
    > cp cocoa CocoaTest.app/Contents/MacOS/CocoaTest
    >
    > and run that same binary, at the different location:
    >
    > ./CocoaTest.app/Contents/MacOS/CocoaTest
    >
    > then the menu bar shows up.
    >
    > Why the difference?  Does a cocoa binary have to run from within a
    > bundle directory?

    mach-o binaries on Mac OS X (whether they're Carbon or Cocoa) must be
    run from within a bundle in order to get the normal GUI interface and
    process management behavior. That includes being able to click on the
    app's windows to make it active and get a menubar.

    It's recommended to just use a bundle, but if you really want to use a
    flat file, you can call TransformProcessType (HIServices/Processes.h)
    from main() to make the app foreground-capable.

    -eric
  • On Nov 4, 2007, at 11:25 AM, Eric Schlegel wrote:
    > On Nov 3, 2007, at 5:15 PM, Robert Nikander wrote:
    >> <snip>
    >> Why the difference?  Does a cocoa binary have to run from within a
    >> bundle directory?
    >
    > mach-o binaries on Mac OS X (whether they're Carbon or Cocoa) must
    > be run from within a bundle in order to get the normal GUI
    > interface and process management behavior. That includes being able
    > to click on the app's windows to make it active and get a menubar.
    >
    > It's recommended to just use a bundle, but if you really want to
    > use a flat file, you can call TransformProcessType (HIServices/
    > Processes.h) from main() to make the app foreground-capable.

    Thanks!  I'll try to use a bundle, but for what I'm working on it's
    good to understand this and have the option.

    Rob
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today