Next: 6 Changing the window Up: GNUstep Renaissance Previous: 4 Loading the gsmarkup

5 Adding a menu

We now want to add a very simple menu, containing a simple Quit item. Clicking on the item should quit the application. Here is the required gsmarkup file:
<gsmarkup>

  <objects>

    <menu type="main">
      <menuItem title="Quit" key="q" action="terminate:" />
    </menu>
 
  </objects>

</gsmarkup>
In this file, the <objects> tag contains a single menu object, which contains a single menuItem.

When GNUstep Renaissance loads the file, it will create a menu object (corresponding to the <menu type="main"> tag inside the <objects> tag). This menu will be the application main menu, because type="main" has been used as attribute of the menu tag. Inside the menu, GNUstep Renaissance will create a single item, with title Quit, key equivalent q, and which, when clicked, will execute the action terminate:.

Please note that the menuItem object is inside the menu object because the <menuItem> tag is inside the <menu> tag. Generally, the nesting of tags represents a corresponding nesting of objects.

Because the menus are organized in a completely different way on Apple Mac OS X, this file won't really generate a proper menu on Apple Mac OS X. If you are using Apple Mac OS X, you should rather use the following gsmarkup file for your menu:

<gsmarkup>

  <objects>

    <menu type="main">
      <menu title="Example" type="apple">
        <menuItem title="Quit Example" key="q" action="terminate:" />
      </menu>
    </menu>
 
  </objects>

</gsmarkup>
The structure in this case is more complex: inside the main menu (displayed horizontally on Apple), there is a submenu called Example. In the submenu there is a single menu item, with title Quit Example, key equivalent q, calling the action terminate:. Please note that this menu has type="apple". This attribute is ignored under GNUstep, and only used by Apple Mac OS X; you should always have one and only one submenu (the first one) with type apple for Apple Mac OS X menus; it is used to identify the first compulsory submenu of an application menu, the one with the title displayed in bold, and containing the Quit XXX menu item.

If you need your application to run on both systems, you will need to provide two separate gsmarkup files, each one using its system specific menu layouts: one for GNUstep, the other one for Apple Mac OS X; and then load the specific one depending on the platform you are running on (you can use the GNUSTEP preprocessor defined symbol to know on which platform you are; the symbol is defined on GNUstep, but not on Apple Mac OS X). Conventionally, you can call the first one Menu-GNUstep.gsmarkup, and the second one Menu-OSX.gsmarkup.

Menus are really the only part of the user interface where such a strong distinction is required. You can usually use the same window (and gsmarkup file) on both systems; but because menus need to comply more strictly with the platform in terms of the names and positions of the menu items and of the submenus, at the moment to get a real native feel on the two platforms, you need separate menus.

The gsmarkup file containing the main menu has to be loaded before calling NSApplicationMain(); this is the most portable way of loading it. Here is the new main.m file, with the required changes to load our new Menu-GNUstep.gsmarkup (or Menu-OSX.gsmarkup) file:

#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
#include <Renaissance/Renaissance.h>

@interface MyDelegate : NSObject
{}
- (void) applicationDidFinishLaunching: (NSNotification *)not;
@end

@implementation MyDelegate : NSObject 

- (void) applicationDidFinishLaunching: (NSNotification *)not;
{
  [NSBundle loadGSMarkupNamed: @"Window"  owner: self];
}
@end

int main (int argc, const char **argv)
{ 
  CREATE_AUTORELEASE_POOL (pool);
  MyDelegate *delegate;
  [NSApplication sharedApplication];

  delegate = [MyDelegate new];
  [NSApp setDelegate: delegate];

#ifdef GNUSTEP
  [NSBundle loadGSMarkupNamed: @"Menu-GNUstep"  owner: delegate];
#else
  [NSBundle loadGSMarkupNamed: @"Menu-OSX"  owner: delegate];
#endif

  RELEASE (pool);
  return NSApplicationMain (argc, argv);
}
Here we use delegate as the owner argument of the loadGSMarkupNamed:owner: method. Because we are not using the owner yet, it is not important which object is passed - except for a detail, which is that the owner is used to determine in which bundle to look for the gsmarkup file to load; passing an object of a class defined in your application makes sure that the file is looked for in the main application bundle. In practice, if you are loading files from your application main bundle, you should always pass an instance of an object defined in your application as the owner.

We have also enclosed the loading of the Menu gsmarkup file inside the creation and release of an autorelease pool; this is needed because otherwise no autorelease pool would in place at that point. Generally, whenever you need to do anything non-trivial inside your main function, you need to create an autorelease pool at the beginning, and release it at the end.

Do not forget to add Menu-GNUstep.gsmarkup and Menu-OSX.gsmarkup to the resource files (listed in the Example_RESOURCE_FILES variable) in the GNUmakefile:

include $(GNUSTEP_MAKEFILES)/common.make

APP_NAME = Example
Example_OBJC_FILES = main.m
Example_RESOURCE_FILES = \
  Menu-GNUstep.gsmarkup \
  Menu-OSX.gsmarkup \
  Window.gsmarkup \


ifeq ($(FOUNDATION_LIB), apple)
  ADDITIONAL_INCLUDE_DIRS += -framework Renaissance
  ADDITIONAL_GUI_LIBS += -framework Renaissance
else
  ADDITIONAL_GUI_LIBS += -lRenaissance
endif

include $(GNUSTEP_MAKEFILES)/application.make

The application should now build and run, and display an empty window and a very simple menu with a single ``Quit'' menu item, which quits the application.


Next: 6 Changing the window Up: GNUstep Renaissance Previous: 4 Loading the gsmarkup
Nicola 2003-01-31