Subversion Repositories Games.Rick Dangerous

Rev

Rev 4 | Blame | Last modification | View Log | Download | RSS feed

  1. // osx-sdlmain.m -- main entry point for our Cocoaized SDL app
  2.  
  3. #import <Cocoa/Cocoa.h>
  4. #include "string.h"
  5. #include "SDL.h"
  6.  
  7.  
  8. // global variables used in this module only
  9. static int global_argc = 0;
  10. static char **global_argv = NULL;
  11. static BOOL has_app_started = FALSE;
  12.  
  13.  
  14. @interface SDLMainAppDelegate : NSObject
  15. - (void) applicationDidFinishLaunching: (NSNotification *) notification;
  16. - (BOOL) application: (NSApplication *) the_app openFile: (NSString *) filename;
  17. @end
  18.  
  19. @interface NSApplication (SDL_Missing_Methods)
  20. // 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
  21. - (void) setAppleMenu: (NSMenu *) menu;
  22. @end
  23.  
  24. @interface NSApplication (SDLApplication)
  25. - (void) quitMenuCommand: (id) sender;
  26. - (void) fullscreenMenuCommand: (id) sender;
  27. - (void) visitwebsiteMenuCommand: (id) sender;
  28. @end
  29.  
  30. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  31.  
  32. @implementation NSApplication (SDLApplication)
  33.  
  34. - (void) quitMenuCommand: (id) sender
  35. {
  36.    // this functin is invoked when the Quit menu item is clicked
  37.  
  38.    SDL_Event event;
  39.    event.type = SDL_QUIT;
  40.    SDL_PushEvent (&event); // post a SDL_QUIT event
  41. }
  42.  
  43.  
  44. - (void) fullscreenMenuCommand: (id) sender
  45. {
  46.     // this functin is invoked when the Enter Full Screen menu item is clicked
  47.    
  48.     SDL_Event event;
  49.  
  50.     event.type = SDL_KEYDOWN;
  51.     event.key.keysym.sym = SDLK_LALT;
  52.     SDL_PushEvent (&event); // post a SDL_KEY event that simulates pressing the left ALT key
  53.     event.type = SDL_KEYDOWN;
  54.     event.key.keysym.sym = SDLK_RETURN;
  55.     SDL_PushEvent (&event); // post a SDL_KEY event that simulates pressing the main ENTER key
  56.     event.type = SDL_KEYUP;
  57.     event.key.keysym.sym = SDLK_RETURN;
  58.     SDL_PushEvent (&event); // post a SDL_KEY event that simulates releasing the main ENTER key
  59.     event.type = SDL_KEYUP;
  60.     event.key.keysym.sym = SDLK_LALT;
  61.     SDL_PushEvent (&event); // post a SDL_KEY event that simulates releasing the left ALT key
  62. }
  63.  
  64. - (void) visitwebsiteMenuCommand: (id) sender
  65. {
  66.    // this functin is invoked when the Visit Website menu item is clicked
  67.  
  68.    [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: @"https://www.pmbaty.com/rick/"]]; // visit the website!
  69. }
  70.  
  71. @end
  72.  
  73. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  74.  
  75. @implementation SDLMainAppDelegate
  76.  
  77. - (void) applicationDidFinishLaunching: (NSNotification *) notification
  78. {
  79.    // this function is called when the internal event loop has just started running
  80.  
  81.    int status;
  82.  
  83.    has_app_started = TRUE; // remember the app has started (so we can no longer change argc and argv)
  84.    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
  85.  
  86.    exit (status); // when SDL_main returns, we can tell Cocoa to quit
  87. }
  88.  
  89.  
  90. - (BOOL) application: (NSApplication *) the_app openFile: (NSString *) filename
  91. {
  92.     // this function catches document open requests and appends them to global argc and argv arrays, so they look like a command-line argument.
  93.     // 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.
  94.     // You need to have a CFBundleDocumentsType section in your Info.plist to get this message.
  95.     // Once the app's main loop has started, this message can no longer be used (since it has already parsed its command-line arguments).
  96.    
  97.     char **new_argv;
  98.    
  99.     if (has_app_started)
  100.         return (FALSE); // if the app has started, then argc and argv can no longer be modified
  101.    
  102.     // reallocate the global argv array to hold one parameter more
  103.     new_argv = (char **) realloc (global_argv, (global_argc + 2) * sizeof (char *));
  104.     if (new_argv == NULL)
  105.         return (FALSE); // on realloc() failure, give up
  106.     global_argv = new_argv;
  107.     global_argc++;
  108.    
  109.     // now store the filename we're opening as a new command-line argument
  110.     global_argv[global_argc - 1] = strdup ([filename UTF8String]);
  111.     global_argv[global_argc] = NULL;
  112.    
  113.     return (TRUE); // message was handled successfully
  114. }
  115. @end
  116.  
  117. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  118.  
  119.  
  120. #ifdef main
  121. #undef main
  122. #endif
  123.  
  124.  
  125. int main (int argc, char **argv)
  126. {
  127.    // OS/X program entrypoint
  128.  
  129.    SDLMainAppDelegate *sdlmain_delegate;
  130.    NSAutoreleasePool *pool;
  131.    NSMenu *submenu;
  132.    NSMenuItem *menu_item;
  133.    const NSDictionary *infoplist_dict;
  134.    NSString *application_name;
  135.    int arg_index;
  136.  
  137.    // copy the program arguments into global variables (discard arguments 1-n if we were launched by double-clicking)
  138.    if ((argc >= 2) && (strncmp (argv[1], "-psn", 4) == 0))
  139.       global_argc = 1; // we were launched by Finder, ignore all arguments except the executable name
  140.    else
  141.       global_argc = argc; // we were NOT launched by Finder (most probably by a shell), copy all arguments
  142.    global_argv = (char **) malloc ((global_argc + 1) * sizeof (char *));
  143.    for (arg_index = 0; arg_index < global_argc; arg_index++)
  144.       global_argv[arg_index] = argv[arg_index];
  145.    global_argv[arg_index] = NULL;
  146.  
  147.    // allocate an autorelease pool and start Cocoa
  148.    pool = [[NSAutoreleasePool alloc] init];
  149.  
  150.    // ensure the application object is initialised (FIXME: is this necessary ?)
  151.    [NSApplication sharedApplication];
  152.  
  153.    // figure out the application name, either from the Info.plist, or from the process name
  154.    application_name = NULL;
  155.    infoplist_dict = (const NSDictionary *) CFBundleGetInfoDictionary (CFBundleGetMainBundle ()); // try to get the bundle's Info.plist
  156.    if (infoplist_dict)
  157.       application_name = [infoplist_dict objectForKey: @"CFBundleName"]; // if it has, read the CFBundleName key value from it
  158.    if ((application_name == NULL) || ([application_name length] == 0))
  159.       application_name = [[NSProcessInfo processInfo] processName]; // else, or if the bundle name is empty, use the process name
  160.  
  161.    // create the application menu and populate it
  162.    [NSApp setMainMenu: [[NSMenu alloc] init]];
  163.  
  164.    // create the [AppName] menu
  165.    submenu = [[NSMenu alloc] initWithTitle: @""];
  166.    [submenu addItemWithTitle: [@"About " stringByAppendingString: application_name] action: @selector(orderFrontStandardAboutPanel:) keyEquivalent: @""];
  167.    [submenu addItem: [NSMenuItem separatorItem]];
  168.    [submenu addItemWithTitle: [@"Hide " stringByAppendingString: application_name] action: @selector(hide:) keyEquivalent: @"h"];
  169.    [[submenu addItemWithTitle: @"Hide Others" action: @selector(hideOtherApplications:) keyEquivalent: @"h"] setKeyEquivalentModifierMask: (NSEventModifierFlagOption|NSEventModifierFlagCommand)];
  170.    [submenu addItemWithTitle: @"Show All" action: @selector(unhideAllApplications:) keyEquivalent: @""];
  171.    [submenu addItem: [NSMenuItem separatorItem]];
  172.    [submenu addItemWithTitle: [@"Quit " stringByAppendingString: application_name] action: @selector(quitMenuCommand:) keyEquivalent: @"q"];
  173.  
  174.    // put the [AppName] menu in the menubar
  175.    menu_item = [[NSMenuItem alloc] initWithTitle: @"" action: nil keyEquivalent: @""];
  176.    [menu_item setSubmenu: submenu];
  177.    [[NSApp mainMenu] addItem: menu_item]; // put menu into the menubar
  178.    [NSApp setAppleMenu: submenu]; // tell the application object that this is now the application menu
  179.    [menu_item release]; // finally give up our references to the objects
  180.    [submenu release]; // finally give up our references to the objects
  181.  
  182.    // create a [Window] menu
  183.    submenu = [[NSMenu alloc] initWithTitle: @"Window"];
  184.    menu_item = [[NSMenuItem alloc] initWithTitle: @"Minimize" action: @selector(performMiniaturize:) keyEquivalent: @"m"];
  185.    [submenu addItem: menu_item];
  186.    menu_item = [[NSMenuItem alloc] initWithTitle: @"Enter Full Screen" action: @selector(fullscreenMenuCommand:) keyEquivalent: @"f"];
  187.    [submenu addItem: menu_item];
  188.    [menu_item release];
  189.  
  190.    // put the [Window] menu in the menubar
  191.    menu_item = [[NSMenuItem alloc] initWithTitle: @"Window" action: nil keyEquivalent: @""];
  192.    [menu_item setSubmenu: submenu];
  193.    [[NSApp mainMenu] addItem: menu_item]; // put menu into the menubar
  194.    [NSApp setWindowsMenu: submenu]; // tell the application object that this is now the window menu
  195.    [menu_item release]; // finally give up our references to the objects
  196.    [submenu release]; // finally give up our references to the objects
  197.  
  198.    // create a [Help] menu
  199.    submenu = [[NSMenu alloc] initWithTitle: @"Help"];
  200.    [submenu addItem: [NSMenuItem separatorItem]];
  201.    menu_item = [[NSMenuItem alloc] initWithTitle: @"How to play" action: @selector(visitwebsiteMenuCommand:) keyEquivalent: @"?"];
  202.    [submenu addItem: menu_item];
  203.    menu_item = [[NSMenuItem alloc] initWithTitle: @"Visit Website" action: @selector(visitwebsiteMenuCommand:) keyEquivalent: @"w"];
  204.    [submenu addItem: menu_item];
  205.    [menu_item release];
  206.  
  207.    // put the [Help] menu in the menubar
  208.    menu_item = [[NSMenuItem alloc] initWithTitle: @"Help" action: nil keyEquivalent: @""];
  209.    [menu_item setSubmenu: submenu];
  210.    [[NSApp mainMenu] addItem: menu_item]; // put menu into the menubar
  211.    [NSApp setHelpMenu: submenu]; // tell the application object that this is now the help menu
  212.    [menu_item release]; // finally give up our references to the objects
  213.    [submenu release]; // finally give up our references to the objects
  214.  
  215.    // create the SDLMain object and make it the app delegate
  216.    sdlmain_delegate = [[SDLMainAppDelegate alloc] init];
  217.    [NSApp setDelegate: (id) sdlmain_delegate];
  218.  
  219.    // start the Cocoa event loop
  220.    [NSApp run];
  221.  
  222.    // finally give up our references to the objects when the Cocoa event loop exits
  223.    [sdlmain_delegate release];
  224.    [pool release];
  225.  
  226.    return (0); // e finita la comedia!
  227. }
  228.