// osx-sdlmain.m -- main entry point for our Cocoaized SDL app
#import <Cocoa/Cocoa.h>
#include "SDL.h"
// global variables used in this module only
static int global_argc = 0;
static BOOL has_app_started = FALSE;
@interface SDLMainAppDelegate : NSObject
- (void) applicationDidFinishLaunching: (NSNotification *) notification;
- (BOOL) application: (NSApplication *) the_app openFile: (NSString *) filename;
@end
@interface NSApplication (SDL_Missing_Methods)
//
for some reaon, Apple removed setAppleMenu from the headers in
10.4, but the method still
is there and works.
To avoid warnings, we declare it ourselves here
-
(void
) setAppleMenu:
(NSMenu *
) menu;
@end
@interface NSApplication (SDLApplication)
- (void) quitMenuCommand: (id) sender;
- (void) fullscreenMenuCommand: (id) sender;
- (void) visitwebsiteMenuCommand: (id) sender;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation NSApplication (SDLApplication)
- (void) quitMenuCommand: (id) sender
{
// this functin
is invoked when the
Quit menu item
is clicked
SDL_Event event;
SDL_PushEvent (&event); // post a SDL_QUIT event
}
- (void) fullscreenMenuCommand: (id) sender
{
// this functin
is invoked when the Enter
Full Screen
menu item
is clicked
SDL_Event event;
event.
type = SDL_KEYDOWN;
event.key.keysym.sym = SDLK_LALT;
SDL_PushEvent (&event); // post a SDL_KEY event that simulates pressing the left ALT key
event.
type = SDL_KEYDOWN;
event.key.keysym.sym = SDLK_RETURN;
SDL_PushEvent (&event); // post a SDL_KEY event that simulates pressing the main ENTER key
event.key.keysym.sym = SDLK_RETURN;
SDL_PushEvent (&event); // post a SDL_KEY event that simulates releasing the main ENTER key
event.key.keysym.sym = SDLK_LALT;
SDL_PushEvent (&event); // post a SDL_KEY event that simulates releasing the left ALT key
}
- (void) visitwebsiteMenuCommand: (id) sender
{
// this functin
is invoked when the Visit Website
menu item
is clicked
[[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: @"http://www.pmbaty.com/rick/"]]; // visit the website!
}
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation SDLMainAppDelegate
- (void) applicationDidFinishLaunching: (NSNotification *) notification
{
// this
function is called when the internal event loop has just started running
int status;
has_app_started = TRUE; // remember the app has started (so we can no longer change argc and argv)
status = SDL_main
(global_argc, global_argv
); // only
now that we know Cocoa has finished its business, we can run SDL_main
() and pass it our command-
line arguments
exit
(status
); // when SDL_main returns, we can tell Cocoa to
quit
}
- (BOOL) application: (NSApplication *) the_app openFile: (NSString *) filename
{
// this
function catches document
open requests and appends them to
global argc and argv arrays, so they look like a command-
line argument.
// This lets us notice files when the app was launched by double-clicking a document, or when a document was dragged/dropped on the app's icon.
// You need to have a CFBundleDocumentsType section in your Info.
plist to
get this message.
// Once the app's main loop has started, this message can no longer be used
(since it has already parsed its command-
line arguments
).
if (has_app_started)
return (FALSE); // if the app has started, then argc and argv can no longer be modified
// reallocate the
global argv array to
hold one parameter
more
new_argv =
(char **
) realloc
(global_argv,
(global_argc +
2) * sizeof
(char *
));
return (FALSE); // on realloc() failure, give up
global_argv = new_argv;
global_argc++;
//
now store the filename we're opening as a new command-
line argument
global_argv[global_argc - 1] = strdup ([filename UTF8String]);
global_argv
[global_argc
] =
NULL;
return (TRUE); // message was handled successfully
}
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef main
#undef main
#endif
int main
(int argc,
char **argv
)
{
// OS/X program entrypoint
SDLMainAppDelegate *sdlmain_delegate;
NSAutoreleasePool *pool;
NSMenu *submenu;
NSMenuItem *menu_item;
const NSDictionary *infoplist_dict;
NSString *application_name;
int arg_index;
// copy the program arguments into global variables (discard arguments 1-n if we were launched by double-clicking)
if ((argc >=
2) &&
(strncmp (argv
[1], "-psn",
4) ==
0))
global_argc =
1; // we were launched by Finder, ignore
all arguments except the executable name
else
global_argc = argc; // we were NOT launched by Finder
(most probably by a shell
), copy
all arguments
global_argv =
(char **
) malloc
((global_argc +
1) * sizeof
(char *
));
for (arg_index = 0; arg_index < global_argc; arg_index++)
global_argv[arg_index] = argv[arg_index];
global_argv
[arg_index
] =
NULL;
// allocate an autorelease pool and start Cocoa
pool = [[NSAutoreleasePool alloc] init];
// ensure the application object
is initialised
(FIXME:
is this necessary ?
)
[NSApplication sharedApplication];
//
figure out the application name, either from the Info.
plist, or from the process name
infoplist_dict =
(const NSDictionary *
) CFBundleGetInfoDictionary
(CFBundleGetMainBundle
()); //
try to
get the bundle's Info.
plist
if (infoplist_dict)
application_name = [infoplist_dict objectForKey: @"CFBundleName"]; // if it has, read the CFBundleName key value from it
if ((application_name ==
NULL) ||
([application_name
length] ==
0))
application_name =
[[NSProcessInfo processInfo
] processName
]; //
else, or
if the bundle name
is empty, use the process name
// create the application
menu and populate it
[NSApp setMainMenu: [[NSMenu alloc] init]];
// create the
[AppName
] menu
submenu = [[NSMenu alloc] initWithTitle: @""];
[submenu addItemWithTitle: [@"About " stringByAppendingString: application_name] action: @selector(orderFrontStandardAboutPanel:) keyEquivalent: @""];
[submenu addItem: [NSMenuItem separatorItem]];
[submenu addItemWithTitle: [@"Hide " stringByAppendingString: application_name] action: @selector(hide:) keyEquivalent: @"h"];
[[submenu addItemWithTitle: @"Hide Others" action: @selector(hideOtherApplications:) keyEquivalent: @"h"] setKeyEquivalentModifierMask: (NSAlternateKeyMask|NSCommandKeyMask)];
[submenu addItemWithTitle: @"Show All" action: @selector(unhideAllApplications:) keyEquivalent: @""];
[submenu addItem: [NSMenuItem separatorItem]];
[submenu addItemWithTitle:
[@"
Quit " stringByAppendingString: application_name
] action: @selector
(quitMenuCommand:
) keyEquivalent: @"q"
];
// put the
[AppName
] menu in the menubar
menu_item = [[NSMenuItem alloc] initWithTitle: @"" action: nil keyEquivalent: @""];
[menu_item setSubmenu: submenu];
[[NSApp mainMenu
] addItem: menu_item
]; // put
menu into the menubar
[NSApp setAppleMenu: submenu
]; // tell the application object that this
is now the application
menu
[menu_item release]; // finally give up our references to the objects
[submenu release]; // finally give up our references to the objects
// create a
[Window
] menu
submenu = [[NSMenu alloc] initWithTitle: @"Window"];
menu_item = [[NSMenuItem alloc] initWithTitle: @"Minimize" action: @selector(performMiniaturize:) keyEquivalent: @"m"];
[submenu addItem: menu_item];
menu_item =
[[NSMenuItem alloc
] initWithTitle: @"Enter
Full Screen" action: @selector
(fullscreenMenuCommand:
) keyEquivalent: @"f"
];
[submenu addItem: menu_item];
[menu_item release];
// put the
[Window
] menu in the menubar
menu_item = [[NSMenuItem alloc] initWithTitle: @"Window" action: nil keyEquivalent: @""];
[menu_item setSubmenu: submenu];
[[NSApp mainMenu
] addItem: menu_item
]; // put
menu into the menubar
[NSApp setWindowsMenu: submenu
]; // tell the application object that this
is now the window
menu
[menu_item release]; // finally give up our references to the objects
[submenu release]; // finally give up our references to the objects
submenu = [[NSMenu alloc] initWithTitle: @"Help"];
[submenu addItem: [NSMenuItem separatorItem]];
menu_item = [[NSMenuItem alloc] initWithTitle: @"How to play" action: @selector(visitwebsiteMenuCommand:) keyEquivalent: @"?"];
[submenu addItem: menu_item];
menu_item = [[NSMenuItem alloc] initWithTitle: @"Visit Website" action: @selector(visitwebsiteMenuCommand:) keyEquivalent: @"w"];
[submenu addItem: menu_item];
[menu_item release];
menu_item = [[NSMenuItem alloc] initWithTitle: @"Help" action: nil keyEquivalent: @""];
[menu_item setSubmenu: submenu];
[[NSApp mainMenu
] addItem: menu_item
]; // put
menu into the menubar
[NSApp setHelpMenu: submenu
]; // tell the application object that this
is now the
help menu
[menu_item release]; // finally give up our references to the objects
[submenu release]; // finally give up our references to the objects
// create the SDLMain object and make it the app delegate
sdlmain_delegate = [[SDLMainAppDelegate alloc] init];
[NSApp setDelegate: (id) sdlmain_delegate];
// start the Cocoa event loop
[NSApp run];
// finally give up our references to the objects when the Cocoa event loop exits
[sdlmain_delegate release];
[pool release];
return (0); // e finita la comedia!
}