1//	SDLMain.M - main entry point for a Cocoa-ized SDL app
2
3
4
5
6#import "SDL_compat.h"
7#import "SDLMain.h"
8#import <sys/param.h> /* for MAXPATHLEN */
9#import <unistd.h>
10
11#import "host.h"
12
13
14
15
16#define UNUSED(param) ((void)param)
17
18
19
20
21static int		gArgc;
22static char		**gArgv;
23static bool		gFinderLaunch;
24static bool		gCalledAppMainline(false);
25static char*	gConfigFile(NULL);
26
27
28
29
30
31
32
33
34//	The main class of the application, the application's delegate.
35@implementation SDLMain
36
37
38
39
40//	Catch document open requests.
41//	Files are added to gArgv, so to the app, they'll look like command line arguments.
42//	This message may be received multiple times to open several docs on launch.
43//	This message is ignored once the app's mainline has been called.
44- (BOOL) application: (NSApplication *) theApplication openFile: (NSString *) filename {
45	UNUSED(theApplication);
46
47	size_t		filenamelen;
48	const char*	configfile;
49	char**		argv;
50
51	if (gCalledAppMainline)
52		//	The pplication has already been started, ignore this document.
53		return(false);
54
55	if (!gFinderLaunch)
56		//	Command line arguments have been passed.
57		return(false);
58
59	//	The gFinderLaunch is set, thus argv was "<app> -psn <number>" and gArgv now is "<app>".
60	//	As there is space left in original agrv to now hold "<app> -c <config>".
61
62	BOOL			isDir;
63	NSFileManager*	fileManager = [NSFileManager defaultManager];
64	if ([fileManager fileExistsAtPath: filename isDirectory: &isDir]) {
65		if (isDir) {
66			NSString*	configfilename;
67
68			configfilename = [filename stringByAppendingPathComponent: @ARANYMCONFIG];
69			if ([fileManager fileExistsAtPath: configfilename]) {
70				filename = configfilename;
71			} else {
72				[configfilename release];
73				configfilename = [filename stringByAppendingPathComponent: @"config"];
74				if ([fileManager fileExistsAtPath: configfilename]) {
75					filename = configfilename;
76				} else {
77					[configfilename release];
78					return(false);
79				}
80			}
81		}
82
83		//	Allocate memory to keep the config file name.
84		configfile = [filename UTF8String];
85		filenamelen = SDL_strlen(configfile) + 1;
86		gConfigFile = (char *)SDL_malloc(filenamelen);
87		if (gConfigFile == NULL)
88			return(false);
89		SDL_strlcpy(gConfigFile, configfile, filenamelen);
90
91		//	Allocate memory to hold the new argument pointers.
92		argv = (char**)SDL_malloc(4 * sizeof(char*));
93		if (argv == NULL) {
94			SDL_free(gConfigFile);
95			gConfigFile = NULL;
96			return(false);
97		}
98
99		//	Build the "<app> -c <cofing>" arguments.
100		argv[0] = gArgv[0];
101		argv[1] = "-c";
102		argv[2] = gConfigFile;
103		argv[3] = NULL;
104
105		//	Set the new into the global arguments.
106		gArgv = argv;
107		gArgc = 3;
108
109		//	ARAnyM can only handle a single config file, thus this flag is set to ignore further files.
110		gCalledAppMainline = true;
111	}
112	return(true);
113}
114
115
116
117
118//	Called when the internal event loop has just started running.
119- (void) applicationDidFinishLaunching: (NSNotification *) aNotification {
120	UNUSED(aNotification);
121	int status;
122
123	//	Remember that application has started.
124	gCalledAppMainline = true;
125	SDL_SetMainReady();
126
127	//	Hand over to main application code.
128	status = SDL_main(gArgc, gArgv);
129
130	//	Terminate the application.
131	//[NSApp terminate: NSApp];
132	//[NSApp stop: self];
133
134	//	Release fake arguments again.
135	if (gConfigFile != NULL) {
136		SDL_free(gArgv);
137		SDL_free(gConfigFile);
138	}
139
140	//	We're done, thank you for playing.
141	exit(status);
142}
143
144
145
146
147//	Called when the application should terminate.
148- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) theApplication {
149	UNUSED(theApplication);
150	//	Post a SDL_QUIT event
151	SDL_Event event;
152	event.type = SDL_QUIT;
153	SDL_PushEvent(&event);
154	//	Cancel the termination, as the SDL_QUIT signal will finally lead to an exit() call.
155	return(NSTerminateCancel);
156}
157
158
159
160
161//	The user selected the "Preferencs..." menu entry.
162- (IBAction) showPrefs: (id) sender {
163	UNUSED(sender);
164	SDL_Event event;
165	event.type = SDL_KEYDOWN;
166	event.key.keysym.sym = bx_options.hotkeys.setup.sym;
167	event.key.keysym.mod = bx_options.hotkeys.setup.mod;
168	SDL_PushEvent(&event);
169}
170
171
172
173
174//	The user selected the "Fullscreen" menu entry.
175- (IBAction) makeFullscreen: (id) sender {
176	UNUSED(sender);
177	SDL_Event event;
178	event.type = SDL_KEYDOWN;
179	event.key.keysym.sym = bx_options.hotkeys.fullscreen.sym;
180	event.key.keysym.mod = bx_options.hotkeys.fullscreen.mod;
181	SDL_PushEvent(&event);
182}
183
184
185
186
187//	The user selected the "Screenshot" menu entry.
188- (IBAction) makeScreenshot: (id) sender {
189	UNUSED(sender);
190	SDL_Event event;
191	event.type = SDL_KEYDOWN;
192	event.key.keysym.sym = bx_options.hotkeys.screenshot.sym;
193	event.key.keysym.mod = bx_options.hotkeys.screenshot.mod;
194	SDL_PushEvent(&event);
195}
196
197
198
199
200//	The user selected the "Reboot" menu entry */
201- (IBAction) reboot: (id) sender {
202	UNUSED(sender);
203	SDL_Event event;
204	event.type = SDL_KEYDOWN;
205	event.key.keysym.sym = bx_options.hotkeys.reboot.sym;
206	event.key.keysym.mod = bx_options.hotkeys.reboot.mod;
207	SDL_PushEvent(&event);
208}
209
210
211
212
213//	The user selected the "Debug" menu entry.
214- (IBAction) debug: (id) sender {
215	UNUSED(sender);
216	SDL_Event event;
217	event.type = SDL_KEYDOWN;
218	event.key.keysym.sym = bx_options.hotkeys.debug.sym;
219	event.key.keysym.mod = bx_options.hotkeys.debug.mod;
220	SDL_PushEvent(&event);
221}
222
223
224
225
226@end
227
228
229
230
231#ifdef main
232	#undef main
233#endif
234
235
236
237
238static int IsRootCwd(void)
239{
240    char buf[MAXPATHLEN];
241    char *cwd = getcwd(buf, sizeof (buf));
242    return cwd != NULL && strcmp(cwd, "/") == 0;
243}
244
245static int IsFinderLaunch(int argc, char **argv)
246{
247    /* -psn_XXX is passed if we are launched from Finder, SOMETIMES */
248    if ( (argc >= 2) && (strncmp(argv[1], "-psn", 4) == 0) ) {
249        return 1;
250    } else if ((argc == 1) && IsRootCwd()) {
251        /* we might still be launched from the Finder; on 10.9+, you might not
252        get the -psn command line anymore. If there's no
253        command line, and if our current working directory is "/", it
254        might as well be a Finder launch. */
255        return 1;
256    }
257    return 0;  /* not a Finder launch. */
258}
259
260
261//	Main entry point to executable.
262int main (int argc, char **argv) {
263	//	Copy the arguments into a global variable.
264
265	//	This is passed if we are launched by double-clicking.
266	if (IsFinderLaunch(argc, argv)) {
267		gArgc = 1;
268		gArgv = argv;
269		gArgv[1] = NULL;
270		gFinderLaunch = true;
271	} else {
272		gArgc = argc;
273		gArgv = argv;
274		gFinderLaunch = false;
275	}
276
277	NSApplicationMain(argc, const_cast<const char**>(argv));
278
279	return(0);
280}
281