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 | |
7 | pmbaty | 68 | [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: @"https://www.pmbaty.com/rick/"]]; // visit the website! |
4 | pmbaty | 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"]; |
||
7 | pmbaty | 169 | [[submenu addItemWithTitle: @"Hide Others" action: @selector(hideOtherApplications:) keyEquivalent: @"h"] setKeyEquivalentModifierMask: (NSEventModifierFlagOption|NSEventModifierFlagCommand)]; |
4 | pmbaty | 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 | } |