// 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!
 
}