Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 4 | pmbaty | 1 | // osx-sdlmain.m -- main entry point for our Cocoaized SDL app  | 
        
| 2 | pmbaty | 2 | |
| 4 | pmbaty | 3 | #import <Cocoa/Cocoa.h> | 
        
| 4 | #include "string.h"  | 
        ||
| 2 | pmbaty | 5 | #include "SDL.h" | 
        
| 6 | |||
| 7 | |||
| 4 | pmbaty | 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;  | 
        ||
| 2 | pmbaty | 12 | |
| 13 | |||
| 4 | pmbaty | 14 | @interface SDLMainAppDelegate : NSObject  | 
        
| 15 | - (void) applicationDidFinishLaunching: (NSNotification *) notification;  | 
        ||
| 16 | - (BOOL) application: (NSApplication *) the_app openFile: (NSString *) filename;  | 
        ||
| 17 | @end | 
        ||
| 2 | pmbaty | 18 | |
| 4 | pmbaty | 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;  | 
        ||
| 2 | pmbaty | 22 | @end | 
        
| 23 | |||
| 24 | @interface NSApplication (SDLApplication)  | 
        ||
| 4 | pmbaty | 25 | - (void) quitMenuCommand: (id) sender;  | 
        
| 26 | - (void) fullscreenMenuCommand: (id) sender;  | 
        ||
| 27 | - (void) visitwebsiteMenuCommand: (id) sender;  | 
        ||
| 2 | pmbaty | 28 | @end | 
        
| 29 | |||
| 4 | pmbaty | 30 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  | 
        
| 31 | |||
| 2 | pmbaty | 32 | @implementation NSApplication (SDLApplication)  | 
        
| 4 | pmbaty | 33 | |
| 34 | - (void) quitMenuCommand: (id) sender  | 
        ||
| 2 | pmbaty | 35 | { | 
        
| 4 | pmbaty | 36 | // this functin is invoked when the Quit menu item is clicked  | 
        
| 2 | pmbaty | 37 | |
| 4 | pmbaty | 38 | SDL_Event event;  | 
        
| 39 | event.type = SDL_QUIT;  | 
        ||
| 40 | SDL_PushEvent (&event); // post a SDL_QUIT event  | 
        ||
| 2 | pmbaty | 41 | } | 
        
| 42 | |||
| 43 | |||
| 4 | pmbaty | 44 | - (void) fullscreenMenuCommand: (id) sender  | 
        
| 2 | pmbaty | 45 | { | 
        
| 4 | pmbaty | 46 | // this functin is invoked when the Enter Full Screen menu item is clicked  | 
        
| 47 | |||
| 48 | SDL_Event event;  | 
        ||
| 2 | pmbaty | 49 | |
| 4 | pmbaty | 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  | 
        ||
| 2 | pmbaty | 62 | } | 
        
| 63 | |||
| 4 | pmbaty | 64 | - (void) visitwebsiteMenuCommand: (id) sender  | 
        
| 2 | pmbaty | 65 | { | 
        
| 4 | pmbaty | 66 | // this functin is invoked when the Visit Website menu item is clicked  | 
        
| 2 | pmbaty | 67 | |
| 4 | pmbaty | 68 | [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: @"http://www.pmbaty.com/rick/"]]; // visit the website!  | 
        
| 69 | } | 
        ||
| 2 | pmbaty | 70 | |
| 4 | pmbaty | 71 | @end | 
        
| 2 | pmbaty | 72 | |
| 4 | pmbaty | 73 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  | 
        
| 2 | pmbaty | 74 | |
| 4 | pmbaty | 75 | @implementation SDLMainAppDelegate  | 
        
| 2 | pmbaty | 76 | |
| 4 | pmbaty | 77 | - (void) applicationDidFinishLaunching: (NSNotification *) notification  | 
        
| 78 | { | 
        ||
| 79 | // this function is called when the internal event loop has just started running  | 
        ||
| 2 | pmbaty | 80 | |
| 4 | pmbaty | 81 | int status;  | 
        
| 2 | pmbaty | 82 | |
| 4 | pmbaty | 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  | 
        ||
| 2 | pmbaty | 85 | |
| 4 | pmbaty | 86 | exit (status); // when SDL_main returns, we can tell Cocoa to quit  | 
        
| 2 | pmbaty | 87 | } | 
        
