Date: Thu, 2 Sep 2004 19:35:51 +0200
From: Max Horn
Subject: [Patch]: Improved menu code for SDLMain.m
the attached patch improves the menu setup for SDL apps built without a
.nib file. On 10.3, the application menus are empty with the current
SDL CVS version; after this patch, a proper app & window menu, with
"About", "Hide", "Quit", "Minimize" etc. entries are visible, just like
with the .nib enabled applications.
This *should* work on 10.2 and even 10.1, but I can't guarantee it, so
somebody should test there, ideally.
I also changed the way setupWorkingDirectory works by making use of the
Bundle APIs, that results in (IMO) less hackish code.
Finally, I added some "static" keywords to ensure that certain local
functions are not exported (that's just a paranoia change, I guess:
never pollute linker namespaces if you can avoid it).
--- a/src/main/macosx/SDLMain.m Fri Sep 17 13:25:06 2004 +0000
+++ b/src/main/macosx/SDLMain.m Fri Sep 17 13:28:12 2004 +0000
@@ -33,16 +33,27 @@
static char **gArgv;
static BOOL gFinderLaunch;
+static NSString *getApplicationName(void)
+{
+ NSDictionary *dict;
+ NSString *appName = 0;
+
+ /* Determine the application name */
+ dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
+ if (dict)
+ appName = [dict objectForKey: @"CFBundleName"];
+
+ if (![appName length])
+ appName = [[NSProcessInfo processInfo] processName];
+
+ return appName;
+}
+
#if SDL_USE_NIB_FILE
/* A helper category for NSString */
@interface NSString (ReplaceSubString)
- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
@end
-#else
-/* An internal Apple class used to setup Apple menus */
-@interface NSAppleMenuController:NSObject {}
-- (void)controlMenu:(NSMenu *)aMenu;
-@end
#endif
@interface SDLApplication : NSApplication
@@ -59,33 +70,24 @@
}
@end
-
/* The main class of the application, the application's delegate */
@implementation SDLMain
/* Set the working directory to the .app's parent directory */
- (void) setupWorkingDirectory:(BOOL)shouldChdir
{
-
if (shouldChdir)
{
char parentdir[MAXPATHLEN];
- char *c;
-
- strncpy ( parentdir, gArgv[0], sizeof(parentdir) );
- c = (char*) parentdir;
-
- while (*c != '\0') /* go to end */
- c++;
+ CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+ CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
+ if (CFURLGetFileSystemRepresentation(url2, true, parentdir, MAXPATHLEN)) {
+ assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */
+ }
+ CFRelease(url);
+ CFRelease(url2);
+ }
- while (*c != '/') /* back up to parent */
- c--;
-
- *c++ = '\0'; /* cut off last part (binary name) */
-
- assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */
- assert ( chdir ("../../../") == 0 ); /* chdir to the .app's parent */
- }
}
#if SDL_USE_NIB_FILE
@@ -115,38 +117,56 @@
#else
-void setupAppleMenu(void)
+static void setApplicationMenu(void)
{
/* warning: this code is very odd */
- NSAppleMenuController *appleMenuController;
NSMenu *appleMenu;
- NSMenuItem *appleMenuItem;
+ NSMenuItem *menuItem;
+ NSString *title;
+ NSString *appName;
+
+ appName = getApplicationName();
+ appleMenu = [[NSMenu alloc] initWithTitle:@""];
+
+ /* Add menu items */
+ title = [@"About " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
- appleMenuController = [[NSAppleMenuController alloc] init];
- appleMenu = [[NSMenu alloc] initWithTitle:@""];
- appleMenuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
-
- [appleMenuItem setSubmenu:appleMenu];
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Hide " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+
+ menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
- /* yes, we do need to add it and then remove it --
- if you don't add it, it doesn't get displayed
- if you don't remove it, you have an extra, titleless item in the menubar
- when you remove it, it appears to stick around
- very, very odd */
- [[NSApp mainMenu] addItem:appleMenuItem];
- [appleMenuController controlMenu:appleMenu];
- [[NSApp mainMenu] removeItem:appleMenuItem];
+ [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Quit " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+
+
+ /* Put menu into the menubar */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+ [menuItem setSubmenu:appleMenu];
+ [[NSApp mainMenu] addItem:menuItem];
+
+ /* Tell the application object that this is now the application menu */
+ [NSApp setAppleMenu:appleMenu];
+
+ /* Finally give up our references to the objects */
[appleMenu release];
- [appleMenuItem release];
+ [menuItem release];
}
/* Create a window menu */
-void setupWindowMenu(void)
+static void setupWindowMenu(void)
{
- NSMenu *windowMenu;
- NSMenuItem *windowMenuItem;
- NSMenuItem *menuItem;
-
+ NSMenu *windowMenu;
+ NSMenuItem *windowMenuItem;
+ NSMenuItem *menuItem;
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
@@ -169,7 +189,7 @@
}
/* Replacement for NSApplicationMain */
-void CustomApplicationMain (argc, argv)
+static void CustomApplicationMain (argc, argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SDLMain *sdlMain;
@@ -190,9 +210,9 @@
/* Set up the menubar */
[NSApp setMainMenu:[[NSMenu alloc] init]];
- setupAppleMenu();
+ setApplicationMenu();
setupWindowMenu();
-
+
/* Create SDLMain and make it the app delegate */
sdlMain = [[SDLMain alloc] init];
[NSApp setDelegate:sdlMain];
@@ -216,7 +236,7 @@
#if SDL_USE_NIB_FILE
/* Set the main menu to contain the real app name instead of "SDL App" */
- [self fixMenu:[NSApp mainMenu] withAppName:[[NSProcessInfo processInfo] processName]];
+ [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
#endif
/* Hand off to main application code */
@@ -284,16 +304,12 @@
/* This is passed if we are launched by double-clicking */
if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
gArgc = 1;
- gFinderLaunch = YES;
+ gFinderLaunch = YES;
} else {
gArgc = argc;
- gFinderLaunch = NO;
+ gFinderLaunch = NO;
}
- gArgv = (char**) malloc (sizeof(*gArgv) * (gArgc+1));
- assert (gArgv != NULL);
- for (i = 0; i < gArgc; i++)
- gArgv[i] = argv[i];
- gArgv[i] = NULL;
+ gArgv = argv;
#if SDL_USE_NIB_FILE
[SDLApplication poseAsClass:[NSApplication class]];