diff --git a/src/cocoa/i_backend_cocoa.mm b/src/cocoa/i_backend_cocoa.mm index d4c353edd6..675fde1826 100644 --- a/src/cocoa/i_backend_cocoa.mm +++ b/src/cocoa/i_backend_cocoa.mm @@ -144,6 +144,8 @@ char* s_argv[ARGC_MAX]; TArray s_argvStorage; +bool s_restartedFromWADPicker; + bool s_nativeMouse = true; @@ -966,7 +968,9 @@ static ApplicationDelegate* s_applicationDelegate; { ZD_UNUSED(theApplication); - if (0 == [filename length] || s_argc + 2 >= ARGC_MAX) + if (s_restartedFromWADPicker + || 0 == [filename length] + || s_argc + 2 >= ARGC_MAX) { return FALSE; } @@ -1724,8 +1728,15 @@ int main(int argc, char** argv) continue; } - s_argvStorage.Push(argument); - s_argv[s_argc++] = s_argvStorage.Last().LockBuffer(); + if (0 == strcmp(argument, "-wad_picker_restart")) + { + s_restartedFromWADPicker = true; + } + else + { + s_argvStorage.Push(argument); + s_argv[s_argc++] = s_argvStorage.Last().LockBuffer(); + } } NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; diff --git a/src/sdl/i_gui.cpp b/src/sdl/i_gui.cpp index c4202a6b32..2ecdcdb74e 100644 --- a/src/sdl/i_gui.cpp +++ b/src/sdl/i_gui.cpp @@ -71,3 +71,8 @@ bool I_SetCursor(FTexture *cursorpic) } return true; } + +void I_SetMainWindowVisible(bool visible) +{ + +} diff --git a/src/sdl/iwadpicker_cocoa.mm b/src/sdl/iwadpicker_cocoa.mm index 3b414d5e8c..7a6b386239 100644 --- a/src/sdl/iwadpicker_cocoa.mm +++ b/src/sdl/iwadpicker_cocoa.mm @@ -33,9 +33,17 @@ ** */ +#include "cmdlib.h" #include "d_main.h" #include "version.h" +#include "c_cvars.h" +#include "m_argv.h" +#include "m_misc.h" +#include "gameconfigfile.h" #include +#include + +CVAR(String, osx_additional_parameters, "", CVAR_ARCHIVE | CVAR_NOSET | CVAR_GLOBALCONFIG); enum { @@ -107,6 +115,45 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; @end +static NSDictionary* GetKnownFileTypes() +{ + return [NSDictionary dictionaryWithObjectsAndKeys: + @"-file" , @"wad", + @"-file" , @"pk3", + @"-file" , @"zip", + @"-file" , @"pk7", + @"-file" , @"7z", + @"-deh" , @"deh", + @"-bex" , @"bex", + @"-exec" , @"cfg", + @"-playdemo", @"lmp", + nil]; +} + +static NSArray* GetKnownExtensions() +{ + return [GetKnownFileTypes() allKeys]; +} + +@interface NSMutableString(AppendKnownFileType) +- (void)appendKnownFileType:(NSString *)filePath; +@end + +@implementation NSMutableString(AppendKnownFileType) +- (void)appendKnownFileType:(NSString *)filePath +{ + NSString* extension = [[filePath pathExtension] lowercaseString]; + NSString* parameter = [GetKnownFileTypes() objectForKey:extension]; + + if (nil == parameter) + { + return; + } + + [self appendFormat:@"%@ \"%@\" ", parameter, filePath]; +} +@end + // So we can listen for button actions and such we need to have an Obj-C class. @interface IWADPicker : NSObject { @@ -114,13 +161,18 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; NSWindow *window; NSButton *okButton; NSButton *cancelButton; + NSButton *browseButton; + NSTextField *parametersTextField; bool cancelled; } - (void)buttonPressed:(id) sender; +- (void)browseButtonPressed:(id) sender; - (void)doubleClicked:(id) sender; - (void)makeLabel:(NSTextField *)label withString:(const char*) str; - (int)pickIWad:(WadStuff *)wads num:(int) numwads showWindow:(bool) showwin defaultWad:(int) defaultiwad; +- (NSString*)commandLineParameters; +- (void)menuActionSent:(NSNotification*)notification; @end @implementation IWADPicker @@ -134,6 +186,52 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [app stopModal]; } +- (void)browseButtonPressed:(id) sender +{ + NSOpenPanel* openPanel = [NSOpenPanel openPanel]; + [openPanel setAllowsMultipleSelection:YES]; + [openPanel setCanChooseFiles:YES]; + [openPanel setCanChooseDirectories:YES]; + [openPanel setResolvesAliases:YES]; + [openPanel setAllowedFileTypes:GetKnownExtensions()]; + + if (NSOKButton == [openPanel runModal]) + { + NSArray* files = [openPanel URLs]; + NSMutableString* parameters = [NSMutableString string]; + + for (NSUInteger i = 0, ei = [files count]; i < ei; ++i) + { + NSString* filePath = [[files objectAtIndex:i] path]; + BOOL isDirectory = false; + + if ([[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory] && isDirectory) + { + [parameters appendFormat:@"-file \"%@\" ", filePath]; + } + else + { + [parameters appendKnownFileType:filePath]; + } + } + + if ([parameters length] > 0) + { + NSString* newParameters = [parametersTextField stringValue]; + + if ([newParameters length] > 0 + && NO == [newParameters hasSuffix:@" "]) + { + newParameters = [newParameters stringByAppendingString:@" "]; + } + + newParameters = [newParameters stringByAppendingString:parameters]; + + [parametersTextField setStringValue: newParameters]; + } + } +} + - (void)doubleClicked:(id) sender { if ([sender clickedRow] >= 0) @@ -159,20 +257,18 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; cancelled = false; app = [NSApplication sharedApplication]; - id windowTitle = [NSString stringWithFormat:@GAMESIG " %s: Select an IWAD to use", GetVersionString()]; + id windowTitle = [NSString stringWithFormat:@"%s %s", GAMENAME, GetVersionString()]; NSRect frame = NSMakeRect(0, 0, 440, 450); window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]; [window setTitle:windowTitle]; - NSTextField *description = [[NSTextField alloc] initWithFrame:NSMakeRect(22, 379, 412, 50)]; - [self makeLabel:description withString:"ZDoom found more than one IWAD\nSelect from the list below to determine which one to use:"]; + NSTextField *description = [[NSTextField alloc] initWithFrame:NSMakeRect(18, 384, 402, 50)]; + [self makeLabel:description withString:GAMENAME " found more than one IWAD\nSelect from the list below to determine which one to use:"]; [[window contentView] addSubview:description]; [description release]; - // Commented out version would account for an additional parameters box. - //NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 103, 412, 288)]; - NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 50, 412, 341)]; + NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 135, 402, 256)]; NSTableView *iwadTable = [[NSTableView alloc] initWithFrame:[iwadScroller bounds]]; IWADTableData *tableData = [[IWADTableData alloc] init:wads num:numwads]; for(int i = 0;i < NUM_COLUMNS;i++) @@ -200,11 +296,12 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [iwadTable release]; [iwadScroller release]; - /*NSTextField *additionalParametersLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(17, 78, 144, 17)]; - [self makeLabel:additionalParametersLabel:"Additional Parameters"]; + NSTextField *additionalParametersLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(18, 108, 144, 17)]; + [self makeLabel:additionalParametersLabel withString:"Additional Parameters:"]; [[window contentView] addSubview:additionalParametersLabel]; - NSTextField *additionalParameters = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 48, 360, 22)]; - [[window contentView] addSubview:additionalParameters];*/ + parametersTextField = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 48, 402, 54)]; + [parametersTextField setStringValue:[NSString stringWithUTF8String:osx_additional_parameters]]; + [[window contentView] addSubview:parametersTextField]; // Doesn't look like the SDL version implements this so lets not show it. /*NSButton *dontAsk = [[NSButton alloc] initWithFrame:NSMakeRect(18, 18, 178, 18)]; @@ -213,39 +310,147 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [dontAsk setState:(showwin ? NSOffState : NSOnState)]; [[window contentView] addSubview:dontAsk];*/ - okButton = [[NSButton alloc] initWithFrame:NSMakeRect(236, 12, 96, 32)]; - [okButton setTitle:[NSString stringWithUTF8String:"OK"]]; + okButton = [[NSButton alloc] initWithFrame:NSMakeRect(236, 8, 96, 32)]; + [okButton setTitle:@"OK"]; [okButton setBezelStyle:NSRoundedBezelStyle]; [okButton setAction:@selector(buttonPressed:)]; [okButton setTarget:self]; [okButton setKeyEquivalent:@"\r"]; [[window contentView] addSubview:okButton]; - cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(332, 12, 96, 32)]; - [cancelButton setTitle:[NSString stringWithUTF8String:"Cancel"]]; + cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(332, 8, 96, 32)]; + [cancelButton setTitle:@"Cancel"]; [cancelButton setBezelStyle:NSRoundedBezelStyle]; [cancelButton setAction:@selector(buttonPressed:)]; [cancelButton setTarget:self]; [cancelButton setKeyEquivalent:@"\033"]; [[window contentView] addSubview:cancelButton]; + + browseButton = [[NSButton alloc] initWithFrame:NSMakeRect(14, 8, 96, 32)]; + [browseButton setTitle:@"Browse..."]; + [browseButton setBezelStyle:NSRoundedBezelStyle]; + [browseButton setAction:@selector(browseButtonPressed:)]; + [browseButton setTarget:self]; + [[window contentView] addSubview:browseButton]; + + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; + [center addObserver:self selector:@selector(menuActionSent:) name:NSMenuDidSendActionNotification object:nil]; [window center]; [app runModalForWindow:window]; + [center removeObserver:self name:NSMenuDidSendActionNotification object:nil]; + [window release]; [okButton release]; [cancelButton release]; + [browseButton release]; return cancelled ? -1 : [iwadTable selectedRow]; } +- (NSString*)commandLineParameters +{ + return [parametersTextField stringValue]; +} + +- (void)menuActionSent:(NSNotification*)notification +{ + NSDictionary* userInfo = [notification userInfo]; + NSMenuItem* menuItem = [userInfo valueForKey:@"MenuItem"]; + + if ( @selector(terminate:) == [menuItem action] ) + { + exit(0); + } +} + @end + +EXTERN_CVAR(String, defaultiwad) + +static void RestartWithParameters(const char* iwadPath, NSString* parameters) +{ + assert(nil != parameters); + + defaultiwad = ExtractFileBase(iwadPath); + + GameConfig->DoGameSetup("Doom"); + M_SaveDefaults(NULL); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + @try + { + const int commandLineParametersCount = Args->NumArgs(); + assert(commandLineParametersCount > 0); + + NSString* executablePath = [NSString stringWithUTF8String:Args->GetArg(0)]; + + NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:commandLineParametersCount + 3]; + [arguments addObject:@"-wad_picker_restart"]; + [arguments addObject:@"-iwad"]; + [arguments addObject:[NSString stringWithUTF8String:iwadPath]]; + + for (int i = 1; i < commandLineParametersCount; ++i) + { + NSString* currentParameter = [NSString stringWithUTF8String:Args->GetArg(i)]; + [arguments addObject:currentParameter]; + } + + wordexp_t expansion; + + if (0 == wordexp([parameters UTF8String], &expansion, 0)) + { + for (size_t i = 0; i < expansion.we_wordc; ++i) + { + NSString* argumentString = [NSString stringWithCString:expansion.we_wordv[i] + encoding:NSUTF8StringEncoding]; + [arguments addObject:argumentString]; + } + + wordfree(&expansion); + } + + [NSTask launchedTaskWithLaunchPath:executablePath arguments:arguments]; + + _exit(0); // to avoid atexit()'s functions + } + @catch (NSException* e) + { + NSLog(@"Cannot restart: %@", [e reason]); + } + + [pool release]; +} + +void I_SetMainWindowVisible(bool visible); + // Simple wrapper so we can call this from outside. int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + I_SetMainWindowVisible(false); + IWADPicker *picker = [IWADPicker alloc]; int ret = [picker pickIWad:wads num:numwads showWindow:showwin defaultWad:defaultiwad]; - [picker release]; + + I_SetMainWindowVisible(true); + + NSString* parametersToAppend = [picker commandLineParameters]; + osx_additional_parameters = [parametersToAppend UTF8String]; + + if (ret >= 0) + { + if (0 != [parametersToAppend length]) + { + RestartWithParameters(wads[ret].Path, parametersToAppend); + } + } + + [pool release]; + return ret; }