| 88 | |||
| 4 | pmbaty | 89 | |
| 90 | - (BOOL) application: (NSApplication *) the_app openFile: (NSString *) filename  | 
        ||
| 2 | pmbaty | 91 | { | 
        
| 4 | pmbaty | 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).  | 
        ||
| 2 | pmbaty | 96 | |
| 4 | pmbaty | 97 | char **new_argv;  | 
        
| 2 | pmbaty | 98 | |
| 4 | pmbaty | 99 | if (has_app_started)  | 
        
| 100 | return (FALSE); // if the app has started, then argc and argv can no longer be modified  | 
        ||
| 2 | pmbaty | 101 | |
| 4 | pmbaty | 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  | 
        ||
| 2 | pmbaty | 114 | } | 
        
| 4 | pmbaty | 115 | @end | 
        
| 2 | pmbaty | 116 | |
| 4 | pmbaty | 117 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  | 
        
| 2 | pmbaty | 118 | |
| 119 | |||
| 4 | pmbaty | 120 | #ifdef main  | 
        
| 121 | #undef main  | 
        ||
| 2 | pmbaty | 122 | #endif  | 
        
| 123 | |||
| 124 | |||
| 4 | pmbaty | 125 | int main (int argc, char **argv)  | 
        
| 2 | pmbaty | 126 | { | 
        
| 4 | pmbaty | 127 | // OS/X program entrypoint  | 
        
| 2 | pmbaty | 128 | |
| 4 | pmbaty | 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;  | 
        ||
| 2 | pmbaty | 136 | |
| 4 | pmbaty | 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;  | 
        ||
| 2 | pmbaty | 146 | |
| 4 | pmbaty | 147 | // allocate an autorelease pool and start Cocoa  | 
        
| 148 | pool = [[NSAutoreleasePool alloc] init];  | 
        ||
| 2 | pmbaty | 149 | |
| 4 | pmbaty | 150 | // ensure the application object is initialised (FIXME: is this necessary ?)  | 
        
| 151 | [NSApplication sharedApplication];  | 
        ||
| 2 | pmbaty | 152 | |
| 4 | pmbaty | 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  | 
        ||
| 2 | pmbaty | 160 | |
| 4 | pmbaty | 161 | // create the application menu and populate it  | 
        
| 162 | [NSApp setMainMenu: [[NSMenu alloc] init]];  | 
        ||
| 2 | pmbaty | 163 | |
| 4 | pmbaty | 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: (NSAlternateKeyMask|NSCommandKeyMask)];  | 
        ||
| 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"];  | 
        ||
| 2 | pmbaty | 173 | |
| 4 | pmbaty | 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  | 
        ||
| 2 | pmbaty | 181 | |
| 4 | pmbaty | 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];  | 
        ||
| 2 | pmbaty | 189 | |
| 4 | pmbaty | 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  | 
        ||
| 2 | pmbaty | 197 | |
| 4 | pmbaty | 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];  | 
        ||
| 2 | pmbaty | 206 | |
| 4 | pmbaty | 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  | 
        ||
| 2 | pmbaty | 214 | |
| 4 | pmbaty | 215 | // create the SDLMain object and make it the app delegate  | 
        
| 216 | sdlmain_delegate = [[SDLMainAppDelegate alloc] init];  | 
        ||
| 217 | [NSApp setDelegate: (id) sdlmain_delegate];  | 
        ||
| 2 | pmbaty | 218 | |
| 4 | pmbaty | 219 | // start the Cocoa event loop  | 
        
| 220 | [NSApp run];  | 
        ||
| 2 | pmbaty | 221 | |
| 4 | pmbaty | 222 | // finally give up our references to the objects when the Cocoa event loop exits  | 
        
| 223 | [sdlmain_delegate release];  | 
        ||
| 224 | [pool release];  | 
        ||
| 2 | pmbaty | 225 | |
| 4 | pmbaty | 226 | return (0); // e finita la comedia!  | 
        
| 2 | pmbaty | 227 | } |