summaryrefslogtreecommitdiff
path: root/pkg/osx
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/osx')
-rw-r--r--pkg/osx/.gitignore7
-rw-r--r--pkg/osx/AppController.h53
-rw-r--r--pkg/osx/AppController.m124
-rw-r--r--pkg/osx/Execute.h31
-rw-r--r--pkg/osx/Execute.m208
-rw-r--r--pkg/osx/GNUmakefile101
-rw-r--r--pkg/osx/IWADController.h54
-rw-r--r--pkg/osx/IWADController.m347
-rw-r--r--pkg/osx/IWADLocation.h44
-rw-r--r--pkg/osx/IWADLocation.m74
-rw-r--r--pkg/osx/Info-gnustep.plist.in36
-rw-r--r--pkg/osx/Info.plist.in60
-rw-r--r--pkg/osx/LauncherManager.h52
-rw-r--r--pkg/osx/LauncherManager.m338
-rw-r--r--pkg/osx/PkgInfo1
-rw-r--r--pkg/osx/Resources/128x128.pngbin0 -> 23029 bytes
-rw-r--r--pkg/osx/Resources/app.icnsbin0 -> 51625 bytes
-rw-r--r--pkg/osx/Resources/app.pngbin0 -> 4597 bytes
-rw-r--r--pkg/osx/Resources/launcher.nib/classes.nib47
-rw-r--r--pkg/osx/Resources/launcher.nib/info.nib23
-rw-r--r--pkg/osx/Resources/launcher.nib/keyedobjects.nibbin0 -> 19616 bytes
-rw-r--r--pkg/osx/Resources/wadfile.icnsbin0 -> 44092 bytes
-rw-r--r--pkg/osx/Resources/wadfile.pngbin0 -> 2249 bytes
-rwxr-xr-xpkg/osx/cp-with-libs100
-rw-r--r--pkg/osx/main.m32
25 files changed, 1732 insertions, 0 deletions
diff --git a/pkg/osx/.gitignore b/pkg/osx/.gitignore
new file mode 100644
index 00000000..ca1a7908
--- /dev/null
+++ b/pkg/osx/.gitignore
@@ -0,0 +1,7 @@
+Info.plist
+Info-gnustep.plist
+launcher
+*.o
+*.d
+*.dmg
+staging
diff --git a/pkg/osx/AppController.h b/pkg/osx/AppController.h
new file mode 100644
index 00000000..88b59043
--- /dev/null
+++ b/pkg/osx/AppController.h
@@ -0,0 +1,53 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_APPCONTROLLER_H
+#define LAUNCHER_APPCONTROLLER_H
+
+#include <AppKit/AppKit.h>
+
+#include "LauncherManager.h"
+
+@interface AppController : NSObject
+{
+ LauncherManager *launcherManager;
+ BOOL filesAdded;
+}
+
++ (void)initialize;
+
+- (id)init;
+- (void)dealloc;
+
+- (void)awakeFromNib;
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotif;
+- (BOOL)applicationShouldTerminate:(id)sender;
+- (void)applicationWillTerminate:(NSNotification *)aNotif;
+- (BOOL)application:(NSApplication *)application openFile:(NSString *)fileName;
+
+- (void)showPrefPanel:(id)sender;
+
+@end
+
+#endif
+
diff --git a/pkg/osx/AppController.m b/pkg/osx/AppController.m
new file mode 100644
index 00000000..a26a7c9e
--- /dev/null
+++ b/pkg/osx/AppController.m
@@ -0,0 +1,124 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include "AppController.h"
+
+#include "config.h"
+
+@implementation AppController
+
++ (void)initialize
+{
+ NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
+
+ /*
+ * Register your app's defaults here by adding objects to the
+ * dictionary, eg
+ *
+ * [defaults setObject:anObject forKey:keyForThatObject];
+ *
+ */
+
+ [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
+ [[NSUserDefaults standardUserDefaults] synchronize];
+}
+
+- (id)init
+{
+ if ((self = [super init]))
+ {
+ }
+
+ self->filesAdded = NO;
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [super dealloc];
+}
+
+- (void)awakeFromNib
+{
+ [[NSApp mainMenu] setTitle:@PACKAGE_NAME];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotif
+{
+// Uncomment if your application is Renaissance-based
+// [NSBundle loadGSMarkupNamed:@"Main" owner:self];
+}
+
+- (BOOL)applicationShouldTerminate:(id)sender
+{
+ return YES;
+}
+
+- (void)applicationWillTerminate:(NSNotification *)aNotif
+{
+}
+
+- (BOOL) application:(NSApplication *) application
+ openFile:(NSString *) fileName
+{
+ NSString *extension;
+
+ // If this is the first file added, clear out the existing
+ // command line. This allows us to select multiple files
+ // in the finder and open them all together (for TCs, etc).
+
+ if (!self->filesAdded)
+ {
+ [self->launcherManager clearCommandLine];
+ }
+
+ // Add file with appropriate command line option based on extension:
+
+ extension = [fileName pathExtension];
+
+ if (![extension caseInsensitiveCompare: @"wad"])
+ {
+ [self->launcherManager addFileToCommandLine: fileName
+ forArgument: @"-merge"];
+ }
+ else if (![extension caseInsensitiveCompare: @"deh"])
+ {
+ [self->launcherManager addFileToCommandLine: fileName
+ forArgument: @"-deh"];
+ }
+ else
+ {
+ return NO;
+ }
+
+ self->filesAdded = YES;
+
+ return YES;
+}
+
+- (void)showPrefPanel:(id)sender
+{
+}
+
+@end
+
diff --git a/pkg/osx/Execute.h b/pkg/osx/Execute.h
new file mode 100644
index 00000000..2098be8a
--- /dev/null
+++ b/pkg/osx/Execute.h
@@ -0,0 +1,31 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_EXECUTE_H
+#define LAUNCHER_EXECUTE_H
+
+void SetProgramLocation(const char *path);
+void ExecuteProgram(const char *executable, const char *iwad, const char *args);
+void OpenTerminalWindow(const char *doomwadpath);
+
+#endif /* #ifndef LAUNCHER_EXECUTE_H */
+
diff --git a/pkg/osx/Execute.m b/pkg/osx/Execute.m
new file mode 100644
index 00000000..608443e2
--- /dev/null
+++ b/pkg/osx/Execute.m
@@ -0,0 +1,208 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <AppKit/AppKit.h>
+
+#include "config.h"
+
+#define RESPONSE_FILE "/tmp/launcher.rsp"
+#define TEMP_SCRIPT "/tmp/tempscript.sh"
+
+static char *executable_path;
+
+// Called on startup to save the location of the launcher program
+// (within a package, other executables should be in the same directory)
+
+void SetProgramLocation(const char *path)
+{
+ char *p;
+
+ executable_path = strdup(path);
+
+ p = strrchr(executable_path, '/');
+ *p = '\0';
+}
+
+// Write out the response file containing command line arguments.
+
+static void WriteResponseFile(const char *iwad, const char *args)
+{
+ FILE *fstream;
+
+ fstream = fopen(RESPONSE_FILE, "w");
+
+ if (iwad != NULL)
+ {
+ fprintf(fstream, "-iwad \"%s\"", iwad);
+ }
+
+ if (args != NULL)
+ {
+ fprintf(fstream, "%s", args);
+ }
+
+ fclose(fstream);
+}
+
+static void DoExec(const char *executable, const char *iwad, const char *args)
+{
+ char *argv[3];
+
+ argv[0] = malloc(strlen(executable_path) + strlen(executable) + 3);
+ sprintf(argv[0], "%s/%s", executable_path, executable);
+
+ if (iwad != NULL || args != NULL)
+ {
+ WriteResponseFile(iwad, args);
+
+ argv[1] = "@" RESPONSE_FILE;
+ argv[2] = NULL;
+ }
+ else
+ {
+ argv[1] = NULL;
+ }
+
+ execv(argv[0], argv);
+ exit(-1);
+}
+
+// Execute the specified executable contained in the same directory
+// as the launcher, with the specified arguments.
+
+void ExecuteProgram(const char *executable, const char *iwad, const char *args)
+{
+ pid_t childpid;
+ char *homedir;
+
+ childpid = fork();
+
+ if (childpid == 0)
+ {
+ signal(SIGCHLD, SIG_DFL);
+
+ // Change directory to home dir before launch, so that any demos
+ // are saved somewhere sensible.
+
+ homedir = getenv("HOME");
+
+ if (homedir != NULL)
+ {
+ chdir(homedir);
+ }
+
+ DoExec(executable, iwad, args);
+ }
+ else
+ {
+ signal(SIGCHLD, SIG_IGN);
+ }
+}
+
+// Write a sequence of commands that will display the specified message
+// via shell commands.
+
+static void WriteMessage(FILE *script, char *msg)
+{
+ char *p;
+
+ fprintf(script, "echo \"");
+
+ for (p=msg; *p != '\0'; ++p)
+ {
+ // Start new line?
+
+ if (*p == '\n')
+ {
+ fprintf(script, "\"\necho \"");
+ continue;
+ }
+
+ // Escaped character?
+
+ if (*p == '\\' || *p == '\"')
+ {
+ fprintf(script, "\\");
+ }
+
+ fprintf(script, "%c", *p);
+ }
+
+ fprintf(script, "\"\n");
+}
+
+// Open a terminal window with the PATH set appropriately, and DOOMWADPATH
+// set to the specified value.
+
+void OpenTerminalWindow(const char *doomwadpath)
+{
+ FILE *stream;
+
+ // Generate a shell script that sets the PATH to include the location
+ // where the Doom binaries are, and DOOMWADPATH to include the
+ // IWAD files that have been configured in the launcher interface.
+ // The script then deletes itself and starts a shell.
+
+ stream = fopen(TEMP_SCRIPT, "w");
+
+ fprintf(stream, "#!/bin/sh\n");
+ //fprintf(stream, "set -x\n");
+ fprintf(stream, "PATH=\"%s:$PATH\"\n", executable_path);
+ fprintf(stream, "DOOMWADPATH=\"%s\"\n", doomwadpath);
+ fprintf(stream, "export DOOMWADPATH\n");
+ fprintf(stream, "rm -f \"%s\"\n", TEMP_SCRIPT);
+
+ // Display a useful message:
+
+ fprintf(stream, "clear\n");
+ WriteMessage(stream,
+ "\n"
+ "This command line has the PATH variable configured so that you may\n"
+ "launch the game with whatever parameters you desire.\n"
+ "\n"
+ "For example:\n"
+ "\n"
+ " " PACKAGE_TARNAME " -iwad doom2.wad -file sid.wad -warp 1\n"
+ "\n"
+ "Type 'exit' to exit.\n");
+
+ fprintf(stream, "exec $SHELL\n");
+ fprintf(stream, "\n");
+
+ fclose(stream);
+
+ chmod(TEMP_SCRIPT, 0755);
+
+ // Tell the terminal to open a window to run the script.
+
+ [[NSWorkspace sharedWorkspace] openFile: @TEMP_SCRIPT
+ withApplication: @"Terminal"];
+}
+
diff --git a/pkg/osx/GNUmakefile b/pkg/osx/GNUmakefile
new file mode 100644
index 00000000..d119efa1
--- /dev/null
+++ b/pkg/osx/GNUmakefile
@@ -0,0 +1,101 @@
+
+# Makefile for building the OS X launcher program and DMG package.
+# It is also possible to build and run the launcher under Unix
+# systems using GNUstep, although this is only here for development
+# and debugging purposes.
+
+include ../config.make
+
+STAGING_DIR=staging
+DMG=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).dmg
+
+TOPLEVEL=../..
+TOPLEVEL_DOCS=$(patsubst %,../../%,$(DOC_FILES))
+
+ifndef GNUSTEP_MAKEFILES
+
+# DMG file containing package:
+
+$(DMG) : $(STAGING_DIR)
+ rm -f $@
+ hdiutil create -volname "$(PACKAGE_STRING)" -srcdir $(STAGING_DIR) $@
+
+endif
+
+# Staging dir build for package:
+
+APP_DIR=$(STAGING_DIR)/$(PACKAGE_NAME).app
+
+# OS X and GNUstep apps have a slightly different internal structure:
+# OS X apps have their files within a containing "Contents" directory
+# that does not exist in GNUstep apps. Similarly, the binaries are
+# installed at the top level, rather than in a "MacOS" directory.
+# Finally, we must install a different Info.plist file.
+
+ifdef GNUSTEP_MAKEFILES
+APP_TOP_DIR=$(APP_DIR)
+APP_BIN_DIR=$(APP_DIR)
+SRC_INFO_PLIST=Info-gnustep.plist
+else
+APP_TOP_DIR=$(APP_DIR)/Contents
+APP_BIN_DIR=$(APP_DIR)/Contents/MacOS
+SRC_INFO_PLIST=Info.plist
+endif
+
+$(STAGING_DIR): launcher $(TOPLEVEL_DOCS)
+ rm -rf $(STAGING_DIR)
+ mkdir $(STAGING_DIR)
+
+ cp $(TOPLEVEL_DOCS) "$(STAGING_DIR)"
+
+ mkdir -p "$(APP_TOP_DIR)"
+ cp -R Resources "$(APP_TOP_DIR)"
+ cp PkgInfo "$(APP_TOP_DIR)"
+ cp $(SRC_INFO_PLIST) "$(APP_TOP_DIR)"
+
+ mkdir -p "$(APP_BIN_DIR)"
+
+ cp launcher "$(APP_BIN_DIR)"
+ $(STRIP) "$(APP_BIN_DIR)/launcher"
+
+ ./cp-with-libs $(TOPLEVEL)/src/$(PACKAGE_TARNAME) "$(APP_BIN_DIR)"
+ $(STRIP) "$(APP_BIN_DIR)/$(PACKAGE_TARNAME)"
+ ./cp-with-libs $(TOPLEVEL)/setup/chocolate-setup "$(APP_BIN_DIR)"
+ $(STRIP) "$(APP_BIN_DIR)/chocolate-setup"
+
+ find $(STAGING_DIR) -name .svn -delete -exec rm -rf {} \; || true
+
+clean : launcher_clean
+ rm -f $(DMG)
+ rm -rf $(STAGING_DIR)
+
+# Launcher build:
+
+CFLAGS = -Wall -I$(TOPLEVEL)
+
+# Are we building using gs_make?
+
+ifdef GNUSTEP_MAKEFILES
+CFLAGS += $(shell gnustep-config --objc-flags)
+LDFLAGS = $(shell gnustep-config --gui-libs)
+else
+LDFLAGS = -framework Cocoa
+endif
+
+LAUNCHER_OBJS= \
+ AppController.o \
+ Execute.o \
+ IWADController.o \
+ IWADLocation.o \
+ LauncherManager.o \
+ main.o
+
+launcher : $(LAUNCHER_OBJS)
+ $(CC) $(LDFLAGS) $(LAUNCHER_OBJS) -o $@
+
+%.o : %.m
+ $(CC) -c $(CFLAGS) $^ -o $@
+
+launcher_clean :
+ rm -f $(LAUNCHER_OBJS) launcher
+
diff --git a/pkg/osx/IWADController.h b/pkg/osx/IWADController.h
new file mode 100644
index 00000000..90f44667
--- /dev/null
+++ b/pkg/osx/IWADController.h
@@ -0,0 +1,54 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_IWADCONTROLLER_H
+#define LAUNCHER_IWADCONTROLLER_H
+
+#include <AppKit/AppKit.h>
+#include <AppKit/NSNibLoading.h>
+
+@interface IWADController : NSObject
+{
+ id iwadSelector;
+ id configWindow;
+
+ id chex;
+ id doom1;
+ id doom2;
+ id plutonia;
+ id tnt;
+}
+
+- (void) closeConfigWindow: (id)sender;
+- (void) openConfigWindow: (id)sender;
+- (NSString *) getIWADLocation;
+- (void) awakeFromNib;
+- (BOOL) setDropdownList;
+- (void) setDropdownSelection;
+- (void) saveConfig;
+- (char *) doomWadPath;
+- (void) setEnvironment;
+
+@end
+
+#endif /* #ifndef LAUNCHER_IWADCONTROLLER_H */
+
diff --git a/pkg/osx/IWADController.m b/pkg/osx/IWADController.m
new file mode 100644
index 00000000..3c596850
--- /dev/null
+++ b/pkg/osx/IWADController.m
@@ -0,0 +1,347 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string.h>
+#include <AppKit/AppKit.h>
+#include "IWADController.h"
+#include "IWADLocation.h"
+
+typedef enum
+{
+ IWAD_DOOM1,
+ IWAD_DOOM2,
+ IWAD_TNT,
+ IWAD_PLUTONIA,
+ IWAD_CHEX,
+ NUM_IWAD_TYPES
+} IWAD;
+
+static NSString *IWADLabels[NUM_IWAD_TYPES] =
+{
+ @"Doom",
+ @"Doom II: Hell on Earth",
+ @"Final Doom: TNT: Evilution",
+ @"Final Doom: Plutonia Experiment",
+ @"Chex Quest"
+};
+
+static NSString *IWADFilenames[NUM_IWAD_TYPES + 1] =
+{
+ @"doom.wad",
+ @"doom2.wad",
+ @"tnt.wad",
+ @"plutonia.wad",
+ @"chex.wad",
+ @"undefined"
+};
+
+@implementation IWADController
+
+- (void) getIWADList: (IWADLocation **) iwadList
+{
+ iwadList[IWAD_DOOM1] = self->doom1;
+ iwadList[IWAD_DOOM2] = self->doom2;
+ iwadList[IWAD_TNT] = self->tnt;
+ iwadList[IWAD_PLUTONIA] = self->plutonia;
+ iwadList[IWAD_CHEX] = self->chex;
+}
+
+- (IWAD) getSelectedIWAD
+{
+ unsigned int i;
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ if ([self->iwadSelector titleOfSelectedItem] == IWADLabels[i])
+ {
+ return i;
+ }
+ }
+
+ return NUM_IWAD_TYPES;
+}
+
+// Get the location of the selected IWAD.
+
+- (NSString *) getIWADLocation
+{
+ IWAD selectedIWAD;
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+
+ selectedIWAD = [self getSelectedIWAD];
+
+ if (selectedIWAD == NUM_IWAD_TYPES)
+ {
+ return nil;
+ }
+ else
+ {
+ [self getIWADList: iwadList];
+
+ return [iwadList[selectedIWAD] getLocation];
+ }
+}
+
+- (void) setIWADConfig
+{
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+ NSUserDefaults *defaults;
+ NSString *key;
+ NSString *value;
+ unsigned int i;
+
+ [self getIWADList: iwadList];
+
+ // Load IWAD filename paths
+
+ defaults = [NSUserDefaults standardUserDefaults];
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ key = IWADFilenames[i];
+ value = [defaults stringForKey:key];
+
+ if (value != nil)
+ {
+ [iwadList[i] setLocation:value];
+ }
+ }
+}
+
+// On startup, set the selected item in the IWAD dropdown
+
+- (void) setDropdownSelection
+{
+ NSUserDefaults *defaults;
+ NSString *selected;
+ unsigned int i;
+
+ defaults = [NSUserDefaults standardUserDefaults];
+ selected = [defaults stringForKey: @"selected_iwad"];
+
+ if (selected == nil)
+ {
+ return;
+ }
+
+ // Find this IWAD in the filenames list, and select it.
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ if ([selected isEqualToString:IWADFilenames[i]])
+ {
+ [self->iwadSelector selectItemWithTitle:IWADLabels[i]];
+ break;
+ }
+ }
+}
+
+// Set the dropdown list to include an entry for each IWAD that has
+// been configured. Returns true if at least one IWAD is configured.
+
+- (BOOL) setDropdownList
+{
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+ BOOL have_wads;
+ id location;
+ unsigned int i;
+ unsigned int enabled_wads;
+
+ // Build the new list.
+
+ [self getIWADList: iwadList];
+ [self->iwadSelector removeAllItems];
+
+ enabled_wads = 0;
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ location = [iwadList[i] getLocation];
+
+ if (location != nil && [location length] > 0)
+ {
+ [self->iwadSelector addItemWithTitle: IWADLabels[i]];
+ ++enabled_wads;
+ }
+ }
+
+ // Enable/disable the dropdown depending on whether there
+ // were any configured IWADs.
+
+ have_wads = enabled_wads > 0;
+ [self->iwadSelector setEnabled: have_wads];
+
+ // Restore the old selection.
+
+ [self setDropdownSelection];
+
+ return have_wads;
+}
+
+- (void) saveConfig
+{
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+ IWAD selectedIWAD;
+ NSUserDefaults *defaults;
+ NSString *key;
+ NSString *value;
+ unsigned int i;
+
+ [self getIWADList: iwadList];
+
+ // Store all IWAD locations to user defaults.
+
+ defaults = [NSUserDefaults standardUserDefaults];
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ key = IWADFilenames[i];
+ value = [iwadList[i] getLocation];
+
+ [defaults setObject:value forKey:key];
+ }
+
+ // Save currently selected IWAD.
+
+ selectedIWAD = [self getSelectedIWAD];
+ [defaults setObject:IWADFilenames[selectedIWAD]
+ forKey:@"selected_iwad"];
+}
+
+// Callback method invoked when the configuration button in the main
+// window is clicked.
+
+- (void) openConfigWindow: (id)sender
+{
+ if (![self->configWindow isVisible])
+ {
+ [self->configWindow makeKeyAndOrderFront: sender];
+ }
+}
+
+// Callback method invoked when the close button is clicked.
+
+- (void) closeConfigWindow: (id)sender
+{
+ [self->configWindow orderOut: sender];
+ [self saveConfig];
+ [self setDropdownList];
+}
+
+- (void) awakeFromNib
+{
+ [self->configWindow center];
+
+ // Set configuration for all IWADs from configuration file.
+
+ [self setIWADConfig];
+
+ // Populate the dropdown IWAD list.
+
+ if ([self setDropdownList])
+ {
+ [self setDropdownSelection];
+ }
+}
+
+// Generate a value to set for the DOOMWADPATH environment variable
+// that contains each of the configured IWAD files.
+
+- (char *) doomWadPath
+{
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+ NSString *location;
+ unsigned int i;
+ unsigned int len;
+ BOOL first;
+ char *env;
+
+ [self getIWADList: iwadList];
+
+ // Calculate length of environment string.
+
+ len = 0;
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ location = [iwadList[i] getLocation];
+
+ if (location != nil && [location length] > 0)
+ {
+ len += [location length] + 1;
+ }
+ }
+
+ // Build string.
+
+ env = malloc(len);
+ strcpy(env, "");
+
+ first = YES;
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ location = [iwadList[i] getLocation];
+
+ if (location != nil && [location length] > 0)
+ {
+ if (!first)
+ {
+ strcat(env, ":");
+ }
+
+ strcat(env, [location UTF8String]);
+ first = NO;
+ }
+ }
+
+ return env;
+}
+
+// Set the DOOMWADPATH environment variable to contain the path to each
+// of the configured IWAD files.
+
+- (void) setEnvironment
+{
+ char *doomwadpath;
+ char *env;
+
+ // Get the value for the path.
+
+ doomwadpath = [self doomWadPath];
+
+ env = malloc(strlen(doomwadpath) + 15);
+
+ sprintf(env, "DOOMWADPATH=%s", doomwadpath);
+
+ free(doomwadpath);
+
+ // Load into environment:
+
+ putenv(env);
+
+ //free(env);
+}
+
+@end
+
diff --git a/pkg/osx/IWADLocation.h b/pkg/osx/IWADLocation.h
new file mode 100644
index 00000000..4ddfebc2
--- /dev/null
+++ b/pkg/osx/IWADLocation.h
@@ -0,0 +1,44 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_IWADLOCATION_H
+#define LAUNCHER_IWADLOCATION_H
+
+#include <AppKit/AppKit.h>
+
+#include "IWADController.h"
+
+@interface IWADLocation : NSObject
+{
+ IWADController *iwadController;
+
+ id locationConfigBox;
+}
+
+- (void) setButtonClicked: (id)sender;
+- (NSString *) getLocation;
+- (void) setLocation: (NSString *) value;
+
+@end
+
+#endif /* #ifndef LAUNCHER_IWADLOCATION_H */
+
diff --git a/pkg/osx/IWADLocation.m b/pkg/osx/IWADLocation.m
new file mode 100644
index 00000000..3f2ac188
--- /dev/null
+++ b/pkg/osx/IWADLocation.m
@@ -0,0 +1,74 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include <AppKit/AppKit.h>
+#include "IWADLocation.h"
+
+static id WAD_TYPES[] =
+{
+ @"wad", @"WAD"
+};
+
+@implementation IWADLocation
+
+- (void) setButtonClicked: (id)sender
+{
+ NSArray *wadTypes = [NSArray arrayWithObjects: WAD_TYPES count: 2];
+ NSOpenPanel *openPanel;
+ NSArray *filenames;
+ int result;
+
+ [wadTypes retain];
+
+ // Open a file selector for the new file.
+
+ openPanel = [NSOpenPanel openPanel];
+ [openPanel setTitle: @"Add IWAD file"];
+ [openPanel setCanChooseFiles: YES];
+ [openPanel setCanChooseDirectories: NO];
+
+ result = [openPanel runModalForTypes: wadTypes];
+
+ // If the "OK" button was clicked, add the new IWAD file to the list.
+
+ if (result == NSOKButton)
+ {
+ filenames = [openPanel filenames];
+ [self setLocation: [filenames lastObject]];
+
+ [self->iwadController saveConfig];
+ [self->iwadController setDropdownList];
+ }
+}
+
+- (NSString *) getLocation
+{
+ return [self->locationConfigBox stringValue];
+}
+
+- (void) setLocation: (NSString *) filename
+{
+ [self->locationConfigBox setStringValue: filename];
+}
+
+@end
+
diff --git a/pkg/osx/Info-gnustep.plist.in b/pkg/osx/Info-gnustep.plist.in
new file mode 100644
index 00000000..da6675ba
--- /dev/null
+++ b/pkg/osx/Info-gnustep.plist.in
@@ -0,0 +1,36 @@
+{
+ ApplicationName = "@PACKAGE_NAME@";
+ ApplicationDescription = "@PACKAGE_SHORTDESC@";
+ ApplicationIcon = app.png;
+ ApplicationRelease = @PACKAGE_VERSION@;
+ ApplicationURL = "@PACKAGE_URL@";
+ Authors = (
+ "@PACKAGE_MAINTAINER@ <@PACKAGE_BUGREPORT@>"
+ );
+ Copyright = "@PACKAGE_COPYRIGHT@";
+ CopyrightDescription = "@PACKAGE_LICENSE@";
+ FullVersionID = @PACKAGE_VERSION@;
+ GSMainMarkupFile = "";
+ NSExecutable = "launcher";
+ NSIcon = app.png;
+ NSMainNibFile = launcher.nib;
+ NSPrincipalClass = NSApplication;
+ NSRole = Application;
+ NSTypes = (
+ {
+ NSHumanReadableName = "Doom WAD file";
+ NSUnixExtensions = ( wad );
+ NSRole = Viewer;
+ NSMimeTypes = (
+ "application/x-doom"
+ );
+ NSIcon = "wadfile.png";
+ },
+ {
+ NSHumanReadableName = "Dehacked patch";
+ NSUnixExtensions = ( deh );
+ NSRole = Viewer;
+ NSIcon = "wadfile.png";
+ }
+ );
+}
diff --git a/pkg/osx/Info.plist.in b/pkg/osx/Info.plist.in
new file mode 100644
index 00000000..8b8436f7
--- /dev/null
+++ b/pkg/osx/Info.plist.in
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleDisplayName</key>
+ <string>@PACKAGE_NAME@</string>
+ <key>CFBundleExecutable</key>
+ <string>launcher</string>
+ <key>CFBundleGetInfoString</key>
+ <string>@PACKAGE_STRING@</string>
+ <key>CFBundleIconFile</key>
+ <string>app.icns</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>@PACKAGE_NAME@</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@PACKAGE_VERSION@</string>
+ <key>CFBundleVersion</key>
+ <string>@PACKAGE_VERSION@</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSMainNibFile</key>
+ <string>launcher</string>
+
+ <!-- file associations: -->
+
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeName</key>
+ <string>Doom WAD file</string>
+ <key>CFBundleTypeIconFile</key>
+ <string>wadfile.icns</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>wad</string>
+ </array>
+ </dict>
+ <dict>
+ <key>CFBundleTypeName</key>
+ <string>Dehacked patch</string>
+ <key>CFBundleTypeIconFile</key>
+ <string>wadfile.icns</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>deh</string>
+ </array>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/pkg/osx/LauncherManager.h b/pkg/osx/LauncherManager.h
new file mode 100644
index 00000000..e454ab4f
--- /dev/null
+++ b/pkg/osx/LauncherManager.h
@@ -0,0 +1,52 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_LAUNCHERMANAGER_H
+#define LAUNCHER_LAUNCHERMANAGER_H
+
+#include <AppKit/AppKit.h>
+#include <AppKit/NSNibLoading.h>
+#include "IWADController.h"
+
+@interface LauncherManager : NSObject
+{
+ IWADController *iwadController;
+
+ id launcherWindow;
+ id launchButton;
+
+ id commandLineArguments;
+ id packageLabel;
+}
+
+- (void) launch: (id)sender;
+- (void) runSetup: (id)sender;
+- (void) awakeFromNib;
+- (void) clearCommandLine;
+- (void) addFileToCommandLine: (NSString *) fileName
+ forArgument: (NSString *) args;
+- (void) openTerminal: (id) sender;
+
+@end
+
+#endif /* #ifndef LAUNCHER_LAUNCHERMANAGER_H */
+
diff --git a/pkg/osx/LauncherManager.m b/pkg/osx/LauncherManager.m
new file mode 100644
index 00000000..ae91ef4d
--- /dev/null
+++ b/pkg/osx/LauncherManager.m
@@ -0,0 +1,338 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include <AppKit/AppKit.h>
+#include "Execute.h"
+#include "LauncherManager.h"
+#include "config.h"
+
+@implementation LauncherManager
+
+// Save configuration. Invoked when we launch the game or quit.
+
+- (void) saveConfig
+{
+ NSUserDefaults *defaults;
+
+ // Save IWAD configuration and selected IWAD.
+
+ [self->iwadController saveConfig];
+
+ // Save command line arguments.
+
+ defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setObject:[self->commandLineArguments stringValue]
+ forKey:@"command_line_args"];
+}
+
+// Load configuration, invoked on startup.
+
+- (void) setConfig
+{
+ NSUserDefaults *defaults;
+ NSString *args;
+
+ defaults = [NSUserDefaults standardUserDefaults];
+
+ args = [defaults stringForKey:@"command_line_args"];
+
+ if (args != nil)
+ {
+ [self->commandLineArguments setStringValue:args];
+ }
+}
+
+// Get the next command line argument from the command line.
+// The position counter used to iterate over arguments is in 'pos'.
+// The index of the argument that was found is saved in arg_pos.
+
+static NSString *GetNextArgument(NSString *commandLine, int *pos, int *arg_pos)
+{
+ NSRange arg_range;
+
+ // Skip past any whitespace
+
+ while (*pos < [commandLine length]
+ && isspace([commandLine characterAtIndex: *pos]))
+ {
+ ++*pos;
+ }
+
+ if (*pos >= [commandLine length])
+ {
+ *arg_pos = *pos;
+ return nil;
+ }
+
+ // We are at the start of the argument. This may be a quoted
+ // string argument, or a "normal" one.
+
+ if ([commandLine characterAtIndex: *pos] == '\"')
+ {
+ // Quoted string, skip past first quote
+
+ ++*pos;
+
+ // Save start position:
+
+ *arg_pos = *pos;
+
+ while (*pos < [commandLine length]
+ && [commandLine characterAtIndex: *pos] != '\"')
+ {
+ ++*pos;
+ }
+
+ // Unexpected end of string?
+
+ if (*pos >= [commandLine length])
+ {
+ return nil;
+ }
+
+ arg_range = NSMakeRange(*arg_pos, *pos - *arg_pos);
+
+ // Skip past last quote
+
+ ++*pos;
+ }
+ else
+ {
+ // Normal argument
+
+ // Save position:
+
+ *arg_pos = *pos;
+
+ // Read until end:
+
+ while (*pos < [commandLine length]
+ && !isspace([commandLine characterAtIndex: *pos]))
+ {
+ ++*pos;
+ }
+
+ arg_range = NSMakeRange(*arg_pos, *pos - *arg_pos);
+ }
+
+ return [commandLine substringWithRange: arg_range];
+}
+
+// Given the specified command line argument, find the index
+// to insert the new file within the command line. Returns -1 if the
+// argument is not already within the arguments string.
+
+static int GetFileInsertIndex(NSString *commandLine, NSString *needle)
+{
+ NSString *arg;
+ int arg_pos;
+ int pos;
+
+ pos = 0;
+
+ // Find the command line parameter we are searching
+ // for (-merge, -deh, etc)
+
+ for (;;)
+ {
+ arg = GetNextArgument(commandLine, &pos, &arg_pos);
+
+ // Searched to end of string and never found?
+
+ if (arg == nil)
+ {
+ return -1;
+ }
+
+ if (![arg caseInsensitiveCompare: needle])
+ {
+ break;
+ }
+ }
+
+ // Now skip over existing files. For example, if we
+ // have -file foo.wad bar.wad, the new file should be appended
+ // to the end of the list.
+
+ for (;;)
+ {
+ arg = GetNextArgument(commandLine, &pos, &arg_pos);
+
+ // If we search to the end of the string now, it is fine;
+ // the new string should be added to the end of the command
+ // line. Otherwise, if we find an argument that begins
+ // with '-', it is a new command line parameter and the end
+ // of the list.
+
+ if (arg == nil || [arg characterAtIndex: 0] == '-')
+ {
+ break;
+ }
+ }
+
+ // arg_pos should now contain the offset to insert the new filename.
+
+ return arg_pos;
+}
+
+// Given the specified string, append a filename, quoted if necessary.
+
+static NSString *AppendQuotedFilename(NSString *str, NSString *fileName)
+{
+ int i;
+
+ // Search the filename for spaces, and quote if necessary.
+
+ for (i=0; i<[fileName length]; ++i)
+ {
+ if (isspace([fileName characterAtIndex: i]))
+ {
+ str = [str stringByAppendingString: @" \""];
+ str = [str stringByAppendingString: fileName];
+ str = [str stringByAppendingString: @"\" "];
+
+ return str;
+ }
+ }
+
+ str = [str stringByAppendingString: @" "];
+ str = [str stringByAppendingString: fileName];
+
+ return str;
+}
+
+// Clear out the existing command line options.
+// Invoked before the first file is added.
+
+- (void) clearCommandLine
+{
+ [self->commandLineArguments setStringValue: @""];
+}
+
+// Add a file to the command line to load with the game.
+
+- (void) addFileToCommandLine: (NSString *) fileName
+ forArgument: (NSString *) arg
+{
+ NSString *commandLine;
+ int insert_pos;
+
+ // Get the current command line
+
+ commandLine = [self->commandLineArguments stringValue];
+
+ // Find the location to insert the new filename:
+
+ insert_pos = GetFileInsertIndex(commandLine, arg);
+
+ // If position < 0, we should add the new argument and filename
+ // to the end. Otherwise, append the new filename to the existing
+ // list of files.
+
+ if (insert_pos < 0)
+ {
+ commandLine = [commandLine stringByAppendingString: @" "];
+ commandLine = [commandLine stringByAppendingString: arg];
+ commandLine = AppendQuotedFilename(commandLine, fileName);
+ }
+ else
+ {
+ NSString *start;
+ NSString *end;
+
+ // Divide existing command line in half:
+
+ start = [commandLine substringToIndex: insert_pos];
+ end = [commandLine substringFromIndex: insert_pos];
+
+ // Construct new command line:
+
+ commandLine = AppendQuotedFilename(start, fileName);
+ commandLine = [commandLine stringByAppendingString: @" "];
+ commandLine = [commandLine stringByAppendingString: end];
+ }
+
+ [self->commandLineArguments setStringValue: commandLine];
+}
+
+- (void) launch: (id)sender
+{
+ NSString *iwad;
+ NSString *args;
+
+ [self saveConfig];
+
+ iwad = [self->iwadController getIWADLocation];
+ args = [self->commandLineArguments stringValue];
+
+ if (iwad == nil)
+ {
+ NSRunAlertPanel(@"No IWAD selected",
+ @"You have not selected an IWAD (game) file.\n\n"
+ "You must configure and select a valid IWAD file "
+ "in order to launch the game.",
+ @"OK", nil, nil);
+ return;
+ }
+
+ ExecuteProgram(PACKAGE_TARNAME, [iwad UTF8String],
+ [args UTF8String]);
+ [NSApp terminate:sender];
+}
+
+// Invoked when the "Setup Tool" button is clicked, to run the setup tool:
+
+- (void) runSetup: (id)sender
+{
+ [self saveConfig];
+
+ [self->iwadController setEnvironment];
+ ExecuteProgram("chocolate-setup", NULL, NULL);
+}
+
+// Invoked when the "Terminal" option is selected from the menu, to open
+// a terminal window.
+
+- (void) openTerminal: (id) sender
+{
+ char *doomwadpath;
+
+ [self saveConfig];
+
+ doomwadpath = [self->iwadController doomWadPath];
+
+ OpenTerminalWindow(doomwadpath);
+
+ free(doomwadpath);
+}
+
+- (void) awakeFromNib
+{
+ [self->packageLabel setStringValue: @PACKAGE_STRING];
+ [self->launcherWindow setTitle: @PACKAGE_NAME " Launcher"];
+ [self->launcherWindow center];
+ [self->launcherWindow setDefaultButtonCell: [self->launchButton cell]];
+ [self setConfig];
+}
+
+@end
+
diff --git a/pkg/osx/PkgInfo b/pkg/osx/PkgInfo
new file mode 100644
index 00000000..6f749b0f
--- /dev/null
+++ b/pkg/osx/PkgInfo
@@ -0,0 +1 @@
+APPL????
diff --git a/pkg/osx/Resources/128x128.png b/pkg/osx/Resources/128x128.png
new file mode 100644
index 00000000..0ef1fe9c
--- /dev/null
+++ b/pkg/osx/Resources/128x128.png
Binary files differ
diff --git a/pkg/osx/Resources/app.icns b/pkg/osx/Resources/app.icns
new file mode 100644
index 00000000..9b535a25
--- /dev/null
+++ b/pkg/osx/Resources/app.icns
Binary files differ
diff --git a/pkg/osx/Resources/app.png b/pkg/osx/Resources/app.png
new file mode 100644
index 00000000..5b932e8c
--- /dev/null
+++ b/pkg/osx/Resources/app.png
Binary files differ
diff --git a/pkg/osx/Resources/launcher.nib/classes.nib b/pkg/osx/Resources/launcher.nib/classes.nib
new file mode 100644
index 00000000..7efc837a
--- /dev/null
+++ b/pkg/osx/Resources/launcher.nib/classes.nib
@@ -0,0 +1,47 @@
+{
+ IBClasses = (
+ {
+ CLASS = AppController;
+ LANGUAGE = ObjC;
+ OUTLETS = {launcherManager = id; };
+ SUPERCLASS = NSObject;
+ },
+ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
+ {
+ ACTIONS = {closeConfigWindow = id; openConfigWindow = id; };
+ CLASS = IWADController;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ chex = id;
+ configWindow = id;
+ doom1 = id;
+ doom2 = id;
+ iwadSelector = id;
+ plutonia = id;
+ tnt = id;
+ };
+ SUPERCLASS = NSObject;
+ },
+ {
+ ACTIONS = {setButtonClicked = id; };
+ CLASS = IWADLocation;
+ LANGUAGE = ObjC;
+ OUTLETS = {locationConfigBox = id; };
+ SUPERCLASS = NSObject;
+ },
+ {
+ ACTIONS = {launch = id; openTerminal = id; runSetup = id; };
+ CLASS = LauncherManager;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ commandLineArguments = id;
+ iwadController = id;
+ launchButton = id;
+ launcherWindow = id;
+ packageLabel = id;
+ };
+ SUPERCLASS = NSObject;
+ }
+ );
+ IBVersion = 1;
+} \ No newline at end of file
diff --git a/pkg/osx/Resources/launcher.nib/info.nib b/pkg/osx/Resources/launcher.nib/info.nib
new file mode 100644
index 00000000..512ee6dd
--- /dev/null
+++ b/pkg/osx/Resources/launcher.nib/info.nib
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>325 73 612 260 0 0 1440 878 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>29</key>
+ <string>221 322 205 44 0 0 1440 878 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>446.1</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>29</integer>
+ <integer>21</integer>
+ <integer>227</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>8S2167</string>
+</dict>
+</plist>
diff --git a/pkg/osx/Resources/launcher.nib/keyedobjects.nib b/pkg/osx/Resources/launcher.nib/keyedobjects.nib
new file mode 100644
index 00000000..cc763056
--- /dev/null
+++ b/pkg/osx/Resources/launcher.nib/keyedobjects.nib
Binary files differ
diff --git a/pkg/osx/Resources/wadfile.icns b/pkg/osx/Resources/wadfile.icns
new file mode 100644
index 00000000..13502a55
--- /dev/null
+++ b/pkg/osx/Resources/wadfile.icns
Binary files differ
diff --git a/pkg/osx/Resources/wadfile.png b/pkg/osx/Resources/wadfile.png
new file mode 100644
index 00000000..394a3e33
--- /dev/null
+++ b/pkg/osx/Resources/wadfile.png
Binary files differ
diff --git a/pkg/osx/cp-with-libs b/pkg/osx/cp-with-libs
new file mode 100755
index 00000000..04fb5bc6
--- /dev/null
+++ b/pkg/osx/cp-with-libs
@@ -0,0 +1,100 @@
+#!/bin/bash
+#
+# Copy a program to the specified destination, along
+# with libraries it depends upon.
+
+src_bin=$1
+dest_dir=$2
+
+# Returns true if the specified file is a dylib.
+
+is_dylib() {
+ case "$1" in
+ *.dylib)
+ true
+ ;;
+ *)
+ false
+ ;;
+ esac
+}
+
+# Returns true if the specified file is in a system location
+# (/System or /usr):
+
+is_sys_lib() {
+ case "$1" in
+ /System/*)
+ true
+ ;;
+ /usr/*)
+ true
+ ;;
+ *)
+ false
+ ;;
+ esac
+}
+
+# Install the specified file to the location in dest_dir, along with
+# any libraries it depends upon (recursively):
+
+install_with_deps() {
+ local src_file
+ local bin_name
+ local dest_file
+ local lib_name
+
+ src_file=$1
+ bin_name=$(basename "$src_file")
+ dest_file="$dest_dir/$bin_name"
+
+ # Already copied into the package? Don't copy again.
+ # Prevents endless recursion.
+
+ if [ -e "$dest_file" ]; then
+ return
+ fi
+
+ echo "Installing $bin_name..."
+
+ # Copy file into package.
+
+ cp "$src_file" "$dest_file"
+
+ # Copy libraries that this file depends on:
+
+ otool -L "$src_file" | tail -n +2 | sed 's/^.//; s/ (.*//' | while read; do
+
+ # Don't copy system libraries
+
+ if is_sys_lib "$REPLY"; then
+ continue
+ fi
+
+ #echo " - $bin_name depends on $REPLY"
+
+ # Copy this library into the package, and:
+ # recursively install any libraries that _this_ library depends on:
+
+ install_with_deps "$REPLY"
+
+ # Change destination binary to depend on the
+ # copy inside the package:
+
+ lib_name=$(basename "$REPLY")
+ install_name_tool -change "$REPLY" "@executable_path/$lib_name" \
+ "$dest_file"
+ done
+
+ # If this is a library that we have installed, change its id:
+
+ if is_dylib "$dest_file"; then
+ install_name_tool -id "@executable_path/$bin_name" "$dest_file"
+ fi
+}
+
+# Install the file, and recursively install any libraries:
+
+install_with_deps "$src_bin"
+
diff --git a/pkg/osx/main.m b/pkg/osx/main.m
new file mode 100644
index 00000000..e3c70dc1
--- /dev/null
+++ b/pkg/osx/main.m
@@ -0,0 +1,32 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include <AppKit/AppKit.h>
+#include "Execute.h"
+
+int main(int argc, const char *argv[])
+{
+ SetProgramLocation(argv[0]);
+
+ return NSApplicationMain (argc, argv);
+}
+