]> icculus.org git repositories - btb/d2x.git/blob - arch/cocoa/SDLMain.m
added XCode project files
[btb/d2x.git] / arch / cocoa / SDLMain.m
1 /*   SDLMain.m - main entry point for our Cocoa-ized SDL app
2        Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
3        Non-NIB-Code & other changes: Max Horn <max@quendi.de>
4
5     Feel free to customize this file to suit your needs
6 */
7
8 #import "SDL.h"
9 #import "SDLMain.h"
10 #import <sys/param.h> /* for MAXPATHLEN */
11 #import <unistd.h>
12
13 /* Use this flag to determine whether we use SDLMain.nib or not */
14 #define         SDL_USE_NIB_FILE        0
15
16
17 static int    gArgc;
18 static char  **gArgv;
19 static BOOL   gFinderLaunch;
20
21 #if SDL_USE_NIB_FILE
22 /* A helper category for NSString */
23 @interface NSString (ReplaceSubString)
24 - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
25 @end
26 #else
27 /* An internal Apple class used to setup Apple menus */
28 @interface NSAppleMenuController:NSObject {}
29 - (void)controlMenu:(NSMenu *)aMenu;
30 @end
31 #endif
32
33 @interface SDLApplication : NSApplication
34 @end
35
36 @implementation SDLApplication
37 /* Invoked from the Quit menu item */
38 - (void)terminate:(id)sender
39 {
40     /* Post a SDL_QUIT event */
41     SDL_Event event;
42     event.type = SDL_QUIT;
43     SDL_PushEvent(&event);
44 }
45 @end
46
47
48 /* The main class of the application, the application's delegate */
49 @implementation SDLMain
50
51 /* Set the working directory to the .app's parent directory */
52 - (void) setupWorkingDirectory:(BOOL)shouldChdir
53 {
54     char parentdir[MAXPATHLEN];
55     char *c;
56     
57     strncpy ( parentdir, gArgv[0], sizeof(parentdir) );
58     c = (char*) parentdir;
59
60     while (*c != '\0')     /* go to end */
61         c++;
62     
63     while (*c != '/')      /* back up to parent */
64         c--;
65     
66     *c++ = '\0';             /* cut off last part (binary name) */
67   
68     if (shouldChdir)
69     {
70       assert ( chdir (parentdir) == 0 );   /* chdir to the binary app's parent */
71       assert ( chdir ("../../../") == 0 ); /* chdir to the .app's parent */
72     }
73 }
74
75 #if SDL_USE_NIB_FILE
76
77 /* Fix menu to contain the real app name instead of "SDL App" */
78 - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
79 {
80     NSRange aRange;
81     NSEnumerator *enumerator;
82     NSMenuItem *menuItem;
83
84     aRange = [[aMenu title] rangeOfString:@"SDL App"];
85     if (aRange.length != 0)
86         [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
87
88     enumerator = [[aMenu itemArray] objectEnumerator];
89     while ((menuItem = [enumerator nextObject]))
90     {
91         aRange = [[menuItem title] rangeOfString:@"SDL App"];
92         if (aRange.length != 0)
93             [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
94         if ([menuItem hasSubmenu])
95             [self fixMenu:[menuItem submenu] withAppName:appName];
96     }
97     [ aMenu sizeToFit ];
98 }
99
100 #else
101
102 void setupAppleMenu(void)
103 {
104     /* warning: this code is very odd */
105     NSAppleMenuController *appleMenuController;
106     NSMenu *appleMenu;
107     NSMenuItem *appleMenuItem;
108
109     appleMenuController = [[NSAppleMenuController alloc] init];
110     appleMenu = [[NSMenu alloc] initWithTitle:@""];
111     appleMenuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
112     
113     [appleMenuItem setSubmenu:appleMenu];
114
115     /* yes, we do need to add it and then remove it --
116        if you don't add it, it doesn't get displayed
117        if you don't remove it, you have an extra, titleless item in the menubar
118        when you remove it, it appears to stick around
119        very, very odd */
120     [[NSApp mainMenu] addItem:appleMenuItem];
121     [appleMenuController controlMenu:appleMenu];
122     [[NSApp mainMenu] removeItem:appleMenuItem];
123     [appleMenu release];
124     [appleMenuItem release];
125 }
126
127 /* Create a window menu */
128 void setupWindowMenu(void)
129 {
130     NSMenu              *windowMenu;
131     NSMenuItem  *windowMenuItem;
132     NSMenuItem  *menuItem;
133
134
135     windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
136     
137     /* "Minimize" item */
138     menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
139     [windowMenu addItem:menuItem];
140     [menuItem release];
141     
142     /* Put menu into the menubar */
143     windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
144     [windowMenuItem setSubmenu:windowMenu];
145     [[NSApp mainMenu] addItem:windowMenuItem];
146     
147     /* Tell the application object that this is now the window menu */
148     [NSApp setWindowsMenu:windowMenu];
149
150     /* Finally give up our references to the objects */
151     [windowMenu release];
152     [windowMenuItem release];
153 }
154
155 /* Replacement for NSApplicationMain */
156 void CustomApplicationMain (argc, argv)
157 {
158     NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
159     SDLMain                             *sdlMain;
160
161     /* Ensure the application object is initialised */
162     [SDLApplication sharedApplication];
163     
164     /* Set up the menubar */
165     [NSApp setMainMenu:[[NSMenu alloc] init]];
166     setupAppleMenu();
167     setupWindowMenu();
168     
169     /* Create SDLMain and make it the app delegate */
170     sdlMain = [[SDLMain alloc] init];
171     [NSApp setDelegate:sdlMain];
172     
173     /* Start the main event loop */
174     [NSApp run];
175     
176     [sdlMain release];
177     [pool release];
178 }
179
180 #endif
181
182 /* Called when the internal event loop has just started running */
183 - (void) applicationDidFinishLaunching: (NSNotification *) note
184 {
185     int status;
186
187     /* Set the working directory to the .app's parent directory */
188     [self setupWorkingDirectory:gFinderLaunch];
189
190 #if SDL_USE_NIB_FILE
191     /* Set the main menu to contain the real app name instead of "SDL App" */
192     [self fixMenu:[NSApp mainMenu] withAppName:[[NSProcessInfo processInfo] processName]];
193 #endif
194
195     /* Hand off to main application code */
196     status = SDL_main (gArgc, gArgv);
197
198     /* We're done, thank you for playing */
199     exit(status);
200 }
201 @end
202
203
204 @implementation NSString (ReplaceSubString)
205
206 - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
207 {
208     unsigned int bufferSize;
209     unsigned int selfLen = [self length];
210     unsigned int aStringLen = [aString length];
211     unichar *buffer;
212     NSRange localRange;
213     NSString *result;
214
215     bufferSize = selfLen + aStringLen - aRange.length;
216     buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
217     
218     /* Get first part into buffer */
219     localRange.location = 0;
220     localRange.length = aRange.location;
221     [self getCharacters:buffer range:localRange];
222     
223     /* Get middle part into buffer */
224     localRange.location = 0;
225     localRange.length = aStringLen;
226     [aString getCharacters:(buffer+aRange.location) range:localRange];
227      
228     /* Get last part into buffer */
229     localRange.location = aRange.location + aRange.length;
230     localRange.length = selfLen - localRange.location;
231     [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
232     
233     /* Build output string */
234     result = [NSString stringWithCharacters:buffer length:bufferSize];
235     
236     NSDeallocateMemoryPages(buffer, bufferSize);
237     
238     return result;
239 }
240
241 @end
242
243
244
245 #ifdef main
246 #  undef main
247 #endif
248
249
250 /* Main entry point to executable - should *not* be SDL_main! */
251 int main (int argc, char **argv)
252 {
253
254     /* Copy the arguments into a global variable */
255     int i;
256     
257     /* This is passed if we are launched by double-clicking */
258     if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
259         gArgc = 1;
260         gFinderLaunch = YES;
261     } else {
262         gArgc = argc;
263         gFinderLaunch = NO;
264     }
265     gArgv = (char**) malloc (sizeof(*gArgv) * (gArgc+1));
266     assert (gArgv != NULL);
267     for (i = 0; i < gArgc; i++)
268         gArgv[i] = argv[i];
269     gArgv[i] = NULL;
270
271 #if SDL_USE_NIB_FILE
272     [SDLApplication poseAsClass:[NSApplication class]];
273     NSApplicationMain (argc, argv);
274 #else
275     CustomApplicationMain (argc, argv);
276 #endif
277     return 0;
278 }